Hi,
XCHG wrote: [1] The Device Driver is loaded from the disk.
How do you load the disk driver from disk?
XCHG wrote: [2] The kernel calls the device driver's code at the offset of 0x00000000.
[3] The device driver will have a function at offset 0x00000000 that will return two values. The return value will be the size of the structure that this driver needs to output its functionalities and one other return value (through a pointer parameter) will be the offset of the initialization procedure/function.
[4] The kernel will take the return value in Step 3 and allocate a physical memory.
[5] The kernel will then call the offset of the initialization procedure in the device driver, returned at Step 3 and passes the allocated memory to that procedure.
[6] The device driver will fill in that structure with information such as the number of functions that are available in the device driver and their offsets, whether this device driver handles an Interrupt or IRQ (if yes, the offset of the IRQ/Interrupt handler) and etc...
Why can't the device driver's initialization function allocate some memory (if necessary) and return a pointer to a structure of information (instead of having 2 initialization functions)? For simple devices, the structure of information might already be in the device driver's ".data" section (no memory allocation needed)...
What will be the format for this structure of information? Will it be the same format (same fields, etc) for all device drivers (e.g. keyboard driver, hard disk, SCSI controller and video card)? It'd be extremely difficult to discuss the device driver interface without knowing any details for this structure. For example, the OS might try to pretend that all devices are either character or block devices and the structure may contain pointers to "read()" and "write()" functions and almost nothing else; or the structure might contain pointers to hundreds of different functions that may or may not be supported by the driver (e.g. pointers to "getKeypress()", "setVideoMode()" and "playSound()" functions that would all be set to NULL by a mouse driver that doesn't support them).
XCHG wrote:There are some problems with this approach of course. For example, the kernel might call the offset of 0x00000000 to a file which is believed to be a device driver. If this is not an actual device driver, an exception will happen. The kernel will then have to handle that exception and etc.
If it's not a device driver an exception may or may not happen - it could go into an infinite loop, or execute random instructions (including calling random kernel API functions) before crashing. I would assume you'd have some sort of binary header or magic number in the binary that the kernel can check to see if it actually is a driver.
Now, what if it's a malicious file specifically designed to look like a driver, that actually sends personal information to some scammer on the internet (like keypresses) instead? I'd assume you'd (for e.g.) put device drivers in a certain place in the file system so that the kernel can find them and so that other software (and normal users) don't have permission to write to that area.
XCHG wrote:Relocation as swapping them on and off the memory to disk storage and back? I am not sure what you mean by relocation in this case.
Relocation - using position independant code to have all device drivers running at different addresses in the same address space (e.g. like a monolithic kernel).
Will your kernel give each device driver it's own seperate address space (like my OS does) or will all the device drivers overwrite each other at the same addresses in the same address space?
XCHG wrote: [7] The kernel will then add this device driver to a queue. This will allow various device drivers to be hooked to a single device, running simultaneously.
XCHG wrote:About multiple drivers, my kernel will be charge of managing a queue of drivers in line to service various interrupts and IRQs. So once the driver is detected, the kernel will place it in the queue. When an IRQ is fired, the kernel will check for all device drivers that are supposed to handle that IRQ. Let's say it finds two of them. It will execute them in the FIFO manner. The second one should be noticed of the changes that the previously-loaded driver has made to the memory/IO/etc or unless it could possible duplicate the same thing the first driver has done. What do you think?
Imagine the first driver wants to send the floppy drive heads to track 0 (before doing a read or write) and the second driver wants to send the same floppy drive heads to track 55 (before doing a different read or write). Both drivers fight with each other and the floppy heads are continually moved from track 0 to track 55 and back. None of the drivers get anything done, until eventually the hardware fails (or the user notices, turns the computer off immediately and then refuses to run your OS ever again). Is this what you mean by "allow various device drivers to be hooked to a single device"?
How can several device drivers use the same device without stuffing each other up? Why do you want various device drivers to be hooked to a single device (is there any advantage that justifies all the synchronization and compatibility problems it'll cause)?
Alternatively, do you mean that the OS will support IRQ sharing (for e.g. where different device drivers control different devices that happen to share the same PCI IRQ line), and that different device drivers share the same software interrupt/s for their API? IRQ sharing is good (you need to support it for PCI devices to work properly).
IMHO different device drivers that share the same software interrupt/s for their API isn't good (it's a security problem, it's less efficient, etc). The kernel should handle the software interrupt/s and do security checks, etc before forwarding things to the correct device driver (not to all device drivers). In this case it'd be the kernel's API (not the device driver's API), where the kernel uses some other API to communicate with device drivers (possibly function pointers in the structure of information returned by the device driver's initialization).
The tricky part is that there's typically a hierarchical tree of device drivers, because there's a hierarchical tree of devices. For example, a floppy drive isn't connected directly to the CPU - the floppy drive is connected to a floppy drive controller that is connected to a "PCI to LPC" bridge that's connected to a PCI host controller that's connected to a memory controller that's connected to the CPU. This is especially important for power management (for example, so you don't send the PCI host controller to sleep while you're still trying to use the floppy drive controller).
This means that device drivers may use the kernel API (or the device driver API) to use other device drivers. For example, a file system might ask the floppy disk driver to do something, and the floppy disk driver might ask the floppy controller driver to do something, and the floppy controller driver might ask the ISA DMA driver to do something.
A device driver might handle all devices for a section of the hierarchical tree. For example, a single driver might handle the floppy drive controller and any floppy drives (and tape drives, zip drives, etc) that could be connected to the controller; instead of having seperate drivers for floppy drives (and tape drives, zip drives, etc) that all talk to a seperate floppy controller device driver. This may or may not be practical depending on the situation. For example, it might be fine for a floppy controller and devices connected to the floppy controller, but it'd be a nightmare for a USB controller and devices connected to the USB controller.
Cheers,
Brendan