driver interface design

Discussions on more advanced topics such as monolithic vs micro-kernels, transactional memory models, and paging vs segmentation should go here. Use this forum to expand and improve the wiki!
Post Reply
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

driver interface design

Post by bluemoon »

I'm currently redesigning & rewriting major parts of my kernel.

So how do you define the communication interface between kernel & driver?


This is my current design:
1. kernel call driver directly (ie C call) by calling driver's exported symbols.

Code: Select all

// kernel code
func = (int(*)(void)) ELF32_sym ( &elf, "driver_init" );
rez = func();
2. driver also call kernel's function directly (C call). the driver is linked as .so and with undefined symbols, the kernel patch it when loading the driver.

Code: Select all

// driver code
void* kmalloc(size_t s); // define prototype only, the body is in the kernel.bin
…
rez = kmalloc(16); // call it directly

I also considered alternatives, like provide another interrupt entry but I can't think of an elegant way to tell if the caller is a driver or an user-apps, checking the return address is ugly.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: driver interface design

Post by Solar »

Well, there's UDI, or CDI, which I would give a look if you're redesigning your driver interface anyway. 8)
Every good solution is obvious once you've found it.
User avatar
Jezze
Member
Member
Posts: 395
Joined: Thu Jul 26, 2007 1:53 am
Libera.chat IRC: jfu
Contact:

Re: driver interface design

Post by Jezze »

In my case the kernel parses the driver's symbol table and for each undefined reference it places the corresponding kernel function address there. This makes communication driver -> kernel work so the driver can now call all kernel function it wants.

When it comes to the opposite direction kernel -> driver it is a bit more trickier. The kernel knows what drivers have been loaded but it doesn't know, for some supported feature, exactly what driver is suppose to handle what. Let's take logging for instance. Perhaps you have two different drivers that both can handle system logging. Which one should you use? For all those instances I've had to implement a table with callbacks where the driver can place a callback in like in this case table[LOG] = driver->log;

So basically there is no direct kernel -> driver communication in the sense that the kernel knows what driver is doing what. It only uses the callback table.

This is what I did. I don't know if there is any other way really.
Fudge - Simplicity, clarity and speed.
http://github.com/Jezze/fudge/
Kevin
Member
Member
Posts: 1071
Joined: Sun Feb 01, 2009 6:11 am
Location: Germany
Contact:

Re: driver interface design

Post by Kevin »

bluemoon wrote:This is my current design:
1. kernel call driver directly (ie C call) by calling driver's exported symbols.
2. driver also call kernel's function directly (C call). the driver is linked as .so and with undefined symbols, the kernel patch it when loading the driver.

I also considered alternatives, like provide another interrupt entry but I can't think of an elegant way to tell if the caller is a driver or an user-apps, checking the return address is ugly
Let me rephrase your question: Should I write a microkernel or a monolithic one? There are good reasons for either option and we can't make that decision for your (well, we could, but after all it's your kernel).

One counter question, though: Why does it matter if some task is a "driver" or a "user-app"? Isn't the only possible difference about privileges?
Developer of tyndur - community OS of Lowlevel (German)
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: driver interface design

Post by bluemoon »

Jezze :

An alternative would be passing an API entry point to driver instead of dynamic resolve kernel's symbols.
something like this:

Code: Select all

struct DRIVER {
  int type;
  int id;
  int (api)(int cmd, ...);
  ...
};
As for kernel->driver, I agree for specific purpose there should be some kind of function registry, and the driver simply set hook/chain/extend in the function table - except I call that plugin module, not a driver.

For my drivers, I have type and id per each driver, and a driver registry that you can do driver = driver_find(kTypeFS,'FAT ');
And I don't have two drivers that do the same thing.

One counter question, though: Why does it matter if some task is a "driver" or a "user-app"? Isn't the only possible difference about privileges?
I don't want my kernel functions to be callable from user apps. If I open up an INT interface that would require permission checks in the interrupt handler, and check every time upon a call - unless there is some more elagent way to do it?
Kevin
Member
Member
Posts: 1071
Joined: Sun Feb 01, 2009 6:11 am
Location: Germany
Contact:

Re: driver interface design

Post by Kevin »

If you're doing it right, almost all syscalls will need quite some checks. Things like "does this pointer really point to valid user memory" or "may this process open the file it's trying to access". Having another syscall that requires a check "may this process get access to an I/O port" doesn't introduce anything fundamentally new.
Developer of tyndur - community OS of Lowlevel (German)
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: driver interface design

Post by bluemoon »

I see your point, thank you!
User avatar
Jezze
Member
Member
Posts: 395
Joined: Thu Jul 26, 2007 1:53 am
Libera.chat IRC: jfu
Contact:

Re: driver interface design

Post by Jezze »

Yeah it is a really good point. If the syscall interface checks for just about everything that can go wrong the rest of the kernel does not need to be bothered checking for buffer overruns, array boundries, invalid ranges et al because they just can't happen.
Fudge - Simplicity, clarity and speed.
http://github.com/Jezze/fudge/
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: driver interface design

Post by Gigasoft »

bluemoon wrote:I don't want my kernel functions to be callable from user apps. If I open up an INT interface that would require permission checks in the interrupt handler, and check every time upon a call - unless there is some more elagent way to do it?
Yes there is. Set the DPL field to 0.

Windows 95 used an interesting technique, where a driver would call the kernel (and other drivers) using an INT instruction followed by a function code. This would be replaced with an indirect call so that further invocations would not have the overhead of executing the interrupt handler.

As for me, the way I have it planned is that calls will be fixed up at loading using a relocation table. However, most of the intermodule communication will take place through COM-like interfaces.
Post Reply