Access to User Buffers

< BACK  NEXT >
[oR]

When a user-mode thread makes an I/O request, it usually passes the address of a data buffer located in user space. Since user-mode addresses are referenced through the lower half (< 2 GB) of the page tables, a driver must cope with the possibility that the page tables will change before the request can be completed. This would occur if the driver code executed at Interrupt Context or Kernel-Mode Thread context. As previously discussed, the lower half of the page tables are changed with each process switch. Thus, code executing with an arbitrary page table state cannot assume that any user-mode address is valid.

Worse, the user buffer may be paged out of RAM and exist only on the system's swap file on disk. User memory is always subject to swap-out if the system needs RAM for other processes.

In general, user memory is pagable, and by rule, pagable memory may not be accessed at DISPATCH_LEVEL_IRQL or higher. This rule is necessary since the tasks providing page-in service of the requested memory might need a device at a lower DIRQL than that which needed the page.

Buffer Access Mechanisms

Now that the problem is defined, a solution is needed. Fortunately, the I/O Manager provides drivers with two different methods for accessing user buffers. When a driver initializes, it tells the I/O Manager which strategy it plans to use. The choice depends on the nature and speed of the device.

The first strategy is to ask the I/O Manager to copy the entire user buffer into dedicated system RAM, which remains fixed (i.e., not paged) in both the page tables and physical memory. The device uses the copy of the buffer to perform the requested I/O operation. Upon completion, the I/O Manager conveniently copies the system buffer back to the user buffer. Actually, only one copy operation is performed. On I/O write requests, the user buffer is copied before presentation to the driver. On I/O read requests, the system buffer is copied after the driver marks the request as completed. Standard read or write requests do not require bidirectional copying.

The first technique is known as buffered I/O (BIO). It is used by slower devices that do not generally handle large data transfers. The technique is simple for driver logic, but requires the somewhat time-consuming job of buffer copying.

The second technique avoids the buffer copy by providing the driver with direct access to the user's buffer in physical memory. At the beginning of the I/O operation, the I/O Manager "locks down" the entire user buffer into memory, thus preventing the block from swap-out and causing a deadly page fault. It then constructs a list of page table entries that are mapped into slots above 2 GB and are thus not subject to process context switches. With the memory and page table entries locked for the duration of the I/O request, driver code may safely reference the user buffer. (Note, however, that the original user address is translated into another logical address, valid only from kernel-mode code. The driver must use the translated address.)

This second technique is well-suited for fast devices that transfer large blocks of data. It is known as direct I/O (DIO). DMA devices almost always use this technique and it is further discussed in chapter 12.

< BACK  NEXT >


The Windows 2000 Device Driver Book(c) A Guide for Programmers
The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition)
ISBN: 0130204315
EAN: 2147483647
Year: 2000
Pages: 156

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net