User-mode task switching
Posted: Sun Jul 16, 2023 3:00 pm
I'm a mega noob to OSDev, so my apologies if the answer is obvious
So I followed the Cooperative Multitasking tutorial on the wiki because I'm struggling a lot with System V assembly function parameters and couldn't get my own to work. It worked, and now I have a basic kernel mode multitasking system. When you have the same memory page maps and can switch to another process without having to switch rings, it's way easier to switch tasks. It's not too hard to wire up the task switch function to IRQ 0 to make a round robin scheduler. However, I'm trying to set up features like control rings and per-program paging to distance userland from the kernel, which makes multitasking so much more confusing. In user mode, the kernel and the processes will have separate page maps. That means that I'll have to identity map a few critical pages for usage during the task switch. The task switch will happen either through IRQ 0, the current process syscalling to give up its control, or the current process dying. So I'm planning on the IRQ 0 switch to be something like this:
So I followed the Cooperative Multitasking tutorial on the wiki because I'm struggling a lot with System V assembly function parameters and couldn't get my own to work. It worked, and now I have a basic kernel mode multitasking system. When you have the same memory page maps and can switch to another process without having to switch rings, it's way easier to switch tasks. It's not too hard to wire up the task switch function to IRQ 0 to make a round robin scheduler. However, I'm trying to set up features like control rings and per-program paging to distance userland from the kernel, which makes multitasking so much more confusing. In user mode, the kernel and the processes will have separate page maps. That means that I'll have to identity map a few critical pages for usage during the task switch. The task switch will happen either through IRQ 0, the current process syscalling to give up its control, or the current process dying. So I'm planning on the IRQ 0 switch to be something like this:
- "Current task" pointer used to determine next task is switched to the former current task's "next task." This will be a pointer to a physical address as the kernel has identity mapped pages and it will only be used by the kernel.
- Certain kernel pages will be identity mapped into the next task's page as read only pages. These are the page containing EIP and the subsequent page; the page containing the "from" task registers and the subsequent page; the page containing the "to" task registers and the subsequent page; and the page containing switch_task() and the subsequent page. I assume I will have to identity map all pages containing interrupt handlers too. (Maybe it's better to just identity map the whole kernel as read only?) The kernel can write to read-only pages, so I don't have to worry about that.
- The framebuffer (0xB8000) will be identity mapped too, but as read-write.
- The switch_task() function saves the current task's state (including EIP, ESP, and CR3) and loads the next task's.
- Return from the interrupt, returning us to user mode.