Process switching between kernel and user processes
Posted: Sun Mar 05, 2023 2:22 pm
(Hello! First post!)
I'm trying to implement preemptive multitasking for the first time, but I've hit a bit of a snag with how x86 does interrupt handling. My OS has a kernel process in addition to all the user processes, which the scheduler treats exactly the same as any other task except that it happens to be in ring 0. The problem, though, is that interrupts in x86 only push SS:ESP and load the new stack from the TSS if there's a privilege change from user to kernel, and iret only loads SS:ESP from the stack when going from kernel to user. This means there's a misalignment when switching between the kernel process and a user process or vice versa. I've come up with a partial solution that involves manually switching stacks, copying between them, etc., but it has to handle four different cases (kernel to user, user to kernel, user to user, and kernel to kernel) so it's a bit convoluted and I haven't gotten it to work yet, and I can't help but think there's probably an easier way to do this. (Or maybe there isn't and I just have to suffer through getting this to work...)
I've searched around a little bit but haven't found anything on my own about how to handle this, but I'm sure it's something anyone else who's also made kernel processes has had to work around, so I'd like to hear what the recommended way of dealing with this is.
I'm trying to implement preemptive multitasking for the first time, but I've hit a bit of a snag with how x86 does interrupt handling. My OS has a kernel process in addition to all the user processes, which the scheduler treats exactly the same as any other task except that it happens to be in ring 0. The problem, though, is that interrupts in x86 only push SS:ESP and load the new stack from the TSS if there's a privilege change from user to kernel, and iret only loads SS:ESP from the stack when going from kernel to user. This means there's a misalignment when switching between the kernel process and a user process or vice versa. I've come up with a partial solution that involves manually switching stacks, copying between them, etc., but it has to handle four different cases (kernel to user, user to kernel, user to user, and kernel to kernel) so it's a bit convoluted and I haven't gotten it to work yet, and I can't help but think there's probably an easier way to do this. (Or maybe there isn't and I just have to suffer through getting this to work...)
I've searched around a little bit but haven't found anything on my own about how to handle this, but I'm sure it's something anyone else who's also made kernel processes has had to work around, so I'd like to hear what the recommended way of dealing with this is.