In their subsequent work, Blumrich et al.  developed a more general user-level DMA method. Their solution is based on the following idea: the two physical addresses needed to start a DMA will be given to the network interface by accessing the two shadow addresses. Their solution to user-level DMA is shown in figure 2.
Figure 2: SHRIMP solution to user-level DMA. This elegant solution to user-level DMA manages to pass all the arguments needed for the DMA to the network interface with only few instructions. Kernel modification is necessary to ensure atomic initiation of user-level DMA.
The STORE instruction is used to pass to the SHRIMP interface the physical address that corresponds to virtual address vdestination, and the size of the DMA transfer. The LOAD operation is used to pass to the SHRIMP interface the physical address that corresponds to virtual address vsource, and to return the status of the DMA initiation.
This solution has the following limitation: If the user process is interrupted after the STORE operation, but before the LOAD operation, then its arguments to the DMA operation may get mixed with arguments of other processes that want to start a user-level DMA and eventually a wrong DMA operation may be started. To alleviate this problem, Blumrich et al. suggested that ``the operating system must invalidate any partial initiated user-level DMA transfer on every context switch'', which implies that the context switch code (and the operating system kernel) must be changed to provide the support for the mentioned invalidations. Although, context switch code may be modified for the purposes of a research prototype, this severely limits the portability of user-level DMA in the market, for the reasons described in the introductory section.