Device drivers <-> kernel protection
Device drivers <-> kernel protection
I would like to implement a device driver to kernel protection, so device drivers cannot access the kernel code/data area.
Imagine a typical process page directory: i map in the first 2 GB the core memory area (that is, code, heap, stack, data etc.) and in the higher 2 GB the user area.
When the process with a syscall enters the kernel area, and the kernel needs to call a device-driver (actually I call them modules) function, there is a ASM stub which loads in CR3 another page directory which contains the same lower 2GB area, but the in higher one the device area is mapped, and the device driver runs in privilege level 3 (access to IO ports is done via IO permission map).
When the exported module function returns, the old page directory is loaded and automagically the module area disappears and the process area is still there.
This way, having the device driver running at CPL 3, I deny access to the core area. And I do not have to use task-switching as in microkernels.
Is this approach to the protection problem working and/or relatively fast?
Thx. ::)
Imagine a typical process page directory: i map in the first 2 GB the core memory area (that is, code, heap, stack, data etc.) and in the higher 2 GB the user area.
When the process with a syscall enters the kernel area, and the kernel needs to call a device-driver (actually I call them modules) function, there is a ASM stub which loads in CR3 another page directory which contains the same lower 2GB area, but the in higher one the device area is mapped, and the device driver runs in privilege level 3 (access to IO ports is done via IO permission map).
When the exported module function returns, the old page directory is loaded and automagically the module area disappears and the process area is still there.
This way, having the device driver running at CPL 3, I deny access to the core area. And I do not have to use task-switching as in microkernels.
Is this approach to the protection problem working and/or relatively fast?
Thx. ::)
Re:Device drivers <-> kernel protection
What about memory mapped devices? (Shot in the dark, I haven't done device drivers yet.)
Every good solution is obvious once you've found it.
Re:Device drivers <-> kernel protection
Do you mean framebuffer devices such as graphic cards?
Re:Device drivers <-> kernel protection
Yes this does work. No, switching privilege levels and CR3 areas is not any better than the microkernel approach. Yes, you do still suffer from the lagged operation problem (disk read slowing your threads). Yes, you do suffer from multiple threads in one space where there should be one, and so you need more mutex operations.Neur0m'ancer wrote: Imagine a typical process page directory: i map in the first 2 GB the core memory area (that is, code, heap, stack, data etc.) and in the higher 2 GB the user area.
When the process with a syscall enters the kernel area, and the kernel needs to call a device-driver (actually I call them modules) function, there is a ASM stub which loads in CR3 another page directory which contains the same lower 2GB area, but the in higher one the device area is mapped, and the device driver runs in privilege level 3 (access to IO ports is done via IO permission map).
When the exported module function returns, the old page directory is loaded and automagically the module area disappears and the process area is still there.
This way, having the device driver running at CPL 3, I deny access to the core area. And I do not have to use task-switching as in microkernels.
It's comparable to microkernel in performance, but it does work.
As for the memorymapped IO stuff, that's completely different, and yes that's like framebuffer devices and APIC's.
Re:Device drivers <-> kernel protection
I'd like to RDTSC the microkernel approach and this one and see how much time does the processor take to pass from kernel to module and viceversa.
For memory mapped devices, I have 1 GB of VM reserved (yeah, I have not 2GB for core and 2GB for user) so I can access them.
AFAIK 1GB is the maximum non-RAM physical memory for devices on IBM-compatible PCs (so only 3GB of RAM are usable).
I cleanup a bit my memory manager and I'll test it.
For memory mapped devices, I have 1 GB of VM reserved (yeah, I have not 2GB for core and 2GB for user) so I can access them.
AFAIK 1GB is the maximum non-RAM physical memory for devices on IBM-compatible PCs (so only 3GB of RAM are usable).
I cleanup a bit my memory manager and I'll test it.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Device drivers <-> kernel protection
if the device driver runs at CPL3, why not simply keep it in the kernel-half so that it's always available ? you could give the driver required protection by toying around base and limits of the segments the driver uses ... Even funnier, you could change the GDT on the fly so that the same selector points at one or the other driver's working set ...
Imho, the cost of having 'traditionnal' INTs to call the kernel from the driver (rather than using super-fast SYSCALL) would be outrun by the fact you won't need to flush TLB at each driver invokation, if proper care is taken ...
Imho, the cost of having 'traditionnal' INTs to call the kernel from the driver (rather than using super-fast SYSCALL) would be outrun by the fact you won't need to flush TLB at each driver invokation, if proper care is taken ...
Re:Device drivers <-> kernel protection
Yeah this is great but....Pype.Clicker wrote: if the device driver runs at CPL3, why not simply keep it in the kernel-half so that it's always available ? you could give the driver required protection by toying around base and limits of the segments the driver uses ... Even funnier, you could change the GDT on the fly so that the same selector points at one or the other driver's working set ...
Imho, the cost of having 'traditionnal' INTs to call the kernel from the driver (rather than using super-fast SYSCALL) would be outrun by the fact you won't need to flush TLB at each driver invokation, if proper care is taken ...
when the driver needs to allocate virtual memory?! I need to have a separate heap for each module (to protect each other) and thus not using a common heap.
And if you have separate heaps, you _obviously_ have to use fixed size heaps and this is not what I want to do.
Re:Device drivers <-> kernel protection
I mean 'when the driver needs to allocate heap memory?'when the driver needs to allocate virtual memory?!
I hope you can understand the problem since I am no good at English. ;D
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Device drivers <-> kernel protection
i see your point, but i can't see why a driver would require *that* much memory. Imho giving a few MB to each driver would be fairly enough.
-- more thoughts to come ... attention required in the kitchen --
-- more thoughts to come ... attention required in the kitchen --
Re:Device drivers <-> kernel protection
I made some calculations and you are right.
I have ~2560MB of free VM space, so I reserved 8 MB of code and 8 MB of heap for each module that is big (this is a module, not a process) and I can many modules without any problem (~160).
I will have segmentation to protect the core from them.
I have ~2560MB of free VM space, so I reserved 8 MB of code and 8 MB of heap for each module that is big (this is a module, not a process) and I can many modules without any problem (~160).
I will have segmentation to protect the core from them.
Re:Device drivers <-> kernel protection
Look at mikrokernels and drivers in userland.
Be aware of dma, the "ignore" the cpu mmu
and can fill your complete kernel memory with zeros.
Dma operate on physical memory
and x86 dont have a io mmu.
And remember, every busmaster capable pci card
have a dma chip on board.
For the segment stuff, look at small addresspaces for L4
as example.
For the opteron, the tagged tlb will reduce the costs
to put a driver an a own address space.
Be aware of dma, the "ignore" the cpu mmu
and can fill your complete kernel memory with zeros.
Dma operate on physical memory
and x86 dont have a io mmu.
And remember, every busmaster capable pci card
have a dma chip on board.
For the segment stuff, look at small addresspaces for L4
as example.
For the opteron, the tagged tlb will reduce the costs
to put a driver an a own address space.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Device drivers <-> kernel protection
So true ... in a sense, as soon as I/O involves some direct memory addresses, the I/O programming should be under control of a trusted component. But what's left to the userland 'driver' then ?qb wrote: Be aware of dma, the "ignore" the cpu mmu
and can fill your complete kernel memory with zeros.
Dma operate on physical memory
and x86 dont have a io mmu.
And remember, every busmaster capable pci card
have a dma chip on board.
imho, only the 'top level' features of devices make sense at user level, like decoding the sectors in a filesystem, handling packets and delivering them to the proper socket in a network stack, etc. But the *real* hardware interface (programming memory transfers, acknowledging interrupts, etc) can hardly be safely extracted from kernel level.
Re:Device drivers <-> kernel protection
Hi,
This is definately not the fastest way to do things, but it suits my OS's design goals completely.
Cheers,
Brendan
IO permissions maps bring IO port access under control of the kernel with very little overhead. The ISA DMA chips should also be under kernel control as it's the easiest way to ensure the DMA channels are not being used by multiple drivers. Any other DMA/bus master (built into the hardware) should be done by the device drivers as the kernel won't/shouldn't know how to use them (unless it's a monolithic kernel).Pype.Clicker wrote: So true ... in a sense, as soon as I/O involves some direct memory addresses, the I/O programming should be under control of a trusted component. But what's left to the userland 'driver' then ?
My micro-kernel runs all device drivers at CPL=3, and there is no real difference between a device driver and any other process (e.g. text editor, compiler) as far as the kernel is concerned - the only difference is that drivers use a different file extension. This simplifies the kernel code because everything is the same. All data transfers are done via messages (a message can be up to 32 Mb). The kernel handles all IRQs by sending a message to any thread/s (device driver/s) that have asked for it and by doing any EOI.imho, only the 'top level' features of devices make sense at user level, like decoding the sectors in a filesystem, handling packets and delivering them to the proper socket in a network stack, etc. But the *real* hardware interface (programming memory transfers, acknowledging interrupts, etc) can hardly be safely extracted from kernel level.
This is definately not the fastest way to do things, but it suits my OS's design goals completely.
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Device drivers <-> kernel protection
Yeah, i know all this. The i/O bitmap will work perfectly as long as you use INs and OUTs, and memory-mapped IO (like VRAM, PCI registers, etc.) will work fine if you create an appropriate segment for the user process ...Brendan wrote: IO permissions maps bring IO port access under control of the kernel with very little overhead. The ISA DMA chips should also be under kernel control as it's the easiest way to ensure the DMA channels are not being used by multiple drivers. Any other DMA/bus master (built into the hardware) should be done by the device drivers as the kernel won't/shouldn't know how to use them (unless it's a monolithic kernel).
Now, consider this: in order to perform a UtlraDMA disk request, i need to write the physical address of the target memory area into the memory-mapped 'buffer' of the busmaster device. How would the microkernel ensure that the disk driver isn't evilly writing a microkernel frame number there, or a random number (likely to come from another process) ?
Same for ISA DMA ports: the Soundblaster driver shouldn't be allowed to toy with them directly, but rather use a trusted service to program the DMA on its behalf, no ?
And as such DMA things cannot be reliably performed at user level, why not simply moving the whole 'lower level' part of the driver at the kernel level ? What sense does it make to have a user-level driver that need a kernel plugin to make its job ?