Dispatch function IRP

Source: Internet
Author: User
Tags win32 error subdomain

Dispatch function is an important concept in the Windows Driver. The main function of the driver is to process I/O requests.
It is handled in dispatch letters.

All the I/O requests to the driver in user mode are converted from the operating system to an IRP data structure.
"Dispatch" to different dispatch letters.


IRP and dispatch functions

The Processing Mechanism of IRP is similar to "message processing" in Windows applications. After the driver receives different IRPs
Dispatch function. IRP is processed in dispatch letter count.


1. IRP

In the Windows Kernel, there is a data structure called IRP (I/O Request Package), that is, the input and output Request Package. Upper-layer application
When the program communicates with the underlying driver, the application sends an I/O Request. The operating system converts I/O requests to corresponding IRP data.
Type IRP will be passed to different dispatch letters.

IRP has two basic attributes: MajorFunction and MinorFunction, which respectively record the primary type and subtype of IRP.
Type. The operating system sends the IRP to different dispatch letters based on the MajorFunction. You can continue to judge the number of dispatch letters.
Which MinorFunction does this IRP belong.

The registration of dispatch functions in DriverEntry of HelloDDK is as follows:

[Cpp] view plaincopy
# Pragma INITCODE
Extern "C" NTSTATUS DriverEntry (
IN PDRIVER_OBJECT pDriverObject,
IN PUNICODE_STRING pRegisterPath
)
{
NTSTATUS status;
KdPrint ("Enter DriverEntry \ n "));

// Set the uninstall Function
PDriverObject-> DriverUnload = HelloDDKUnload;

// Set the dispatch function
PDriverObject-> MajorFunction [IRP_MJ_CREATE] = HelloDDKDispatchRoutine;
PDriverObject-> MajorFunction [IRP_MJ_CLOSE] = HelloDDKDispatchRoutine;
PDriverObject-> MajorFunction [IRP_MJ_WRITE] = HelloDDKDispatchRoutine;
PDriverObject-> MajorFunction [IRP_MJ_READ] = HelloDDKDispatchRoutine;
PDriverObject-> MajorFunction [IRP_MJ_CLEANUP] = HelloDDKDispatchRoutine;
PDriverObject-> MajorFunction [IRP_MJ_SET_INFORMATION] = HelloDDKDispatchRoutine;
PDriverObject-> MajorFunction [IRP_MJ_DEVICE_CONTROL] = HelloDDKDispatchRoutine;
PDriverObject-> MajorFunction [IRP_MJ_SHUTDOWN] = HelloDDKDispatchRoutine;
PDriverObject-> MajorFunction [IRP_MJ_SYSTEM_CONTROL] = HelloDDKDispatchRoutine;

// Create a driver object
Status = CreateDevice (pDriverObject );

KdPrint ("Leave DriverEntry \ n "));
Return status;

}

2. IRP type
Functions related to file I/O, such as CreateFile, ReadFile, WriteFile, CloseHandle, etc.
RP_MJ_CREATE, IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_CLOSE, and so on. In addition, file I/O processing in the kernel
Functions, such as ZwCreateFile, ZwReadFile, ZwWriteFile, and ZwClose, also generate the above IRPs.

The types of IRPs are listed and the sources of IRPs are described.


IRP type Source

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------

IRP_MJ_CREATE creates a device, and CreateFile generates this IRP

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------

IRP_MJ_CLOSE: closes the device. CloseHandle will generate this IR
P

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------
IRP_MJ_CLEANUP cleanup, CloseHandle will generate this IRP

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------
The IRP_MJ_DEVICE_CONTROL DeviceControl function generates this IRP

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------
IRP_MJ_PNP refers to the out-of-the-box message, which is not supported by the NT driver.
Only the WDM driver supports secondary IRP.

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------
IRP_MJ_POWER is generated when the operating system processes power messages.
IRP

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------
IRP_MJ_QUERY_INFORMATION: get the file length. GetFileSize will generate IRP

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------
IRP_MJ_READ reads the device content, which is generated by ReadFile
IRP

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------
IRP_MJ_SET_INFORMATION sets the file length. GetFileSize will generate IRP

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------
IRP_MJ_SHUTDOWN will generate this IRP before shutting down the system

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------
The internal control information generated by the IRP_MJ_SYSTEM_CONTROL system is similar to the kernel that calls DeviceC.
Ontrol Function

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------
IRP_MJ_WRITE will generate
IRP

