IRP_MJ_SHUTDOWN Shutdown notification

The fixed part of an IRP (the IRP structure itself) contains fixed attributes of the IRP. Each stack location — an IO_STACK_LOCATION structure — in fact contains most of the pertinent IRP parameters.

More than one IRP stack location is used when an IRP might be processed by more than one driver. Each driver gets its irp parameters from the current IRP stack location. If you pass an irp down the stack of drivers for the current device, you must set up the next stack location with the correct parameters. The parameters that you pass down may be different from the ones you are working with.

Figure 3.1 IRP Overview

IRP Parameters

When a write I/O request is made into an IRP, the I/O Manager fills in the main IRP header and builds the first IRP stack location. For a write, the IRP header contains the user buffer information. If you use Buffered I/O, the IRP AssociatedIrp.SystemBuffer field contains a pointer to the nonpaged copy of the user's buffer. For Direct I/O, the IRP MdlAddress field has a pointer to the user buffer MDL.

The IRP stack location has the main write request parameters. The stack MajorFunction field has the IRP_MJ_WRITE major function code that indicates that a write has been requested. The Parameters.Write.Length field has the byte transfer count and Parameters.Write.ByteOffset has the file pointer. The stack also has other important fields that are described later.

As I said earlier, you have to set up the next stack location if you call another driver. This means that you can theoretically change the IRP major function code to something else. While this might work in some cases, it is generally not a good idea, as the parameters in the fixed part of the IRP might not be correct.

However, it might be appropriate to change the number of bytes to transfer and the file pointer. You might do this if you know that the lower driver can only handle short transfers. To handle a large transfer, you might, therefore, send the IRP down several times. Each transfer request you send down will be within the capabilities of the lower driver.

Processing IRPs in a Driver Stack

In practice, the I/O stack locations are not usually used to alter these fundamental IRP parameters. Instead, the IRP stack is normally used to let an IRP be processed by all the drivers in a device stack.

Figure 3.2 shows how an IRP might be processed by four drivers in the device stack. The first IRP arrives at the highest driver, Driver 1. This uses the function IoGetCurrentlrpStack-Location to obtain a pointer to the current stack location. The figure shows that this returns the topmost IRP stack location.

Driver 1 decides that it needs to pass the IRP down the stack for processing. The IRP might be a Power Management IRP that the lowest bus driver needs to see. Driver 1 might not do anything with this IRP, but it still needs to pass the IRP down the stack.

Driver 1 therefore sets up the stack location for the next driver. In many cases, it simply copies the current stack location to the next using the IoCopyCurrentlrpStackLocation-ToNext or IoSkipCurrentlrpStackLocation functions. If you need to alter the next stack location, then use IoGetNextlrpStackLocation to get a pointer to it.

Driver 1 then calls the next driver down the stack using the IoCallDriver function. The I/O Manager now changes the 'current IRP stack location' pointer so that Driver 2 sees the second IRP stack location down (the one that Driver 1 set up for it). This process continues until the lowest driver, Driver 4, receives the IRP.

Driver 4 now processes the IRP. When it has finished with the IRP, Driver 4 calls IoCompleteRequest to indicate that it has finished processing the IRP. The IRP travels back up the device stack until it eventually pops out the top and is returned to the user.

Each of the drivers in the stack is given an opportunity to work with the IRP again as it travels up the stack, if they wish to do so. To do this, a driver must attach a completion routine to an IRP using the IoSetCompletionRoutine function. The completion routine information is stored in each driver's IRP stack location. This lets each of the drivers numbered 1 to 3 work on the IRP as it travels back up the stack in the order: Driver 3, Driver 2, and then Driver 1. A driver does not need to attach a completion routine. In this case, the I/O Manager does not call the driver as the IRP passes up the stack.

Figure 3.2 How all drivers in a stack process an IRP

A driver does not have to pass an IRP down the stack. If it detects an error in a parameter, or is able to process the IRP itself, then it should do its job and complete the IRP with IoCompleteRequest.

When a driver processes an IRP as it travels back up the device stack, it does not necessarily let the IRP progress further up the stack straightaway. If Driver 2 for example, splits Write IRPs into small chunks that Driver 3 can digest, then it may send the IRP back down the stack again, with changed parameters.

A further possibility is that a driver can build a new IRP and send it down the stack. Driver 2 might be processing a read request. To satisfy this request, it has to send an IOCTL request to the lower drivers. When the IOCTL request returns, Driver 2 checks that it worked satisfactorily and carries on processing its Read IRP.

To reiterate, an IRP includes a stack of I/O request operations. A driver only looks at the current IRP stack location and does not have to worry if there are higher-level drivers above.

Conclusion

Windows provides a well-defined hierarchy and structure for drivers. Go with the grain and learn how to fit in nicely with the rest of the operating system. Do not forget to cope with multiprocessor machines.

Windows provides a generic model of different processors that may be running. Drivers have routines that run at PASSIVE_LEVEL, DISPATCH_LEVEL, and DIRQL interrupt levels. Use system memory carefully and access user memory using the relevant kernel routines.

The kernel calls a driver in many ways. Most driver processing is in response to I/O Request Packets (IRPs). Conversely, a driver can make use of a whole host of kernel routines. Many system drivers have specific interfaces defined to handle particular I/O control codes. Drivers should use these interfaces wherever possible.

Enough prevarication, let's start on the first real device driver. The following chapters describe the Wdm1 virtual device driver in detail, how it is implemented and used, and how to test and debug drivers.

Chapter 4

WDM Driver Environment

This chapter writes a simple WDM device driver, called Wdm1. It shows how Wdm1 is built and installed in Windows 98 and Windows 2000. The basics of the driver are explained, but a full explanation of the guts has to wait until the following chapters.

The Wdm1 driver is for a virtual WDM device that does not correspond to any real hardware. For now, the Plug and Play and Power Management support is minimal. The Wdm1 driver implements a shared memory buffer for all Wdm1 devices.

First, I describe how to set up your computer for WDM driver development by installing the various development kits and by setting up Visual Studio. I describe the other useful tools that you will need.

The book software provides a Visual Studio workspace called WDM Book that you can use to compile the drivers and any associated user mode Win32 applications. Be careful if editing within this workspace as the different projects in this workspace often have files of the same name.

System Set Up

The section details what you will have to do to set up your development computer or computers for WDM driver development. This task is laborious, especially as you have to do it at least twice, once for Windows 2000 and once for Windows 98.

You will have to be an Administrative user to install the W2000 Driver Development Kit (DDK) and drivers in Windows 2000.

These instructions assume that you are using Visual C++ for development. While other compilers can almost certainly do the job, most Windows driver writers will be firmly in the Visual Studio camp. Visual C++ also has various useful tools that you will need such as rebase and guidgen. I used VC++ version 5.

You will need a Microsoft Developer Network (MSDN) Professional (or Universal) subscription to get the necessary development kits. While some of these kits are available free online, it is best to get an MSDN subscription to ensure that you receive the most recent releases and beta versions. The Installable File System (IFS) DDK costs extra and is only available currently in the USA and Canada.

DDKs

Install the W98 DDK in Windows 98. Install the W2000 DDK in Windows 2000. Install the Platform Software Development Kit (SDK) and MSDN Library in both versions of Windows. The Platform SDK is not vital, but it has quite a few useful tools.

The DDK tools and documentation are listed in the Start+Programs+Development kits menu. The Platform SDK tools are listed in the Start+Programs

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату