The previous section introduces the buffer-based read/write method. Let's take a look at the direct read/write method.
1.
Directly read and write the device. The operating system locks the buffer in user mode, and then the operating system maps the buffer address in kernel mode again. In this way, the user-mode buffer and the kernel-mode buffer point to the physical memory in the same region. No matter how the operating system switches the process, the kernel mode address remains unchanged.
After iocreatedevice is created, you need to set do_direct_io, p1_bj-> flags | = do_direct_io.
2.
Memory Descriptor Table (MDL)
The MDL structure declaration is as follows:
Typedef struct _ MDL {
Struct _ MDL * next;
Cshort size;
Cshort mdlflags;
Struct _ eprocess * process;
Pvoid mappedsystemva;
Pvoid startva; // specifies the virtual address of the user buffer. The address on the first page is valid only in the context of the user mode process that owns the data buffer.
Ulong bytecount; // The length of the buffer in bytes.
Ulong byteoffset; // The Offset Value of the starting position of the buffer on a page frame. The first address of the buffer is MDL-> startva + MDL-> byteoffset.
} MDL, * pmdl;
The structure of the memory Descriptor Table (MDL) is as follows:
The figure shows that the buffer in user mode is continuous in virtual memory, but it may be discrete in physical memory.
3. The following describes some MDL-related functions.
Ioallocatemdl |
Create MDL |
Iobuildpartialmdl |
Create a child MDL with an existing MDL |
Iofreemdl |
Destroy MDL |
Mmbuildmdlfornonpagedpool |
Modify MDL to describe a non-Paging memory area in kernel mode |
Mmgetmdlbytecount |
Buffer byte size (get MDL-> bytecount) |
Mmgetmdlbyteoffset |
Take the offset of the buffer on the first memory page (get MDL-> byteoffset) |
Mmgetmdlvirtualaddress |
Obtain the virtual address (pvoid) (pchar) (MDL-> startva + MDL-> byteoffset )) |
Mmgetsystemaddressformdl |
Create a kernel mode virtual address mapped to the same memory location |
Mmgetsystemaddressformdlsafe |
Same as mmgetsystemaddressformdl, but preferred for Windows 2000 |
Mminitializemdl |
(Again) initialize MDL to describe a given virtual buffer |
MMP reparemdlforreuse |
Initialize MDL again |
MMP robeandlockpages |
Lock the memory page after address validity Verification |
Mmsizeofmdl |
The memory size occupied by the MDL that describes a given virtual buffer. |
Mmunlockpages |
Unlock the Memory Page for this MDL |
4. The following uses readfile as an example to describe how to directly read a device.
Call readfile in user mode:
Uchar outputbuffer [10];
DWORD retlen = 0;
Readfile (hdevice, outputbuffer, sizeof (outputbuffer), & retlen, null );
The number of bytes to be read in kernel mode: (same as the buffer read/write mode)
// Obtain the current stack
Pio_stack_location stack = iogetcurrentirpstacklocation (pirp );
// Obtain the number of bytes read by readfile.
Ulong cbread = stack-> parameters... read. length;
In addition, the MDL data structure is obtained through the pirp-> mdladdress of the IRP. This structure describes the memory of the locked buffer.
The following is a dispatch function of irp_mj_read for your reference only.
Ntstatus dispathread; pio_stack_location stack = iogetcurrentirpstacklocation (pirp); ulong ulreadlength = stack-> parameters. read. length; // get the read length kdprint ("ulreadlength: % d \ n", ulreadlength); ulong mdl_length = mmgetmdlbyteco Unt (pirp-> mdladdress); // MDL Virtual Memory Length pvoid mdl_address = mmgetmdlvirtualaddress (pirp-> mdladdress ); // starting address of the virtual memory ulong mdl_offset = mmgetmdlbyteoffset (pirp-> mdladdress); // offset of the first address of the virtual memory on the first page 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 pir-> iostatus. information = 0; status = status_unsuccessful;} else {// use mmgetsystemaddressformdlsafe to obtain the MDL ing in kernel mode and map it To the memory address in kernel mode, pvoid kernel_address = Priority (pirp-> mdladdress, normalpagepriority); kdprint ("kernel_address: 0x % 08x \ n", kernel_address); memset (kernel_address, 0xaa, ulreadlength); // perform operations on the memory address in kernel mode pirp-> iostatus. information = ulreadlength; // set the actual number of bytes for the Operation} pirp-> iostatus. status = status; iocompleterequest (pirp, io_no_increment); kdprint ("Leave dispatchread \ n"); Return status ;}
Device read/write mode for driver development: Buffer mode see: http://blog.csdn.net/liyun123gx/article/details/38042125
Neither method reference: http://blog.csdn.net/liyun123gx/article/details/38046865
Device read/write Method for driver development: direct mode