Example DMA Transfers

To illustrate these two strategies, consider the example of a fax board in an MS-DOS environment. The controlling application creates an image of the fax in application memory. It then programs the DMA controller to move the fax image to the memory on the fax board. The application then sends a command to the fax board (through an I/O port operation or other means) telling it to receive the DMA transfer and start sending the fax. In Windows NT, the unmodified MS-DOS application running under VDM requests the DMA and then signals the fax board to receive the DMA and begin sending the fax. However, there are two differences:

  1. The DMA controller has not really been programmed because the VDM intercepted the DMA request, although the application has no way of knowing this.

  2. The command to the fax board has been intercepted by the VDD. So now, the VDD must move the data specified by the DMA request to the board.

Using the double-buffer strategy described in Double-Buffer DMA Transfer, the VDD calls VDDRequestDMA to move the data from the application’s buffer to the VDD buffer. This call does not actually use the DMA controller, but performs the equivalent data transfer by other means. The VDD then calls the kernel-mode driver to move the data to the device. Finally, the VDD relays the send fax command to the kernel-mode driver.

Using the single-buffer strategy described in Single Buffer DMA Transfer, the VDD calls VDDQueryDMA to determine the parameters for the DMA request. The VDD then sends these parameters to the kernel-mode driver and enables the driver to control the data transfer directly from the application’s buffer to the device. When the driver has transferred the data, the VDD calls VDDSetDMA to update the DMA state. Finally, the VDD relays the send fax command to the kernel-mode driver.

The following functions are used for memory accesses:

FlushVDMPointer

Flushes data associated with a memory range.

FreeVDMPointer

Releases a pointer returned by GetVDMPointer.

GetVDMPointer

Returns a linear address for an x86 address.

VDDAllocMem

Allocates memory at a given virtual address.

VDDFreeMem

Releases previously allocated memory.

VDDDeInstallMemoryHook

Releases a range of memory-mapped I/O addresses.

VDDIncludeMem

Includes a particular memory range for use as a UMB.

VDDInstallMemoryHook

Releases memory-mapped addresses.

VDDQueryDMA

Gathers all DMA data.

VDDRequestDMA

Requests a DMA transfer from a VDD.

VDDSetDMA

Resets the state of the virtual DMA controller.