Bytes ------------------------------------------------------------------------------------------
-----------------------------------------------------


3. Simple handling of dispatch functions

Most IRPs are derived from Win32API for file I/O processing. The simplest way to process these IRPs is to convert the IRPs
The status is set to successful, then the request for IRP is terminated, and the dispatch function is returned successfully. The IoCompleteRe function is used to end an IRP request.
Quest .. The following code demonstrates a simple dispatch function for processing IRP requests.

[Plain] view plaincopy
NTSTATUS HelloDDKDispatchRoutine (IN PDEVICE_OBJECT p1_bj, in pirp pIrp)
{
KdPrint ("Enter HelloDDKDispatchRoutine \ n "));
// Simple operations on general IRPs
NTSTATUS status = STATUS_SUCCESS;
// Sets the IRP completion status.
PIrp-> IoStatus = status;
// Sets the number of bytes for the IRP operation.
PIrp-> IoStatus. Information = 0;
// Process IRP
IoCompleteRequest (pIrp, IO_NO_INCREMENT );
KdPrint ("Leave HelloDDKDispatchRputine "));
Return status;
}

In this example, the dispatch function sets the completion status of IRP to STATUS_SUCCESS. In this way, the Win32API that initiates the I/O operation request will return
Returns TRUE. Otherwise, FALSE is returned. In this case, you can use GetLastError Win32API to get the error code.
The error code is in the same status as that set by IRP.
In addition to setting the completion status of the IRP, the dispatch function also sets the number of bytes of the IRP operation.

The dispatch function ends the IRP request, which is completed through the IoCompleteRequest function.


4. Open the device through the device link

To open a device, you must use the device name to obtain the handle of the device. As described earlier, each device has a device name, such as Hell.
The Device name of the oDDK driver is \ Device \ MyDDKDevice, but the Device name cannot be queried by the application in user mode.
The device name can only be queried by programs in kernel mode. In the application, you need to access through a symbolic link.

The following program shows how to enable the driver in user mode:

[Cpp] view plaincopy
# Include <windows. h>
# Include <stdio. h>

Int main ()
{
HANDLE hDevice =
CreateFile ("\\\\\ HelloDDK ",
GENERIC_READ | GENERIC_WRITE,
0, // share mode none
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL); // no template

If (hDevice = INVALID_HANDLE_VALUE)
{
Printf ("Failed to obtain file handle to device :"
"% S with Win32 error code: % d \ n ",
"MyWDMDevice", GetLastError ());
Return 1;
}

CloseHandle (hDevice );
Return 0;
}


5. Compile a more general dispatch function
In Windows driver development, there is an important kernel data structure, IO_STACK_LOCATION, that is, the I/O stack. This data structure and
IRP is closely connected.

The driver object creates Device objects and stacks them into a vertical structure called the device stack ". IRP MEETING
The request is sent by the operating system to the top layer of the device stack. If the top-layer device ends the request, the I/O Request ends.
End. You can forward the IRP to the next device. Therefore, an IRP may be forwarded multiple times. To record IRPs in each layer of devices
Operation, the IRP will have an IO_STACK_LOCATION array, each IO_STACK_LOCATION element records the operations performed in the corresponding device
. For the IO_STACK_LOCATION of the current layer, you can use the IoGetCurrentIrpStackLocation function. IO_STACK_LOCA
The type of IRP is recorded in the TION structure, that is, the MajorFuncation subdomain in IO_STACK_LOCATION.

The following code makes the dispatch function more difficult:

