Page 1 of 1
Loadable device drivers and modules
Posted: Fri Jun 11, 2010 7:03 am
by mutex
I have come to the stage that i have separated out all drivers into modules.
The modules are either statically and dynamically linked modules in PE og ELF format.
All modules are loaded into address space of the loading process. For most cases until now its the kernel process that loads and relocates the binaries into its process space. When a module is loaded its basically like creating a new thread. I load the sections of the executable image and set up a stack for it.
Now in some scenarios i think i might have more than one instance of a drive. For example i have two disk drives, two serial ports etc. This could probably be have been included into one driver with handling of multiple instances etc, but my approach is;
load executable module once. create a stack pr instance of the driver / thread that is running. All function / stack parameters are of course created on a pr thread stack, and global/static data is shared among all threads.
Now my question is;
Lets say i have kernel loaded, i have one stack for the kernel, and i have n allocations of heap to kernel.
I load serialport.sys and kernel loads two instances for it. First one with the static/initialization data set to Com1 io port , and second one for Com2.
How do i arrange stack layout. Where do i put things in the address space to optimize usage and layout of address space?
I guess if the stack has a fixed max size its not a problem, but for growable stacks its a problem.
How do you guys layout this?
Do you use fixed size stack or do you have any other smart way of solving this that i have not though about?
One way could of course be to create a process for each driver. This way i would not get problem, but it would be resource and time consuming switching back and forth between process contexts..
Thanks.
-
Thomas
Re: Loadable device drivers and modules
Posted: Fri Jun 11, 2010 7:57 am
by gerryg400
I would say ideally that each module should request the stack size that it feels that it needs when it's loaded. That way the kernel doesn't have to guess. Make sure there's a guard-page at the bottom. If something goes wrong it should be the module's fault. And hopefully the kernel can unload it gracefully.
One way could of course be to create a process for each driver. This way i would not get problem, but it would be resource and time consuming switching back and forth between process contexts..
That's how I do it... microkernel.
Re: Loadable device drivers and modules
Posted: Fri Jun 11, 2010 8:21 am
by mutex
Seems to be the way to go. The more i think about it, it seems like a good solution.
I already have the guard page implemented for my threads. For now it just un-register the thread from execution if the canary-page touched. Giving "hanging" threads in the process if this happens. Could also stop whole process though.. Dont know what would be the best. Actually if a thread does something wrong the entire state of the process could be "poisioned" and should probably be froozen asap to prevent additional damage..
Anyway. I will implement fixed stack size (defined only on stack creation with CreateThread() function)..
Cheers mate !
-
Thomas
Re: Loadable device drivers and modules
Posted: Fri Jun 11, 2010 8:53 am
by Owen
Why does a module need a stack or a thread of its own?
To me, a kernel module would simply be like a library in user space: The kernel would call some functions on it, it would call some functions of the kernel in return; if it needs a thread, it calls the functions to make one. If it wants to hook interrupts, it asks the kernel to do so on its behalf, etc.
Re: Loadable device drivers and modules
Posted: Fri Jun 11, 2010 9:19 am
by mutex
Hi,
Good question actually,
The reason why is;
Code: Select all
int sharedvariable; // Shared among all instances of this module (and any in process space really)
someDriverFunc()
{
int variable; // This uses stack and of course you know that..
}
So the reason why i cannot just juse same stack for all threads in kernel is:
The threads for one process can be executed in paralell/simultaneous (multiprocessor) and its not possible for them to share it. If they where not executing in paralell they could of course use same per process stack.
The shared variable of course does not require a stack, but then its not thread safe either and needs a mutex when accessing it. Often its usefull to have some global data shared amongst the instances of the object/driver/module and some local private data..
I think..
-
Thomas
Re: Loadable device drivers and modules
Posted: Fri Jun 11, 2010 9:25 am
by mutex
Hmm... after some considerations i think you might be right..
That is you can only have returning functions part of the driver.. But you will need to create threads from those functions if you need a non-returning state-machine or something.
I guess maby a stack would be usefull if you need some non-shared data aswell, but can probably be handled inside the new thread created from the functions exported to the kernel.
-
Thomas
Re: Loadable device drivers and modules
Posted: Fri Jun 11, 2010 12:25 pm
by Gigasoft
Well, of course each thread must have a different stack. But each driver doesn't need a stack. A driver would use the caller's stack. If needed, a driver could create threads in the initialization function for a device. Some systems have a set of worker threads that perform operations after another, where drivers can add operations (calls to a function in the driver) to the operation queue which is shared by the entire system.
I'm not sure of what you mean by "instances" of a driver. There's no point in having different instances of the same driver, although the same driver should of course be able to handle an arbitrary number of independent devices.
Re: Loadable device drivers and modules
Posted: Fri Jun 11, 2010 2:56 pm
by mutex
Every thread needs a stack (mostly true).
Caller.. Ok lets say you are running your favorite program. Then an IRQ fires. The context will switch to kernel stack of that process. From here we will call the module_irq_handler(). If that handler takes 5 second to respond there is no way to reshedule your favorite program/thread before the call that the kernel did to module_irq_handler() returns.
I was thinking;
Im running my favorite program. The IRQ fires. The context will switch to kernel stack of that process. The kernel will toggle a IRQ pending in some sort of message system for this then return / reschedule. Then when the scheduler runs it sees that the module have a pending irq. One of the cpus shedules/switches to the module thread and puts it into running. Now driver are working for five seconds. In the same time the favorite program is running.
With driver instances i actually mean instances of the object/executable module code with its own stack/context. Basically what your C++ compiler does for you when you create two objects of same class. For example the device driver loader loads serial.sys two times with different data on the stack/arguments for both of them. One with 0x3f8 and one with 0x2f8..
I might be stuck on some wierd idea here but i actually cannot se how this is easily fixed otherwise.. I of want drivers that are "interruptable" to be just that, and re-entrant drivers that are "re-entrant" safe should be that as well. Making variables local and using context for each one seems reasonable. Of course they all have a own stack when called from kernel aswell, but that stack is empty each time it returns from the function and back to kernel..
-
Thomas
Re: Loadable device drivers and modules
Posted: Fri Jun 11, 2010 3:46 pm
by Owen
The driver's interrupt handler function should be short. If it needs to do long processing, it should notify a background thread to do so.
Re: Loadable device drivers and modules
Posted: Fri Jun 11, 2010 4:39 pm
by mutex
Hmm. Ok.
So the interruptible device drivers is not an approach you find usefull? As far as i know both Solaris and WinNT have done this in many years. I think even linux can support that now..? Could be important for responsiveness. Must of course have a IRQ level/priority system to prioritize interruption..
I think i have a scheme that works.
static int instances;
void *configdata;
module_init() -- called by os when loading driver (increments instances)
module_exit() -- called by os to remove driver (decrement instances)
module_irq() -- added to IRQ list by module_init() code
module_init also allocates memory buffer for configdata, and if it needs to be increased it does so..
This was all instances of the driver have its own dataset saved between each run of module_irq().
The multiple instances thing is for supporting an unlimited count of driver instances for different devices..
-
Thomas
Re: Loadable device drivers and modules
Posted: Fri Jun 11, 2010 8:14 pm
by Gigasoft
On Windows, any interrupt handlers registered by drivers are invoked immediately when an interrupt occurs. The typical action for this interrupt handler is to insert a Deferred Procedure Call, which it turn may insert a work item or wake up a thread belonging to the driver.
It should be up to the driver to create any needed threads, not the system. If it doesn't need any threads, then no threads should be created. The driver's interrupt handler should then be able to continue processing in whatever way they want, by waking up one of the threads or by inserting operations into a system queue.
Usually, by module instances one means that the same module is loaded at different addresses or in different address spaces. This isn't the case here, what you probably mean is that devices are instances of a class implemented by the driver, which is something entirely different.
Re: Loadable device drivers and modules
Posted: Sat Jun 12, 2010 11:24 am
by mutex
I guess you are right about the handling of modules. They should export their "logic" as functions. They create threads etc, if they need it.
An "instance" of a object/module is:
http://en.wikipedia.org/wiki/Object-ori ... g#Instance
So its an instance.. The code is reused, but the state/stack is different among them.
I dont know, but i want to have my loader like this;
If same module/executable is loaded before in same process/address space. Then we reuse the code, but setup different stack. Thats how i want it to be. Of course now it seems that i wont be allocating a stack for each of them, neither creating a thread for each of them on load so my question now is;
How do i create a persistent memory for each driver. Like my example above. serial.sys is loaded and it gets 0x3f8 and 0x2f8 + other parameters on loading. It registers the driver in the "driver manager" and continue to setup.. Hmm now it seems like i might have solved my question right here... I could allocate a buffer for it and save pointer to it in the device_registering proces..
Nice how this ideas pop up when you write about your problem...
Case closed. Thank you all for helping me sorting out my
issues...
-
Thomas
Re: Loadable device drivers and modules
Posted: Sat Jun 12, 2010 12:51 pm
by Gigasoft
The driver can simply allocate a structure to hold all information about that particular device instance, when it starts handling the device. The interfaces that it exposes to the higher layers of the system contain a pointer to this structure. I also recommend that you don't enforce an one-to-one relationship between interfaces and physical devices, since some devices implement multiple, distinct functions.
Re: Loadable device drivers and modules
Posted: Sat Jun 12, 2010 1:04 pm
by mutex
Hi again,
Very true. I think of a device more like a isolated feature produced in a device. So the driver is not taking the whole device hostage. Many drivers may communicate with same device.
So back to my serial-port example again. All serial port drivers from same "serial.sys" will do same job of course. They allocate resources from kernel like io-port access, interrupt delivery, timers etc. Then when next driver is loaded it does the same job.
Only thing that differ between them is that they have a different device_driver entry in my device manager. That also hold the info that the driver needs to remeber between each time its used. Like in the example above the io-port,irq and some other basic settings are loaded.
The settings is sent to the driver upon loading. So the loading process must know what parameters the driver needs, OR the driver must be able to detect it themselves.. Actually drivers supporting auto-detection is only needed to be loaded once, and the module_init function will register as many devices as it needs to for all the physical devices..
-
Thomas
Re: Loadable device drivers and modules
Posted: Sat Jun 12, 2010 1:52 pm
by Gigasoft
What I'm thinking is that in the case of PCI devices, there should be a PCI driver which detects PCI cards, and somehow interacts with the system to load the appropriate driver for each individual device. The driver must then be passed a connection to the PCI driver which it stores in its own device structure. It can use this to get information about I/O and memory address ranges, and communicate information about power states. The same can be the case for every type of enumerated device, such as USB devices.
For devices that can't be enumerated, information can be stored in a configuration file which can be manipulated by a setup program.