OSDev.org
https://forum.osdev.org/

Device Driver Interface
https://forum.osdev.org/viewtopic.php?f=1&t=9713
Page 1 of 1

Author:  srg [ Mon Jul 19, 2004 5:26 am ]
Post subject:  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

Author:  Pype.Clicker [ Mon Jul 19, 2004 6:04 am ]
Post subject:  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).

Author:  Solar [ Mon Jul 19, 2004 6:22 am ]
Post subject:  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. ;-) )

Author:  srg [ Mon Jul 19, 2004 8:12 am ]
Post subject:  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

Author:  Pype.Clicker [ Mon Jul 19, 2004 8:31 am ]
Post subject:  Re:Device Driver Interface

srg wrote:
The other thing I was going to ask was how exactly do I create ELF shared libraries with my GCC cross compiler?

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 ...

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)

Quote:
Also, how do I introduce my Kernel to the routines in the shared library file.

like 'how will the shared module call kalloc and kprint' ? well you have several options, like
- 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

Author:  srg [ Mon Jul 19, 2004 8:35 am ]
Post subject:  Re:Device Driver Interface

Pype.Clicker wrote:
Quote:
Also, how do I introduce my Kernel to the routines in the shared library file.

like 'how will the shared module call kalloc and kprint' ?


I meant

'how will the Kernel call functions in the shared module'

Sorry
srg

Author:  Pype.Clicker [ Mon Jul 19, 2004 9:33 am ]
Post subject:  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.

Code:
   struct Device { void (read*)(...); void (write*)(...); }
   typedef struct Device* (InitDriver)();

   
   MyDriver=((InitDriver)Elf.EntryPoint)();
   MyDriver.read(...);


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 ...

Author:  srg [ Mon Jul 19, 2004 10:45 am ]
Post subject:  Re:Device Driver Interface

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.

Code:
   struct Device { void (read*)(...); void (write*)(...); }
   typedef struct Device* (InitDriver)();

   
   MyDriver=((InitDriver)Elf.EntryPoint)();
   MyDriver.read(...);


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 ...


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?

Could this work (with a bit of filling out)?
srg

BTW Thanks, you've given me some ideas to go away with.

Author:  Pype.Clicker [ Tue Jul 20, 2004 2:47 am ]
Post subject:  Re:Device Driver Interface

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.

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 ...

Quote:
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,


So you're suggesting something like
Code:
   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;
   }


that looks like a partial relocation to me. The problem with it is that data reference cannot be relative and that they won't be fixed by this code. If variables can be made relative to a "global object structure" which pointer would be passed at any driver invocation, there are some references (like those pointing to constant strings) that you cannot alter this way from your code.

Author:  srg [ Tue Jul 20, 2004 7:42 am ]
Post subject:  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

Author:  Pype.Clicker [ Tue Jul 20, 2004 9:04 am ]
Post subject:  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 ...

Author:  srg [ Tue Jul 20, 2004 11:00 am ]
Post subject:  Re:Device Driver Interface

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.


How do you do this BTW. What are you patching? Individual instructions that make memory references possibly?

srg

Author:  Pype.Clicker [ Mon Aug 02, 2004 4:16 am ]
Post subject:  Re:Device Driver Interface

okay, let's say you have in some C code
Code:
    buffer=kalloc(KMEM_KERNEL, 512);

the object file will look like (pd, pb, cn are opcodes for PushDword, PushByte and CallNear respectively):
Code:
+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


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
Code:
foreach $symbol (@module.import_table) {
    $value = resolve($symbol.name);
    foreach $where ($symbol.references) {
       ((dword*)(module.loaded+$where)) += $value;
    }
}


Hope this helps.

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/