From - Fri Oct 31 07:36:14 1997 Path: news.mitre.org!blanket.mitre.org!agate!newsgate.cuhk.edu.hk!logbridge.uoregon.edu!ais.net!news1.chicago.iagnet.net!iagnet.net!usc!newshub.cts.com!newsfeed.cts.com!cmkrnl!jeh From: jeh@cmkrnl.com (Jamie Hanrahan) Newsgroups: comp.os.ms-windows.programmer.nt.kernel-mode Subject: Re: DMA to User Mode allocated buffer outside of calling thread context Message-ID: <1997Oct30.184849.8284@cmkrnl> Date: 30 Oct 97 18:48:49 PST References: <878238171.27449@dejanews.com> Organization: Kernel Mode Systems, San Diego, CA Lines: 76 In article <878238171.27449@dejanews.com>, ejs01@mhs.sperry-marine.com (Eric Solberg) writes: > Hello, > > I'm writing an NT Device Driver for a PCI Bus Master device that supports > DMA through a PLX 9080 interface chip. The driver supports IOCTL's from > a user mode application. > > I intend to have the user mode application allocate a buffer and send the > buffer to the driver via DeviceIoControl. The buffer will be written to > via DMA at a rate of about 1MB/second. I need to be able to write into > the buffer at any point in time. Therefore, this buffer must be > accessible to the driver at all times (outside the thread context of user > application that gives the driver the buffer). > > I believe the following should give me the results I'm looking for, but > it doesn't work quite right.: > > IoAllocateMdl() to create an MDL for use by the driver independent of any > IRP. MmProbeAndLockPages() with the allocated MDL from IoAllocateMdl. If you were going to do it this way (which isn't the right approach, but more on that in a moment...) There is no need to bother with all this. Just set up an "IO" request whose purpose is "tell the driver that this is the buffer to use". Have the driver not complete this request. Have the app not block on this request, but cancel it later. The driver can use the cancel of this "map the buffer" IRP to tell it to unmap the buffer. > MmMapLockedPages() with the MDL that now has locked pages. > MmGetSystemAddressForMdl() with the MDL that now has locked pages. These two calls are redundant wrt each other. Use only MmGetSystemAddressForMdl for creating system-space addresses for an MDL. > MmGetPhysicalAddress() with the system address returned by > MmGetSystemAddressForMdl. The MDL, Virtual Address, System Address, and > Physical Address are kept in the DeviceExtension. > > Later, the device interrupts the driver telling it that acquired data > needs to be transferred. The driver then DMA's the device memory > contents to the user buffer residing at the physical address acquired in > the steps above. > > In the physical memory (for the user buffer) everything shows up > correctly. Although the physical memory (for the user buffer) contains > the DMA'd data only pieces of the data show up in the application buffer. > Why? Because you haven't looked far enough into the physical memory, or into the MDL. If you look carefully at the MDL you will find that the buffer is almost certainly physically discontiguous. e.g. if it's three pages long it might sit on PFNs 35, 5A, and 2C. Alas your MmGetPhysicalAddress only returns the physical address of the first page (35xxx). Hence your DMA transfer does the first page ok but then blithely clobbers physical pages 36 and 37. > I'm in DIRE need of an answer to this problem. When starting from an application's buffer, you should use IoMapTransfer, not MmGetPhysicalAddress, to get the logical address of each of the buffer pages from the MDL. If your device does not support DMA scatter/gather, and you want to avoid NT's buffer copying magic, you will have to use HalAllocateCommonBuffer, and map the buffer so allocated to process space instead of the other way around. --- Jamie Hanrahan, Kernel Mode Systems, San Diego CA Internet: jeh@cmkrnl.com (JH645) CompuServe: 74140,2055 drivers, internals, networks, applications, and training for VMS and Windows NT NT driver FAQ, links, and other information: http://www.cmkrnl.com/ If you post a reply in news, please don't e-mail it too.