Các cấu trúc dữ liệu (data structures )

15 337 0
Các cấu trúc dữ liệu (data structures )

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Các cấu trúc liệu (Data Structures ) Các cấu trúc liệu (Data Structures ) Bởi: Khoa CNTT ĐHSP KT Hưng Yên Two data structures are crucial to the handling of I/O requests: the I/O request packet itself and the IO_STACK_LOCATION structure I’ll describe both structures in this section Structure of an IRP Figure 5-1 illustrates the IRP data structure, with opaque fields shaded in the usual convention of this book A brief description of the important fields follows 1/15 Các cấu trúc liệu (Data Structures ) MdlAddress (PMDL) is the address of a memory descriptor list (MDL) describing the user-mode buffer associated with this request The I/O Manager creates this MDL for IRP_MJ_READ and IRP_MJ_WRITE requests if the topmost device object’s flags indicate DO_DIRECT_IO It creates an MDL for the output buffer used with an IRP_MJ_DEVICE_CONTROL request if the control code indicates METHOD_IN_DIRECT or METHOD_OUT_DIRECT The MDL itself describes the user-mode virtual buffer and also contains the physical addresses of locked pages containing that buffer A driver has to additional work, which can be quite minimal, to actually access the user-mode buffer Figure 5-1 I/O request packet data structure Flags (ULONG) contains flags that a device driver can read but not directly alter None of these flags are relevant to a Windows Driver Model (WDM) driver 2/15 Các cấu trúc liệu (Data Structures ) AssociatedIrp (union) is a union of three possible pointers The alternative that a typical WDM driver might want to access is named AssociatedIrp.SystemBuffer The SystemBuffer pointer holds the address of a data buffer in nonpaged kernel-mode memory For IRP_MJ_READ and IRP_MJ_WRITE operations, the I/O Manager creates this data buffer if the topmost device object’s flags specify DO_BUFFERED_IO For IRP_MJ_DEVICE_CONTROL operations, the I/O Manager creates this buffer if the I/O control function code indicates that it should (See Chapter 9.) The I/O Manager copies data sent by user-mode code to the driver into this buffer as part of the process of creating the IRP Such data includes the data involved in a WriteFile call or the so-called input data for a call to DeviceIoControl For read requests, the device driver fills this buffer with data; the I/O Manager later copies the buffer back to the user-mode buffer For control operations that specify METHOD_BUFFERED, the driver places the so-called output data in this buffer, and the I/O Manager copies it to the user-mode output buffer IoStatus (IO_STATUS_BLOCK) is a structure containing two fields that drivers set when they ultimately complete a request IoStatus.Status will receive an NTSTATUS code, while IoStatus.Information is a ULONG_PTR that will receive an information value whose exact content depends on the type of IRP and the completion status A common use of the Information field is to hold the total number of bytes transferred by an operation such as IRP_MJ_READ that transfers data Certain Plug and Play (PnP) requests use this field as a pointer to a structure that you can think of as the answer to a query RequestorMode will equal one of the enumeration constants UserMode or KernelMode, depending on where the original I/O request originated Drivers sometimes inspect this value to know whether to trust some parameters PendingReturned (BOOLEAN) is meaningful in a completion routine and indicates whether the next lower dispatch routine returned STATUS_PENDING This chapter contains a disagreeably long discussion of how to use this flag Cancel (BOOLEAN) is TRUE if IoCancelIrp has been called to cancel this request and FALSE if it hasn’t (yet) been called IRP cancellation is a relatively complex topic that I’ll discuss fully later on in this chapter (in “Cancelling I/O Requests”) CancelIrql (KIRQL) is the interrupt request level (IRQL) at which the special cancel spin lock was acquired You reference this field in a cancel routine when you release the spin lock CancelRoutine (PDRIVER_CANCEL) is the address of an IRP cancellation routine in your driver You use IoSetCancelRoutine to set this field instead of modifying it directly 3/15 Các cấu trúc liệu (Data Structures ) UserBuffer (PVOID) contains the user-mode virtual address of the output buffer for an IRP_MJ_DEVICE_CONTROL request for which the control code specifies METHOD_NEITHER It also holds the user-mode virtual address of the buffer for read and write requests, but a driver should usually specify one of the device flags DO_BUFFERED_IO or DO_DIRECT_IO and should therefore not usually need to access the field for reads or writes When handling a METHOD_NEITHER control operation, the driver can create its own MDL using this address Tail.Overlay is a structure within a union that contains several members potentially useful to a WDM driver Refer to Figure 5-2 for a map of the Tail union In the figure, items at the same level as you read left to right are alternatives within a union, while the vertical dimension portrays successive locations within a structure Tail.Overlay.DeviceQueueEntry (KDEVICE_QUEUE_ENTRY) and Tail.Overlay.DriverContext (PVOID[4]) are alternatives within an unnamed union within Tail.Overlay The I/O Manager uses DeviceQueueEntry as a linking field within the standard queue of requests for a device The cancel-safe queuing routines IoCsqXxx use the last entry in the DriverContext array If these system usages don’t get in your way, at moments when the IRP is not in some queue that uses this field and when you own the IRP, you can use the four pointers in DriverContext in any way you please Tail.Overlay.ListEntry (LIST_ENTRY) is available for you to use as a linking field for IRPs in any private queue you choose to implement CurrentLocation (CHAR) and Tail.Overlay.CurrentStackLocation (PIO_STACK_LOCATION) aren’t documented for use by drivers because support functions such as IoGetCurrentIrpStackLocation can be used instead During debugging, however, it might help you to realize that CurrentLocation is the index of the current I/O stack location and CurrentStackLocation is a pointer to it 4/15 Các cấu trúc liệu (Data Structures ) Figure 5-2 Map of the Tail union in an IRP The I/O Stack Whenever any kernel-mode program creates an IRP, it also creates an associated array of IO_STACK_LOCATION structures: one stack location for each of the drivers that will process the IRP and sometimes one more stack location for the use of the originator of the IRP (See Figure 5-3.) A stack location contains type codes and parameter information for the IRP as well as the address of a completion routine Refer to Figure 5-4 for an illustration of the stack structure 5/15 Các cấu trúc liệu (Data Structures ) Figure 5-3 Parallelism between driver and I/O stacks A final consideration in calling the two synchronous IRP routines is that you can’t create just any kind of IRP using these routines See Table 5-1 for the details A common trick for creating another kind of synchronous IRP is to ask for an IRP_MJ_SHUTDOWN, which has no parameters, and then alter the MajorFunction code in the first stack location Table 5-1 Synchronous IRP Types Support Function Types of IRP You Can Create IRP_MJ_READ IRP_MJ_WRITE IRP_MJ_FLUSH_BUFFERS IoBuildSynchronousFsdRequest IRP_MJ_SHUTDOWN IRP_MJ_PNP IRP_MJ_POWER (but only for IRP_MN_POWER_SEQUENCE) IoBuildDeviceIoControlRequest IRP_MJ_DEVICE_CONTROL IRP_MJ_INTERNAL_DEVICE_CONTROL Creating Asynchronous IRPs The other two IRP creation functions—IoBuildAsynchronousFsdRequest and IoAllocateIrp—create an asynchronous IRP Asynchronous IRPs don’t belong to the 6/15 Các cấu trúc liệu (Data Structures ) creating thread, and the I/O Manager doesn’t schedule an APC and doesn’t clean up when the IRP completes Consequently: • When a thread terminates, the I/O Manager doesn’t try to cancel any asynchronous IRPs that you happen to have created in that thread • It’s OK to create asynchronous IRPs in an arbitrary or nonarbitrary thread • Because the I/O Manager doesn’t any cleanup when the IRP completes, you must provide a completion routine that will release buffers and call IoFreeIrp to release the memory used by the IRP • Because the I/O Manager doesn’t automatically cancel asynchronous IRPs, you might have to provide code to that when you no longer want the operation to occur • Because you don’t wait for an asynchronous IRP to complete, you can create and send one at IRQL DeviceObject = DeviceObject; ULONG fcn = stack->MajorFunction; PDRIVER_OBJECT driver = DeviceObject->DriverObject; 8/15 Các cấu trúc liệu (Data Structures ) return (*driver->MajorFunction[fcn])(DeviceObject, Irp); } As you can see, IoCallDriver simply advances the stack pointer and calls the appropriate dispatch routine in the driver for the target device object It returns the status code that that dispatch routine returns Sometimes I see online help requests wherein people attribute one or another unfortunate action to IoCallDriver (For example, “IoCallDriver is returning an error code for my IRP….”) As you can see, the real culprit is a dispatch routine in another driver Locating Device Objects Apart from IoAttachDeviceToDeviceStack, drivers can locate device objects in at least two ways I’ll tell you here about IoGetDeviceObjectPointer and IoGetAttachedDeviceReference IoGetDeviceObjectPointer If you know the name of the device object, you can call IoGetDeviceObjectPointer as shown here: PUNICODE_STRING devname; // [...].. .Các cấu trúc dữ liệu (Data Structures ) Refer to Table 5-3 for an abbreviated list of status codes for common situations The Information value depends on what type of IRP you’re completing and on whether you’re causing the IRP to succeed or to fail Most of the time, when you’re causing an IRP to fail (that is, completing it with an error status of some kind), you’ll set Information... because that function clears some flags that IoSetCompletionRoutine sets A completion routine looks like this: NTSTATUS CompletionRoutine(PDEVICE_OBJECT fdo, PIRP Irp, 12/15 Các cấu trúc dữ liệu (Data Structures ) PVOID context) { return ; } It receives pointers to the device object and the IRP, and it also receives whichever context value you specified in the call to IoSetCompletionRoutine... situation, you’ll want to use IoSetCompletionRoutineEx if you issue an asynchronous IRP and don’t wait (as in scenario 8) for it to finish Otherwise, you don’t need the new routine unless you somehow return before the IRP completes, which 14/15 Các cấu trúc dữ liệu (Data Structures ) would be against all the rules for IRP handling and not just the rules for completion routines Situation 5: Synchronous... consider occurs when you create a synchronous IRP to help you process an IRP that someone else has sent you You intend to complete the main IRP after the subsidiary IRP completes 13/15 Các cấu trúc dữ liệu (Data Structures ) You wouldn’t ordinarily use a completion routine with a synchronous IRP, but you might want to if you were going to implement the safe cancel logic discussed later in this chapter... finishes, for example—it’s not necessary to apply this extraordinary priority increment to a get-driver-version control request Table 5-4 Priority Boost Values for IoCompleteRequest 11/15 Các cấu trúc dữ liệu (Data Structures ) Manifest Constant Numeric Priority Boost IO_NO_INCREMENT 0 IO_CD_ROM_INCREMENT 1 IO_DISK_INCREMENT 1 IO_KEYBOARD_INCREMENT 6 IO_MAILSLOT_INCREMENT 2 IO_MOUSE_INCREMENT 6 IO_NAMED_PIPE_INCREMENT... STATUS_MORE_PROCESSING_REQUIRED but more evocatively named (Future printings of this book may also employ better grammar in describing the meaning to be ascribed the constant, at least if my editors get their way .) • Anything else, which allows the completion process to continue Because any value besides STATUS_MORE_PROCESSING_REQUIRED has the same meaning as any other, I usually just code STATUS_SUCCESS Future... STATUS_END_OF_FILE End-of-file marker reached STATUS_DELETE_PENDING The device is in the process of being removed from the system STATUS_INSUFFICIENT_RESOURCES Not enough system resources (often memory) to perform an operation When you call IoCompleteRequest, you supply a priority boost value to be applied to whichever thread is currently waiting for this request to complete You normally choose a boost... Situation 3: IRP Issued from Your Own System Thread The third situation in our analysis of completion routines occurs when a system thread you’ve created (see Chapter 14 for a discussion of system threads) installs completion routines for IRPs it sends to other drivers If you create a truly asynchronous IRP in this situation, use IoSetCompletionRoutineEx to install the obligatory completion routine and... IoSetCompletionRoutine Completion routines can be called at DISPATCH_LEVEL in an arbitrary thread context but can also be called at PASSIVE_LEVEL or APC_LEVEL To accommodate the worst case (DISPATCH_LEVEL), completion routines therefore need to be in nonpaged memory and must call only service functions that are callable at or below DISPATCH_LEVEL To accommodate the possibility of being called at a lower .. .Các cấu trúc liệu (Data Structures ) MdlAddress (PMDL) is the address of a memory descriptor list (MDL) describing the user-mode buffer associated... (ULONG) contains flags that a device driver can read but not directly alter None of these flags are relevant to a Windows Driver Model (WDM) driver 2/15 Các cấu trúc liệu (Data Structures ) AssociatedIrp... PDRIVER_OBJECT driver = DeviceObject->DriverObject; 8/15 Các cấu trúc liệu (Data Structures ) return (*driver->MajorFunction[fcn ])( DeviceObject, Irp); } As you can see, IoCallDriver simply advances

Ngày đăng: 31/12/2015, 22:05

Từ khóa liên quan

Mục lục

  • Các cấu trúc dữ liệu (Data Structures )

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan