1.
There are three methods for reading and writing device objects: Buffer mode (buffered mode), direct mode (direct mode), and neither mode. The flags of these three methods correspond to do_buffered_io, do_direct_io, and 0 respectively.
In buffered mode, the I/O manager first creates a system buffer with the same size as the user mode data buffer. And your driver will use this system buffer to work. The I/O manager is responsible for copying data between the system buffer zone and the user mode buffer zone.
In direct mode, the I/O manager locks the physical memory page containing the user mode buffer, and creates a secondary data structure called MDL (memory Descriptor Table) to describe the lock page. Therefore, your driver will work with MDL.
In the neither mode, the I/O manager simply transmits the virtual address in user mode to you. The driver that uses the user mode address should be very careful.
2.
The following describes how to read and write data in a buffer. The advantage is that it solves the problem of transferring user addresses to the driver. The disadvantage is that data replication between the user mode and the kernel mode is required. It is conceivable that the running efficiency will be affected. This method is suitable for a small amount of memory operations.
Take readfile as an example. First, the application needs to provide a buffer and pass the buffer size as a parameter. For example
Uchar outputbuffer [10];
DWORD retlen = 0;
Readfile (hdevice, outputbuffer, sizeof (outputbuffer), & retlen, null );
Outputbuffer is the provided output buffer and the memory address in user mode. The operating system copies the data in the buffer to the address in kernel mode. sizeof (outputbuffer) is the buffer size, retlen is the actual number of output bytes.
How can we get the address of this kernel mode in kernel mode? How can we get the number of bytes of writefile or readfile? The answer is as follows.
The address in this kernel mode can be obtained through the associatedirp. systembuffer of the IRP created in this readfile.
If the requested IRP is pirp (usually the parameter of the dispatch function), then uchar * outputbuffer = (uchar *) pir-> associatedirp. systembuffer;
The number of bytes in the readfile request is parameters. Read. Length in io_stack_location, and writefilew is parameters. Write. Length in io_stack_location.
// Obtain the current stack
Pio_stack_location stack = iogetcurrentirpstacklocation (pirp );
// Obtain the readfile buffer size
Ulong cbread = stack-> parameters... read. length;
// Obtain the writefile buffer size
Ulong cbwrite = stack-> parameters. Write. length;
After obtaining the buffer address in kernel mode, you can operate on the buffer. For example:
Uchar * outputbuffer = (uchar *) pirp-> associatedirp. systembuffer;
Ulong cbread = stack-> parameters... read. length;
Memcpy (outputbuffer, 0xbb, cbread );
In this way, the data in the buffer zone in user mode is 0xbb.
In addition, you also need to set the number of bytes for the actual operation, pirp-> iostatus. information = cbread; (the actual number of bytes does not have to be set to the buffer size, but should not be greater than the buffer size)
In user mode, the retlen of readfile is set to cbread.
3.
Note: If you call deviceiocontrol in user mode, the buffer information is obtained as follows:
// Obtain the current stack
Pio_stack_location stack = iogetcurrentirpstacklocation (pirp );
// Obtain the input buffer size
Ulong cbin = stack-> parameters. deviceiocontrol. inputbufferlength;
// Obtain the size of the output buffer.
Ulong cbout = stack-> parameters. deviceiocontrol. outputbufferlength;
// Input buffer data
Uchar * inputbuffer = (uchar *) pirp-> associatedirp. systembuffer;
// Operation output buffer
Uchar * outputbuffer = (uchar *) pirp-> associatedirp. systembuffer;
Pirp-> iostatus. Information = number of actual operation bytes.
Device read/write mode for driver development: Buffer Mode