drivers and devices...

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
dc0d32

drivers and devices...

Post by dc0d32 »

i couldn't find appropriate thread to jump in, so creating a new one. moderators can always move this.

lets start with an example. in crude terms, you have a hard disk drive, which we can consider as a device. you have the hdd driver which just talks in terms of sector numbers and buffers. you have a filesystem driver operating on top of this hdd driver. (for simplicity, didn't consider something complex like a network file system).

now when a process requests for a file operation, lets say read operation, the request is passes on to the filesystem driver. the driver will then take help of hdd driver, which will read off the disk. this looks like a list of drivers operating on a device, or the driver stack in ms' terms. the basic stuff that we all know.
well, the idea is clear to me. (i may be wrong... pls correct if so)

how have you implemented this???
ti_mo_n

Re:drivers and devices...

Post by ti_mo_n »

Look at Windows' DLLs: One DLL uses functions from other DLLs. Eventually you end up in 'ntdll.dll' which doesn't use any other DLL, so this is the first DLL to be written if you're about to write your own 'Windows' (then you write kernel32.dll, then gdi32.dll, then user32.dll, msvcrt.dll, and so on). Make a driver with some 'functions' (like: Read sector, Write sector), and then make another driver which uses those functions (and exports its own, at the same time, like "read dir", "read file").

Everything (except few cases) requires some form of memory management, so a memory manager is the first 'driver' to be written. You load this 'memory manager' and 'hdd driver' using some standard/compatibility methods (like BIOS ints), and then you switch to your own drivers.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re:drivers and devices...

Post by Colonel Kernel »

ti_mo_n wrote:Look at Windows' DLLs: One DLL uses functions from other DLLs. Eventually you end up in 'ntdll.dll' which doesn't use any other DLL, so this is the first DLL to be written if you're about to write your own 'Windows' (then you write kernel32.dll, then gdi32.dll, then user32.dll, msvcrt.dll, and so on).
This is a bit misleading. ntdll.dll just wraps the NT system calls in more palatable C functions -- it doesn't actually do the work itself. The drivers are all loaded in kernel mode, while ntdll.dll is loaded and run by user-mode processes.

The NT driver stack would make for a long and complicated example, so I'll just use QNX (a real-time OS based on a microkernel architecture) as an example instead. In QNX, the disk driver is a user process and each file system driver is a shared library. When an app opens a file, it is really asking the Process Manager (which I believe also acts as a name server) to find the appropriate server process responsible for the named resource, and open a channel to it for IPC. When the app does a read, it sends a message to the server process, which routes the request through the appropriate file system driver routines, which in turn makes use of the disk driver itself. The appropriate blocks are read from the disk and sent back to the client in a reply message.

I hope this makes some sense... you've asked a very broad question.
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
Dex4u

Re:drivers and devices...

Post by Dex4u »

This is the way i do it in Dex4u OS
The driver (TestMod.asm) is load into a free space in memory and add to the mod list etc.
Its functions are called like this:

Code: Select all

        mov   esi,CLIModID ; Points to module ID string.
        mov   ah,1  ; Module function number
        call  ModService  ; call module function
                              ;NOTE: there is also a int for this
        jnc   @f   ; jump if no error.
        call  ModError   ; If error call print error
        jmp  ExitError
CLIModID             db    'DEX4UMOD',0
@@:
Note: this does nothing but print a message if error, as its only a demo.
dc0d32

Re:drivers and devices...

Post by dc0d32 »

Colonel Kernel wrote:This is a bit misleading.
it sure was...

Colonel Kernel wrote: When an app opens a file, it is really asking the Process Manager (which I believe also acts as a name server) to find the appropriate server process responsible for the named resource, and open a channel to it for IPC.
what if i do it more or less the ms' way...

lets say we have a namespace manager/object manager which keeps track of all the objects that are in the system, alive
let the namespace start with a \
so for accessing a file on the first partition of the primary master hd, with a path
\Dir1\Dir2\TheFile.txt
will have the correct path, according to the naming convention as

\Devices\Block\hda_part\hda1\Dir1\Dir2\TheFile.txt

now, the application's library will issue a open request on \Devices\Block\hda_part\hda1\Dir1\Dir2\TheFile.txt object.
this request will be given first to the namespace manager. it will sequentially traverse the path, descending deeper into directories [well, these are object directories].
now it will come at hda1, which is not a directory, but itself is a device object.

the problem is, how do i parse down from here?

one way i think is something like registering a filesystem 'filter' on the device. so when the namespace manager sees the directory parse request on a device with filter drivers attached, it will redirect the io request to that filter driver targetted to a device in the filter driver(a pseudo dev) which gets created as a consequence of applying/mounting the filter driver on a device. this operation can be in turn repeated if the pseudo-device in the filter driver itself has some filter applied over it and so on.... (like a stack, the latest registered filter is invoked first). the filter driver then will do whatever operations it need to, probably issuing another set of io requests to the underlying device on which it is mounted, and returning the results back to the user library (or the namespace manager). this too is a cascaded operation, it will come up in the same order it went down.
what glitched do you see in this method?
Colonel Kernel wrote: When the app does a read, it sends a message to the server process, which routes the request through the appropriate file system driver routines, which in turn makes use of the disk driver itself.
this 'making use of disk driver' is just a call or some sophisticated request mechanism?
Colonel Kernel wrote: I hope this makes some sense... you've asked a very broad question.
sorry for that..... but i wanted to ask for what all methods you guys have thought of....
JoeKayzA

Re:drivers and devices...

Post by JoeKayzA »

prashant wrote: lets say we have a namespace manager/object manager which keeps track of all the objects that are in the system, alive
let the namespace start with a \
so for accessing a file on the first partition of the primary master hd, with a path
\Dir1\Dir2\TheFile.txt
will have the correct path, according to the naming convention as

\Devices\Block\hda_part\hda1\Dir1\Dir2\TheFile.txt

now, the application's library will issue a open request on \Devices\Block\hda_part\hda1\Dir1\Dir2\TheFile.txt object.
this request will be given first to the namespace manager. it will sequentially traverse the path, descending deeper into directories [well, these are object directories].
now it will come at hda1, which is not a directory, but itself is a device object.

the problem is, how do i parse down from here?
I'm not sure how the NT-kernel does this internally, but I would say you have several different ways to achieve this. First of all, the device object 'hda1' can be read and/or written as raw block data as well, doesn't it? So you could say it implements this block io interface, and as soon as a filesystem driver gets attached, it implements a directory interface as well (this would mean your objects must support implementing several interfaces at once).

You could, however, also say that the filesystem is represented as a seperate object. So when the filesystem driver is attached, a new object is created (hda1_ext2 or something...), which acts as a directory only. This way you have seperate objects for block io and filesystem accesses.

I haven't decided yet which road to take regarding devices and driver interfaces in my system design, but it will surely have some similarities to the nt kernel's. The only thing that I really don't like about nt kernel stacks is that they are by definition one-dimensional (one stack belongs to one device, every driver can have only one parent and one child). I would go for a tree-like structure instead...

cheers Joe
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Re:drivers and devices...

Post by Colonel Kernel »

I found some more specific info on how QNX handles pathname "mounting":

http://www.qnx.com/developers/docs/mome ... esmgr.html
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
mystran

Re:drivers and devices...

Post by mystran »

My own plan is to simply give the whole path to whatever you think is root (which you might have several in a single process), and then that server resolves the pathnames, unless it finds a mountpoint, at which point it directly forwards the query to the next server, which resolves, and so own, until it's either found, or not found, at which point the final server returns a handle to the original caller.
dc0d32

Re:drivers and devices...

Post by dc0d32 »

JoeKayzA wrote: You could, however, also say that the filesystem is represented as a seperate object. So when the filesystem driver is attached, a new object is created (hda1_ext2 or something...), which acts as a directory only. This way you have seperate objects for block io and filesystem accesses.
i am thinking very similar thing, but only without names, the fs object for the partition will not have a specific name, rather it will be internal naming, so that the mounting/unmounting is transparent, and user does not need to remember whether it was hda1_ext2 or hda1_fat32.
JoeKayzA wrote: The only thing that I really don't like about nt kernel stacks is that they are by definition one-dimensional (one stack belongs to one device, every driver can have only one parent and one child). I would go for a tree-like structure instead...
i think this is possible in the mounting technique.

@mystran:

lets say i have mounted the ext2 driver over hda1 device, and it created an anonymous (internally named, invisible to outside world) fs object for hda1. now, the ext2 driver, when accepts request targetted to this fs object, we shall choose a specific protocol (many to choose from, depends on the device), and using that protocol, it can communicate with the hda1 device.
now if it is a kernel mode driver, the protcol is fairly simple, but if it is as a usermode process/server, we can have the ipc below this protocol. am i correct?
mystran

Re:drivers and devices...

Post by mystran »

prashant wrote: lets say i have mounted the ext2 driver over hda1 device, and it created an anonymous (internally named, invisible to outside world) fs object for hda1.
Well, yes, it needs to provide an object, that supports the directory protocol. It also needs to send that object to someone, and that someone then needs to provide some namespace for it. Provided that it wants others to be use the drive as a filesystem, ofcourse.

Basicly, some other process will take the handle to the ext2 root, and add it to it's own namespace. If it's another service that provides directory service, it can make appear as mounted under it's directory tree. Ofcourse it might just give it as a root directory to anyone asking using whatever other protocol it wants.
now, the ext2 driver, when accepts request targetted to this fs object, we shall choose a specific protocol (many to choose from, depends on the device), and using that protocol, it can communicate with the hda1 device.
Yes, it can use whatever protocol it wants. I would suggest it use a common blockstorage protocol, so that it can work over anything providing that service, but ofcourse it need not.
now if it is a kernel mode driver, the protcol is fairly simple, but if it is as a usermode process/server, we can have the ipc below this protocol. am i correct?
Actually, it doesn't matter (from the ext2 servers point of view) if it's kernel or user driver it's using, because the ext2 server can't tell them from each other. It will use the same IPC system in any case.

You see, all you can do is use handles to communicate with whoever sits in the other end. When you get a handle, you hopefully get some message describing the handle too, telling you what it does. You can also use a standard "unknown" interface to "query" whether the handle supports another interface. But that's all.

When a process starts, it's get a handle it's parent provides when starting the process. For initial tasks, kernel implements certain basic services, but even they can't really tell whether they really are initial tasks, because they might have been started by another process, that wants to run a virtual system inside another system. It doesn't matter.

Actually, the server doesn't know who sent it a request either. All the server knows is that at some point it gave a handle to certain object to someone, and obviously someone still has the handle (because no "handleClosed" has not been received).

This might explain why it's taking me so long to get my kernel right. ;)
Post Reply