Writing an interrupt trampoline
Posted: Sun Apr 18, 2010 5:16 pm
Hi,
I just finished my threading code inside my kernel and want to get to usermode as fast as possible now to get finally out of the kernel.
My design is going to be a microkernel.
The address space layout is inspired from mac os where every process and the kernel has its very own virtual address space. The kernel isn't mapped anywhere in the usermode address space.
This leads to a problem on x86:
If an interrupt occurs, the processor needs to jump somewhere, but since, unlike on Power PC, the CPU doesn't switch the page directory to the kernel directory or turns off paging it jumps into a nonexistent memory location. Bad!
So I need to switch it by myself. My idea was do dedicate one page as a trampoline, mapped into every address space. The IDT points to several entrypoints inside the trampoline page and switches the page directory if necessary and jumps to the real handling code after that.
On x86 Mac OS uses this approach, too. I already opened a thread a few weeks ago about that because I couldn't find the source code about that, but I can't figure out how all this works on XNU
Now there are several questions how to do that:
How would you write such a trampoline? It needs to be loaded with the kernel and needs to be configured at runtime. The page directory to switch to needs to be set as well as the real entry points to the interrupt handlers. All this with as less work as necessary.
Another thing is the x86 TSS: When an interrupt occurs in usermode the stack is switched to the correponding stack segment and stack pointer in the current TSS. If the kernel stack is only mapped in the kernel page directory, this leads to a problem. The CPU tries to push the return information to the stack which is not mapped and faults.
If I only map it in the usermode page directory of the process the stack gets invalid as soon as the trampoline switches the address spaces and the cpu would fault, too.
I don't really like the obvious solution about this: Mapping this stack into both address spaces since it would bring much management work with it. I would have to handle two address spaces, keep the location unique for every process on both of them etc.
Any ideas about that?
I just finished my threading code inside my kernel and want to get to usermode as fast as possible now to get finally out of the kernel.
My design is going to be a microkernel.
The address space layout is inspired from mac os where every process and the kernel has its very own virtual address space. The kernel isn't mapped anywhere in the usermode address space.
This leads to a problem on x86:
If an interrupt occurs, the processor needs to jump somewhere, but since, unlike on Power PC, the CPU doesn't switch the page directory to the kernel directory or turns off paging it jumps into a nonexistent memory location. Bad!
So I need to switch it by myself. My idea was do dedicate one page as a trampoline, mapped into every address space. The IDT points to several entrypoints inside the trampoline page and switches the page directory if necessary and jumps to the real handling code after that.
On x86 Mac OS uses this approach, too. I already opened a thread a few weeks ago about that because I couldn't find the source code about that, but I can't figure out how all this works on XNU
Now there are several questions how to do that:
How would you write such a trampoline? It needs to be loaded with the kernel and needs to be configured at runtime. The page directory to switch to needs to be set as well as the real entry points to the interrupt handlers. All this with as less work as necessary.
Another thing is the x86 TSS: When an interrupt occurs in usermode the stack is switched to the correponding stack segment and stack pointer in the current TSS. If the kernel stack is only mapped in the kernel page directory, this leads to a problem. The CPU tries to push the return information to the stack which is not mapped and faults.
If I only map it in the usermode page directory of the process the stack gets invalid as soon as the trampoline switches the address spaces and the cpu would fault, too.
I don't really like the obvious solution about this: Mapping this stack into both address spaces since it would bring much management work with it. I would have to handle two address spaces, keep the location unique for every process on both of them etc.
Any ideas about that?