Structure Flashcards
Driver
Is as a container for a collection of subroutines that the operating system calls to perform various operations that relate to your hardware
Routines present in every such container
DriverEntry and AddDevice routines, as well as dispatch functions for a few types of I/O Request Packet (IRP)
Drivers that need to queue requests
Might have a StartIo routine
Drivers for devices that generate hardware interrupts
Have an interrupt service routine (ISR) and a deferred procedure call (DPC) routine
Jobs as the author of a WDM driver
Select the functions that need to be included in your particular container
OS Scheduler
The operating system kernel contains a scheduler that gives short blocks of time, called time slices, to all the
threads that are currently eligible to run. An application begins life with a single thread and can create more if it wants. Each thread has a priority, given to it by the system and subject to adjustment up and down for various reasons. At each decision point, the scheduler picks the highest-priority eligible thread and gives it control by loading a set of saved register images,
including an instruction pointer, into the processor registers. A processor interrupt accompanies expiration of the thread’s time slice. As part of handling the interrupt, the system saves the current register images, which can be restored the next time the system decides to redispatch the same thread.
Instead of just waiting for its time slice to expire, a thread can block each time it initiates a time-consuming activity in another thread until the activity finishes. This is better than spinning in a polling loop waiting for completion because it allows other
threads to run sooner than they would if the system had to rely solely on expiration of a time slice to turn its attention to some other thread.
Application is
A selfish thread that grabs the CPU and tries to hold on until it exits and that the operating system scheduler acts like a playground monitor to make a bunch of selfish threads play well together
A a driver is also an executable file with extension
.SYS
Who charge the driver
A driver doesn’t contain a main program. Instead, it contains a collection of subroutines that the
system can call when the system thinks it’s time to. To be sure, these subroutines can use helper subroutines in the driver, in static libraries, and in the operating system, but the driver isn’t in charge of anything except its own hardware: the system is in charge of everything else, including the decisions about when to run your driver code.
Thead context
Running in an arbitrary thread context. A driver subroutine executes in the context of whatever thread happens to be currently active at the time the system decides to call that subroutine. It’s not possible to predict which thread will be current at the time a hardware interrupt occurs.
Arbitrary thread
All the eligible threads that happens to be executing at the time of hardware interrupt is likewise not predictable
The system doesn’t always execute driver code in an arbitrary thread context
A driver can create its own system threads by
calling PsCreateSystemThread. A driver can also ask the system to call it back in the context of a system thread by scheduling a work item. In these situations, we consider the thread context to be nonarbitrary.
Thread block in an arbitrary thread
driver shouldn’t block
When a driver shouldn’t block
- In an arbitrary thread
* When a driver creates an IRP to send to some other driver
IRP in an arbitrary thread
Asynchronous IRP. The I/O Manager doesn’t tie an asynchronous IRP to any particular thread
IRP in a nonarbitrary thread
Synchronous IRP. The I/O Manager ties the synchronous kind of IRP to the thread within which you
create the IRP. It will cancel the IRP automatically if that thread terminates.
Symmetric Multiprocessing
In this model, each CPU is treated exactly like every other CPU with respect to thread scheduling. Each CPU has its own current thread. It’s perfectly possible for the I/O Manager, executing in the context of the threads running on two or more CPUs, to call subroutines in your driver simultaneously.
Function driver
It understands all the details about how to make
the hardware work. It’s responsible for initiating I/O operations, for handling the interrupts that occur when those operations finish, and for providing a way for the end user to exercise any control over the device that might be appropriate.
Bus driver
It’s responsible for managing the connection between
the hardware and the computer
PDO
physical device object
FDO
function device object
FiDO
filter device object
Plug and Play device
Is one that has an electronic signature that a bus driver can interrogate to learn the identity of a device.
Basic Data Structures
the driver object and the device object
Driver object
represents the driver itself and contains pointers to all the driver subroutines that the system will ever call on its own motion.
Device object
represents an instance of hardware and contains
data to help you manage that instance
DeviceObject (PDEVICE_OBJECT)
anchors a list of device object data structures, one for each of the devices managed by the driver. The I/O Manager links the device objects together and maintains this field. The DriverUnload function of a non-WDM driver would use this field to traverse the list of device objects in order to delete them. A WDM driver probably doesn’t have any particular need to use this field.
DeviceObject (PDEVICE_OBJECT)
anchors a list of device object data structures, one for each of the devices managed by the driver. The I/O Manager links the device objects together and maintains this field. The DriverUnload function of a non-WDM driver would use this field to traverse the list of device objects in order to delete them. A WDM driver probably doesn’t have any particular need to use this field.
DriverExtension (PDRIVER_EXTENSION)
points to a small substructure within which only the AddDevice (PDRIVER_ADD_DEVICE) member is accessible to the likes of us. AddDevice is a pointer to a function within the driver that creates device objects
HardwareDatabase (PUNICODE_STRING)
describes a string that names a hardware database registry key for the device. This
is a name like Registry\Machine\Hardware\Description\System and names the registry key within which resource allocation
information resides. WDM drivers have no need to access the information below this key because the PnP Manager performs resource allocation automatically. The name is stored in Unicode
FastIoDispatch (PFAST_IO_DISPATCH)
points to a table of function pointers that file system and network drivers export.
DriverStartIo (PDRIVER_STARTIO)
points to a function in your driver that processes I/O requests that the I/O Manager has serialized for you.
DriverUnload (PDRIVER_UNLOAD)
points to a cleanup function in your driver.
MajorFunction (array of PDRIVER_DISPATCH)
is a table of pointers to functions in your driver that handle each of the roughly two dozen types of I/O requests. This table is also something of a big deal, as you might guess, because it defines how I/O requests make it into your code.
DriverObject (PDRIVER_OBJECT)
points to the object describing the driver associated with this device object, usually the one that called IoCreateDevice to create it.
DriverObject (PDRIVER_OBJECT)
points to the object describing the driver associated with this device object, usually the one that called IoCreateDevice to create it.
NextDevice (PDEVICE_OBJECT)
points to the next device object that belongs to the same driver as this one. This field is the
one that links device objects together starting from the driver object’s DeviceObject member. There’s probably no reason for a WDM driver to use this field. That’s just as well because proper use of this pointer requires synchronization using an internal
system lock that’s not exposed for access by device drivers.
CurrentIrp (PIRP)
is used by the Microsoft IRP queuing routines StartPacket and StartNextPacket to record the IRP most
recently sent to your StartIo routine. WDM drivers should implement their own IRP queues (see Chapter 5) and may have no use for this field.
Flags (ULONG)
contains a collection of flag bits
Characteristics (ULONG)
is another collection of flag bits describing various optional characteristics of the device. The I/O Manager initializes these flags based on an argument to IoCreateDevice. Filter drivers propagate some of them upward in the device stack
DeviceExtension (PVOID)
points to a data structure you define that will hold per-instance information about the device. The I/O Manager allocates space for the structure, but its name and contents are entirely up to you. A common convention is to declare a structure with the type name DEVICE_EXTENSION. To access it given a pointer (for example, fdo) to the device object, use a statement like this one:
DeviceType (DEVICE_TYPE)
is an enumeration constant describing what type of device this is. The I/O Manager initializes
this member based on an argument to IoCreateDevice. Filter drivers might conceivably need to inspect it
StackSize (CCHAR)
counts the number of device objects starting from this one and descending all the way to the PDO. The
purpose of this field is to inform interested parties regarding how many stack locations should be created for an IRP that will be sent first to this device’s driver. WDM drivers don’t normally need to modify this value, however, because the support routine they use for building the device stack (IoAttachDeviceToDeviceStack) does so automatically.
AlignmentRequirement (ULONG)
specifies the required alignment for data buffers used in read or write requests to this device.
DriverEntry Routine
Do the global initialization that the driver
needs to perform only once when it’s loaded for the first time
NTSTATUS
Always return NTSTATUS
DriverEntry Routine first argument
The first argument to DriverEntry is a pointer to a barely initialized driver object that represents your driver. A WDM driver’s DriverEntry function will finish initializing this object and return.
DriverEntry Routine second argument
is the name of the service key in the registry. This string is not persistent—you must copy it if you plan to use it later. In a WDM driver, the only use I’ve ever made of this string is as part of WMI registration
WDM job in DriverEntry
A WDM driver’s main job in DriverEntry is to fill in the various function pointers in the driver object. These pointers indicate to the operating system where to find the subroutines you’ve decided to place in your driver container
- DriverUnload
Set this to point to whatever cleanup routine you create. The I/O Manager will call this routine just prior to unloading the driver. If there’s nothing to clean up, you need to have a DriverUnload function for the system to be able to unload your driver dynamically.
- DriverExtension->AddDevice
Set this to point to your AddDevice function. The PnP Manager will call AddDevice once for each hardware instance you’re responsible for
- DriverStartIo
If your driver uses the standard method of queuing I/O requests, you’ll set this member of the driver object to point to your StartIo routine
- MajorFunction
The I/O Manager initializes this vector of function pointers to point to a dummy dispatch function that fails every request. You’re presumably going to be handling certain types of IRPs—otherwise, your driver is basically going to be deaf and inert—so you’ll set at least some of these pointers to your own dispatch functions.
Handle IRPs
Every WDM driver must handle PNP, POWER, and SYSTEM_CONTROL I/O requests, and it should handle
SYSTEM_CONTROL I/O requests
DriverUnload
The purpose of a WDM driver’s DriverUnload function is to clean up after any global initialization that DriverEntry might have done. If your DriverEntry routine returns a failure status, the system doesn’t call your DriverUnload routine. Therefore, if DriverEntry generates any side effects that need cleaning up prior to returning an error status, DriverEntry has to perform the cleanup.
AddDevice Routine
a driver might be called upon to manage more than one actual device. In the WDM architecture, a driver has a special AddDevice function that the PnP Manager can call for each such device.
The basic responsibility of AddDevice in a function driver is to create a device object and link it into the stack rooted in this PDO. The steps involved are as follows:
1. Call IoCreateDevice to create a device object and an instance of your own device extension object.
2. Register one or more device interfaces so that applications know about the existence of your device. Alternatively, give the device object a name and then create a symbolic link.
3. Next initialize your device extension and the Flags member of the device object.
4. Call IoAttachDeviceToDeviceStack to put your new device object into the stack.
ISR
interrupt service routine
DPC
deferred procedure call