[Plain] view plaincopy
# Pragma PAGEDCODE
NTSTATUS HelloDDKDispatchRoutine (IN PDEVICE_OBJECT p1_bj, in pirp pIrp)
{
KdPrint ("Enter HelloDDKDispatchRoutine \ n "));

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation (pIrp );
// Create a string array that corresponds to the IRP type
Static char * irpname [] =
{
"IRP_MJ_CREATE ",
"IRP_MJ_CREATE_NAMED_PIPE ",
"IRP_MJ_CLOSE ",
"IRP_MJ_READ ",
"IRP_MJ_WRITE ",
"IRP_MJ_QUERY_INFORMATION ",
"IRP_MJ_SET_INFORMATION ",
"IRP_MJ_QUERY_EA ",
"IRP_MJ_SET_EA ",
"IRP_MJ_FLUSH_BUFFERS ",
"IRP_MJ_QUERY_VOLUME_INFORMATION ",
"IRP_MJ_SET_VOLUME_INFORMATION ",
"IRP_MJ_DIRECTORY_CONTROL ",
"IRP_MJ_FILE_SYSTEM_CONTROL ",
"IRP_MJ_DEVICE_CONTROL ",
"IRP_MJ_INTERNAL_DEVICE_CONTROL ",
"IRP_MJ_SHUTDOWN ",
"IRP_MJ_LOCK_CONTROL ",
"IRP_MJ_CLEANUP ",
"IRP_MJ_CREATE_MAILSLOT ",
"IRP_MJ_QUERY_SECURITY ",
"IRP_MJ_SET_SECURITY ",
"IRP_MJ_POWER ",
"IRP_MJ_SYSTEM_CONTROL ",
"IRP_MJ_DEVICE_CHANGE ",
"IRP_MJ_QUERY_QUOTA ",
"IRP_MJ_SET_QUOTA ",
"IRP_MJ_PNP ",
};
UCHAR type = stack-> MajorFunction;
If (type> = arraysize (irpname ))
{
KdPrint ("-Unknow IRP, major type % X \ n", type ));
}
Else
{
KdPrint ("\ t % s \ n", irpname [type]);
}
// Simple operations on the general IRP. More complex operations on the IRP will be introduced later.
NTSTATUS status = STATUS_SUCCESS;
// Complete the IRP
PIrp-> IoStatus. Status = status;
PIrp-> IoStatus. Information = 0;
IoCompleteRequest (pIrp, IO_NO_INCREMENT );
KdPrint ("Leave HelloDDKDispatchRoutine \ n "));

Return status;

}


Buffer-based read/write operations

The device created by the driver generally has three read/write modes: one is the buffer mode, the other is the direct mode, and the other is the buffer mode.
.


1. Buffer Mode

After IOCreateDevice creates a device, you need to set the Flags subdomain of the device object. Setting different Flags will lead to different
To operate the device.

There are three read/write methods for device objects. The Flags of these three methods correspond to DO_BUFFERED_ID, DO_DIRECT_IO, and 0 respectively.
, The buffer mode is relatively simple to read and write.

Read/write operations are generally caused by the ReadFile or WriteFile function. Here we will introduce the WriteFile function as an example. WriteFil
E. Ask the user to provide a buffer and describe the buffer size. Then, WriteFile transfers the data in the memory to the driver.
.

This buffer memory is the user-mode memory address. It is very dangerous for the driver to directly reference this memory. If a buffer is used
The operating system copies the data in the buffer zone provided by the program to the address in kernel mode.
The address of the kernel mode does not change. The IRP dispatch function operates the buffer address in kernel mode, while
It is not the buffer address in user mode. However, this will have a certain impact on efficiency.


2. read/write of the buffer device

When writing a device as a buffer, the operating system copies the user-mode buffer provided by WriteFile to the kernel-mode address.
The AssociateIrp. SystemBuffer subdomain record of the IRP created by WriteFile.

In addition, you can also use the Parameters. Read. Length subdomain in IO_STACK_LOCATION to know the ReadFile request.
The number of bytes. You can use the Parameters. Write. Length subdomain in IO_STACK_LOCATION to know the number of bytes of the WriteFile request.

Then, WriteFile and ReadFile specify the number of bytes to operate on the device. This does not really mean that so many bytes are operated. In the dispatch function
You should set the IoStatus. Information of the subdomain of IRP. This subdomain records the number of bytes actually operated by the device.

The following code demonstrates how to read a device using a buffer:

[Plain] view plaincopy
NTSTATUS HelloDDKRead (IN PDEVICE_OBJECT p1_bj, in pirp pIrp)
{
KdPrint ("Enter HelloDDKRead \ n "));

// Process General IRPs. More complex processing of IRPs will be introduced later.
NTSTATUS status = STATUS_SUCCESS;

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation (pIrp );
// Obtain the number of bytes of the device to be read
ULONG ulReadLength = stack-> Parameters. Read. Length;

// Complete the IRP
// Sets the IRP completion status.
PIrp-> IoStatus. Status = status;

// Sets the number of bytes for the IRP operation.
PIrp-> IoStatus. Information = ulReadLength;

Memset (pIrp-> AssociatedIrp. SystemBuffer, 0XAA, ulReadLength );

// Process IRP
IoCompleteRequest (pIrp, IO_NO_INCREMENT );
KdPrint ("Leave HelloDDKRead \ n "));

