Blumrich et al. described one of the first user-level DMA solutions
[2], developed in conjunction with the SHRIMP prototype.
In SHRIMP, each page that is used for communication, is ``mapped out''
to another page in a different workstation.
In this DMA mode of operation,
if a local page is used
as the source argument in a DMA operation, the destination
argument will always be its mapped-out page. To start a DMA operation,
an access to a shadow address is performed. This access, passes to the
DMA engine, the source address, the destination address (the ``mapped out''
page), the size of the DMA, and returns the success/failure of the DMA
initiation. All this information is passed by using a
compare-and-exchange atomic instruction. The address
argument of the instruction is the source address,
the data argument of the instruction is the size of the transfer,
and the return value is used to determine if the DMA operation
has started correctly.
This solution, although correct, is of limited functionality. A DMA operation can happen only between a page and its mapped out counterpart, which is very restrictive in practice. To achieve arbitrary user-level DMA transfers, the mapping between a page and its ``mapped-out'' page would have to change, which would result in significant operating system overhead.