Device Driver Interface
Device Driver Interface
Hi all
I was wondering are there any points to concider when developing device drives and how to interface them with the Kernel.
I want my device drivers to be ELF shared libraries, that are loaded and unloaded if the particular piece of hardware is present or not respectively.
Thanks
srg
I was wondering are there any points to concider when developing device drives and how to interface them with the Kernel.
I want my device drivers to be ELF shared libraries, that are loaded and unloaded if the particular piece of hardware is present or not respectively.
Thanks
srg
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Device Driver Interface
well, that means that you'll need some "super driver" (for instance a bus driver like in the Mobius ddk) that will probe the different busses (pci, usb, ata) and identify hardware that might need a driver.
Personnally, i decided to have a small software component that will check meta-data blundled with each available driver (e.g. the Features list) to see which one will best fit the available hardware (e.g. the one which maximizes the hardware's utility according to features).
Personnally, i decided to have a small software component that will check meta-data blundled with each available driver (e.g. the Features list) to see which one will best fit the available hardware (e.g. the one which maximizes the hardware's utility according to features).
Re:Device Driver Interface
You might want to check http://www.project-udi.org, which advocates a "Uniform Driver Interface" - basically, a portable driver architecture. The project was basically stopped dead when the .com-bubble burst and the Free Software Foundation voiced its dislike of UDI, but the mere concept is worth considering IMHO. (In the very least, that'd mean we two could interchange drivers once I get to the point. )
Every good solution is obvious once you've found it.
Re:Device Driver Interface
The other thing I was going to ask was how exactly do I create ELF shared libraries with my GCC cross compiler?
Also, how do I introduce my Kernel to the routines in the shared library file. The reason I say this is that normally, the main executable, at least with PE DLLs, is compiled to expect that library dynamically linked into it's address space, so it then just calls the libraries functions as if they were compiled into the program its stelf AFAIK. With the Kernel, it doesn't necessarily know what functions are in the library. Also, an executable AFAIK is compiled to expect certain librares (the ones with the routines it needs), with the kernel, completly new libraries (drivers), that is was never compiled to expect, can be loaded and unloaded at need. Not to mention that with a normal shared library, it's the OS enviroment that checks for dependant shared libaraies and then loads and links them in.
This is what's getting me
Thanks
srg
srg
Also, how do I introduce my Kernel to the routines in the shared library file. The reason I say this is that normally, the main executable, at least with PE DLLs, is compiled to expect that library dynamically linked into it's address space, so it then just calls the libraries functions as if they were compiled into the program its stelf AFAIK. With the Kernel, it doesn't necessarily know what functions are in the library. Also, an executable AFAIK is compiled to expect certain librares (the ones with the routines it needs), with the kernel, completly new libraries (drivers), that is was never compiled to expect, can be loaded and unloaded at need. Not to mention that with a normal shared library, it's the OS enviroment that checks for dependant shared libaraies and then loads and links them in.
This is what's getting me
Thanks
srg
srg
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Device Driver Interface
I'm not sure at all making it a *shared* ELF file will be the best option (because of how shared ELF look like with IA-32: requiring ebx to be kept up-to-date with the current file's table in a kernel context ?), compared to a ELF file in which you'd keep the relocation informations ...srg wrote: The other thing I was going to ask was how exactly do I create ELF shared libraries with my GCC cross compiler?
If your 'kernel space' is large enough (e.g. 1GB), you could also decide to pin-point a location for each module (if you're really uncomfortable with relocation and as uncomfortable as i am with ELF shared stuff)
like 'how will the shared module call kalloc and kprint' ? well you have several options, likeAlso, how do I introduce my Kernel to the routines in the shared library file.
- having a well-known interrupt that will provide a interface to all the kernel functions (a Kernel Programming Interface)
- leave kernel-defined symbols pending in the ELF file (thus with a list of symbols) and resolve them while loading
- have a 'jump table' ready in each driver that will be filled with the kernel jump table's content when loading.
Hope i made myself clear enough. Don't hesitate to bug me back if i've been too fast on some point.
If you're interrested in how clicker solved the problem, you may check http://clicker.sourceforge.net/forums/i ... hreadid=17
Re:Device Driver Interface
I meantPype.Clicker wrote:like 'how will the shared module call kalloc and kprint' ?Also, how do I introduce my Kernel to the routines in the shared library file.
'how will the Kernel call functions in the shared module'
Sorry
srg
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Device Driver Interface
This is much easier. For instance, your driver's initialization function may return a structure that the kernel will use to invoke the module. Thinking "? la COM" here can help alot.
Your driver offers one (or possibly many) *interfaces* to the kernel. Some interfaces are known by the kernel itself, other may be known only by some other components. In the first case, a table with a collection of function pointer is just fine.
In the latest, you'll probably have one such table of fctptr for each 'interface' and will offer a 'basic interface' (iUnknown ) to the kernel so that it can get any interface for the sake of another component through the 'basic' interface.
i'm still cooking my own devices/drivers model so i cannot come with a clear suggestion on what interfaces to offer ...
Your driver offers one (or possibly many) *interfaces* to the kernel. Some interfaces are known by the kernel itself, other may be known only by some other components. In the first case, a table with a collection of function pointer is just fine.
Code: Select all
struct Device { void (read*)(...); void (write*)(...); }
typedef struct Device* (InitDriver)();
MyDriver=((InitDriver)Elf.EntryPoint)();
MyDriver.read(...);
i'm still cooking my own devices/drivers model so i cannot come with a clear suggestion on what interfaces to offer ...
Re:Device Driver Interface
Or I suppose the Kernel, when linking in the module could simply look out for a magic string (a la VBE) or magic number which tells it were the table of function pointers are. Then, once copied into its reference structure, it could add to the function pointers the base address of where the module has been loaded (is this a bit like what PIC is like?) so the calls jump the the right address, of course this would also need to happen to data as well, hmm. Anyway, in which case, surely the module wouldn't need be be ELF at all, just a simple custom object format?Pype.Clicker wrote: This is much easier. For instance, your driver's initialization function may return a structure that the kernel will use to invoke the module. Thinking "? la COM" here can help alot.
Your driver offers one (or possibly many) *interfaces* to the kernel. Some interfaces are known by the kernel itself, other may be known only by some other components. In the first case, a table with a collection of function pointer is just fine.
In the latest, you'll probably have one such table of fctptr for each 'interface' and will offer a 'basic interface' (iUnknown ) to the kernel so that it can get any interface for the sake of another component through the 'basic' interface.Code: Select all
struct Device { void (read*)(...); void (write*)(...); } typedef struct Device* (InitDriver)(); MyDriver=((InitDriver)Elf.EntryPoint)(); MyDriver.read(...);
i'm still cooking my own devices/drivers model so i cannot come with a clear suggestion on what interfaces to offer ...
Could this work (with a bit of filling out)?
srg
BTW Thanks, you've given me some ideas to go away with.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Device Driver Interface
Yes, it could, but why scanning for a magic number while just using the entry point (which could either be a function returning info or a table) would be enough ? The purpose of magic scan (imho) is to locate some information which location cannot be standardized and when you have nothing you can call ...srg wrote: Or I suppose the Kernel, when linking in the module could simply look out for a magic string (a la VBE) or magic number which tells it were the table of function pointers are.
So you're suggesting something likeThen, once copied into its reference structure, it could add to the function pointers the base address of where the module has been loaded (is this a bit like what PIC is like?) so the calls jump the the right address,
Code: Select all
kernel_something() {
void *base=load_driver("myDriver");
FctPtr **export_table=find_export_table(base);
for (FctPtr **export=export_table;*export!=MAGIC_END_OF_TABLE;export++)
*export+=base;
}
Re:Device Driver Interface
So what driver model does clicker, or say mobius have at the moment. (I know mobius uses PE not ELF)
srg
srg
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Device Driver Interface
i won't try to describe the mobius, as tim did it marvelously in its device book (yet the document seems to be offline atm, but it should be at http://mobius.sourceforge.net/index.php)
Concerning Clicker,
- i have modules in a personal format, which includes the relocation list
- each module has a list of symbols which it will import from the running system (among which kalloc, but also helper functions for I/O operations etc) and a list of locations to be patched with the symbol's value.
- the device driver manager initially reads the header of every kdrv file it can find and list them by io bus. For instance, the IDELBA driver belongs to bus "ATA".
- a special category of drivers ("bus" drivers) are used to scan hardware and detect devices and their properties. These drivers are loaded by the driver manager and will report things like "device for ATA bus, available properties are: LBA, UDMA"
- for each reported device, an entry is created. When a program will attempt to access that device (say device.disk.primary-master), the broker is invoked to find a driver that will match the device. As the broker knows the 'bus' on which the device is attached and the available drivers for that bus, it just needs to compare the offered features of the device with the required features of the driver and picks the one that will make the best use of the device.
- each driver has an "ioDriverControl" structure telling (for instance) how devices should be attached with the driver, which is returned as a result of kdrv's init() function
Hmm ... i didn't remember it had *that* many steps ...
Concerning Clicker,
- i have modules in a personal format, which includes the relocation list
- each module has a list of symbols which it will import from the running system (among which kalloc, but also helper functions for I/O operations etc) and a list of locations to be patched with the symbol's value.
- the device driver manager initially reads the header of every kdrv file it can find and list them by io bus. For instance, the IDELBA driver belongs to bus "ATA".
- a special category of drivers ("bus" drivers) are used to scan hardware and detect devices and their properties. These drivers are loaded by the driver manager and will report things like "device for ATA bus, available properties are: LBA, UDMA"
- for each reported device, an entry is created. When a program will attempt to access that device (say device.disk.primary-master), the broker is invoked to find a driver that will match the device. As the broker knows the 'bus' on which the device is attached and the available drivers for that bus, it just needs to compare the offered features of the device with the required features of the driver and picks the one that will make the best use of the device.
- each driver has an "ioDriverControl" structure telling (for instance) how devices should be attached with the driver, which is returned as a result of kdrv's init() function
Hmm ... i didn't remember it had *that* many steps ...
Re:Device Driver Interface
How do you do this BTW. What are you patching? Individual instructions that make memory references possibly?Pype.Clicker wrote: i won't try to describe the mobius, as tim did it marvelously in its device book (yet the document seems to be offline atm, but it should be at http://mobius.sourceforge.net/index.php)
Concerning Clicker,
- i have modules in a personal format, which includes the relocation list
- each module has a list of symbols which it will import from the running system (among which kalloc, but also helper functions for I/O operations etc) and a list of locations to be patched with the symbol's value.
srg
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Device Driver Interface
okay, let's say you have in some C code
the object file will look like (pd, pb, cn are opcodes for PushDword, PushByte and CallNear respectively):
A helper tool inspect the .coff or .elf file and browse the relocation information so that it put it in a 'easier-to-use' form for me, but the information basically remains the same:
value of symbol "kalloc" should be added to dword at offset 8
So the relocation looks like
Hope this helps.
Code: Select all
buffer=kalloc(KMEM_KERNEL, 512);
Code: Select all
+0: pd 00 02 00 00 push 512
+5: pb 02 push 2 ;; KMEM_KERNEL
+7: cn 00 00 00 00 call 0x00000000
;; an entry in the relocation info of the object file tells that
;; when linking, the address of 'kalloc' symbol should be
;; added to value at offset +8 ...
+C: ad 08 add esp, 8
value of symbol "kalloc" should be added to dword at offset 8
So the relocation looks like
Code: Select all
foreach $symbol (@module.import_table) {
$value = resolve($symbol.name);
foreach $where ($symbol.references) {
((dword*)(module.loaded+$where)) += $value;
}
}