Return status;

}

Program in ring3 to read data:
[Plain] view plaincopy
# Include <windows. h>
# Include <stdio. h>

Int main ()
{
HANDLE hDevice =
CreateFile ("\\\\\ HelloDDK ",
GENERIC_READ | GENERIC_WRITE,
0, // share mode none
NULL, // no security
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL); // no template

If (hDevice = INVALID_HANDLE_VALUE)
{
Printf ("Failed to obtain file handle to device :"
"% S with Win32 error code: % d \ n ",
"MyWDMDevice", GetLastError ());
Return 1;
}

UCHAR buffer [10];
ULONG ulRead;
BOOL bRet = ReadFile (hDevice, buffer, 10, & ulRead, NULL );
If (bRet)
{
Printf ("Read % d bytes:", ulRead );
For (int I = 0; I <(int) ulRead; I ++)
{
Printf ("% 02X", buffer [I]);
}

Printf ("\ n ");
}

CloseHandle (hDevice );
Return 0;
}

Direct read/write:
1. Directly read the device:

In addition to the "buffer" method, the other method is to read and write devices directly. This method requires that after the device object is created
When setting device properties, set it to DO_DIRECT_IO.
Different from the buffer read/write method, the operating system locks the buffer in user mode. Then the Operating System
The buffer is mapped again in kernel mode. In this way, the user-mode buffer and the kernel-mode buffer point to the same region
Physical memory. No matter how the operating system switches the process, the kernel mode address remains unchanged.

After the operating system locks the user-mode address, the operating system uses the memory Descriptor (MDL Data Structure) to record this memory segment.

MDL records this virtual memory, and the size of this virtual memory is stored in mdl-> ByteCount. The first page address of this virtual memory is
Mdl-> StartVa. the offset of the first address of the virtual memory segment to the address on the first page is mdl-> ByteOffset ,. Therefore
The first address of the proposed memory should be mdl-> StartVa + mdl-> ByteOffset.

DDK provides several macros for programmers to get these values:

[Plain] view plaincopy
# Define MmGetMdlByteCount (mdl) (Mdl)-> ByteCount)

# Define MmGetMdlByteOffset (mdl) (Mdl)-> ByteOffset)

# Define MmGetMdlVirtualAddress (mdl) (PVOID) (PCHAR) (Mdl-> StartVa) + (Mdl)-> ByteOffset ))

2. Read and Write the device directly.
The following code demonstrates how to compile a dispatch function for a device directly.

[Plain] view plaincopy
NTSTATUS HelloDDKRead (IN PDEVICE_OBJECT p1_bj,
In pirp)
{
KdPrint ("Enter HelloDDKRead \ n "));

PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) p1_bj-> DeviceExtension;
NTSTATUS status = STATUS_SUCCESS;

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation (pIrp );

ULONG ulReadLength = stack-> Parameters. Read. Length;
KdPrint ("ulReadLength: % d \ n", ulReadLength ));

ULONG mdl_length = MmGetMdlByteCount (pIrp-> MdlAddress );
PVOID mdl_address = MmGetMdlVirtualAddress (pIrp-> MdlAddress );
ULONG mdl_offset = MmGetMdlByteOffset (pIrp-> MdlAddress );

KdPrint ("mdl_address: 0X % 08X \ n", mdl_address ));
KdPrint ("mdl_length: % d \ n", mdl_length ));
KdPrint ("mdl_offset: % d \ n", mdl_offset ));

If (mdl_length! = UlReadLength)
{
// The MDL length should be equal to the read length; otherwise, this operation should be set to unsuccessful.
PIrp-> IoStatus. Information = 0;
Status = STATUS_UNSUCCESSFUL;
} Else
{
// Use MmGetSystemAddressForMdlSafe to obtain the MDL ing in kernel mode.
PVOID kernel_address = MmGetSystemAddressForMdlSafe (pir-> MdlAddress, NormalPagePri
Ority );
KdPrint ("kernel_address: 0X % 08X \ n", kernel_address ));
Memset (kernel_address, 0XAA, ulReadLength );
PIrp-> IoStatus. Information = ulReadLength; // bytes xfered
}

PIrp-> IoStatus. Status = status;

IoCompleteRequest (pIrp, IO_NO_INCREMENT );
KdPrint ("Leave HelloDDKRead \ n "));

Return status;
}


Other read/write operations:

This method is not discussed here.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.