Page 1 of 2

Device drivers <-> kernel protection

Posted: Mon May 10, 2004 7:40 am
by Neuromancer
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. ::)

Re:Device drivers <-> kernel protection

Posted: Mon May 10, 2004 7:45 am
by Solar
What about memory mapped devices? (Shot in the dark, I haven't done device drivers yet.)

Re:Device drivers <-> kernel protection

Posted: Mon May 10, 2004 7:56 am
by Neuromancer
Memory mapped devices? :-[

Re:Device drivers <-> kernel protection

Posted: Mon May 10, 2004 8:03 am
by Neuromancer
Do you mean framebuffer devices such as graphic cards?

Re:Device drivers <-> kernel protection

Posted: Mon May 10, 2004 8:10 am
by Candy
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.
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.

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

Posted: Mon May 10, 2004 8:21 am
by Neuromancer
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.

Re:Device drivers <-> kernel protection

Posted: Mon May 10, 2004 8:30 am
by Pype.Clicker
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 ...

Re:Device drivers <-> kernel protection

Posted: Mon May 10, 2004 10:44 am
by Neuromancer
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 ...
Yeah this is great but....
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

Posted: Mon May 10, 2004 10:46 am
by Neuromancer
when the driver needs to allocate virtual memory?!
I mean 'when the driver needs to allocate heap memory?'

I hope you can understand the problem since I am no good at English. ;D

Re:Device drivers <-> kernel protection

Posted: Mon May 10, 2004 11:40 am
by Pype.Clicker
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 --

Re:Device drivers <-> kernel protection

Posted: Mon May 10, 2004 11:58 am
by Neuromancer
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.

Re:Device drivers <-> kernel protection

Posted: Mon May 10, 2004 4:58 pm
by qb
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.

Re:Device drivers <-> kernel protection

Posted: Tue May 11, 2004 1:40 am
by Pype.Clicker
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.
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 ?

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

Posted: Tue May 11, 2004 2:30 am
by Brendan
Hi,
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 ?
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).
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.
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.

This is definately not the fastest way to do things, but it suits my OS's design goals completely.


Cheers,

Brendan

Re:Device drivers <-> kernel protection

Posted: Tue May 11, 2004 3:48 am
by Pype.Clicker
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).
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 ...

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 ?