Hello,
I’m writing a driver for a device that receives a high speed data stream. The data is written in a DMA buffer (size > 1MB) at the host system. The device writes the data cyclical in the buffer. In a later stage messages are read from the cyclic buffer. This implicates that the message at the end of the buffer will be fragmented in two parts, one at the end of the buffer, and one at the start. I would like to prevent that software has handle the fragmentation. Therefore I would like to map the start of the DMA buffer for the second time in virtual memory, behind the end of the DMA buffer. This way the fragmented message can still be read contiguously from virtual memory. In whit way could this be done?
I looked int the MDL structure. The MDL of the DMA buffer should be modified to add the pages of the start to the end. But thereis no API for it as far as I can see.
I also looked into MmAllocateMappingAddress, but that seems to fail with the 1MB MDL. Besides that, the issue can not be solved with MmAllocateMappingAddress MmMapLockedPagesWithReservedMapping, because MmMapLockedPagesWithReservedMapping accepts only the start address of the VM area returned by MmAllocateMappingAddress. I cannot use an address half-way the VM area returned by MmAllocateMappingAddress.
So, does anyone have any suggestion?
Thanks in advance…
>be fragmented in two parts, one at the end of the buffer, and one at the start. I would like to prevent
that software has handle the fragmentation.
For me, it is 100% obvious that actually handling this fragmentation in software is by far simpler (and thus better) then the perversion of double-mapping the first page just to avoid a couple of comparisons in software.
Nevertheless, if you really want it:
- build a MDL around the common buffer, use MmProbeAndLockPages
- MmAllocateMappingAddress for 1 more page then the buffer size
- MmMapLockedPagesWithReservedMapping for the common buffer’s MDL
- IoBuildPartialMdl for a second MDL of 1 page in size (head)
- MmMapLockedPagesWithReservedMapping for the partial MDL to the tail part of the reserved mapping.
Then undo everything properly.
–
Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com
> I also looked into MmAllocateMappingAddress, but that seems to fail with the 1MB MDL.
Then sorry, you cannot remap.
On a heavily loaded machine, you can trivially get into the situation where 1MB of system PTEs is a scarse resource.
an address half-way the VM area returned by MmAllocateMappingAddress.
Just try using this in contradiction with the docs. Can work.
The only other way is to handicraft the MDL tail by hand for a specially built MDL, and then to map this MDL.
–
Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com
> Hello,
I’m writing a driver for a device that receives a high speed data stream.
The data is written in a DMA buffer (size > 1MB) at the host system. The
device writes the data cyclical in the buffer. In a later stage messages
are read from the cyclic buffer. This implicates that the message at the
end of the buffer will be fragmented in two parts, one at the end of the
buffer, and one at the start. I would like to prevent that software has
handle the fragmentation. Therefore I would like to map the start of the
DMA buffer for the second time in virtual memory, behind the end of the
DMA buffer. This way the fragmented message can still be read contiguously
from virtual memory. In whit way could this be done?
I looked int the MDL structure. The MDL of the DMA buffer should be
modified to add the pages of the start to the end. But thereis no API for
it as far as I can see.
*****
If you want the buffer to be page-aligned and a multiple of an integral
number of pages, you make this a requirement on the application
programmer. If you receive an address which is not page-aligned, or an
integer multiple of pages in length, you return STATUS_INVALID_PARAMETER
and document that is what you will do.
APIs are Application Program Interface calls, and are done from user
space. So it is unlikely you would find one documented for use by the
kernel. Did you permaps mean a “DDI call”? Note that this would involve
you allocating a buffer in the kernel, and copying the data down to it,
because you cannot do anything which impacts the user allocation from the
kernel. This means you cannot construct a MDL which describes a space
different than the one you were passed from user space. You cannot
“prepend” data, align it to other than a page boundary, or append data in
any way.
As an alternative to rejecting the user call, you can round the start of
the buffer up to the next page boundary and truncate the end of the buffer
down to represent an integral number of pages by changing the length, then
constructing a “partial MDL” based on these new computations, and use
that.
You seem to be trying to construct a convoluted solution to a non-problem.
joe
******
I also looked into MmAllocateMappingAddress, but that seems to fail with
the 1MB MDL. Besides that, the issue can not be solved with
MmAllocateMappingAddress MmMapLockedPagesWithReservedMapping, because
MmMapLockedPagesWithReservedMapping accepts only the start address of the
VM area returned by MmAllocateMappingAddress. I cannot use an address
half-way the VM area returned by MmAllocateMappingAddress.
So, does anyone have any suggestion?
Thanks in advance…
NTDEV is sponsored by OSR
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer
Thank you for the responses!
I try to use the method Maxim states in his first mail. After rebooting the system MmAllocateMappingAddress did succeed.
I execute the following steps in the driver:
* Allocate 100MB of memory for a MDL with MmAllocatePagesForMdlEx() at startup of the driver
* In a ioctl call in the context of the calling user space application process I perform the following steps:
* call IoAllocateMdl() using size of 10MB
* call IoBuildPartialMdl() to build a partial MDL from the 100MB buffer
* call MmAllocateMappingAddress() with twice the size of the partial MDL: 20MB
* call MmMapLockedPagesSpecifyCache with the MDL and pointer returned by the previous step, and UserMode as parameter.
Now I get the following exception:
SYSTEM_SERVICE_EXCEPTION
I also tried MmMapLockedPagesWithReservedMapping() instead of MmMapLockedPagesSpecifyCache, but then I get exception:
SYSTEM_PTE_MISUSE
Any ideas?
Thanks
There is a way to do this using supported APIs but it’s a bit convoluted:
- Mdl1 = MmAllocatePagesForMdlEx (1 MB);
- UserVa =
3. MmMapLockedPagesSpecifyCache (Mdl1, UserMode, UserVa);
4. MmMapLockedPagesSpecifyCache (Mdl1, UserMode, UserVa + 1 MB);
5. Repeat steps 2-4 until both mappings succeed.
6. Mdl2 = IoAllocateMdl (UserVa, 2 MB);
7. MmProbeAndLockPages (Mdl2, UserMode);
8. SystemVa = MmGetSystemAddressForMdlSafe (Mdl2);
9. MmUnmapLockedPages (UserVa, Mdl1);
10. MmUnmapLockedPages (UserVa + 1 MB, Mdl1);
Now SystemVa will contain two virtually contiguous mappings of the same physical buffer. If the second mapping doesn’t need to cover the entire buffer, you can supply a smaller size to IoAllocateMdl in step 6, and maybe also use IoBuildPartialMdl instead of mapping the same MDL twice.
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@technolution.nl
Sent: Monday, November 07, 2011 1:54 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] mapping a DMA buffer twice in vitual memory contiguously
Hello,
I’m writing a driver for a device that receives a high speed data stream. The data is written in a DMA buffer (size > 1MB) at the host system. The device writes the data cyclical in the buffer. In a later stage messages are read from the cyclic buffer. This implicates that the message at the end of the buffer will be fragmented in two parts, one at the end of the buffer, and one at the start. I would like to prevent that software has handle the fragmentation. Therefore I would like to map the start of the DMA buffer for the second time in virtual memory, behind the end of the DMA buffer. This way the fragmented message can still be read contiguously from virtual memory. In whit way could this be done?
I looked int the MDL structure. The MDL of the DMA buffer should be modified to add the pages of the start to the end. But thereis no API for it as far as I can see.
I also looked into MmAllocateMappingAddress, but that seems to fail with the 1MB MDL. Besides that, the issue can not be solved with MmAllocateMappingAddress MmMapLockedPagesWithReservedMapping, because MmMapLockedPagesWithReservedMapping accepts only the start address of the VM area returned by MmAllocateMappingAddress. I cannot use an address half-way the VM area returned by MmAllocateMappingAddress.
So, does anyone have any suggestion?
Thanks in advance…
To me, IoBuildPartialMdl as you proposed is more intuitive. It should work.
I’ve done something very similar in principle but not exact.
Calvin
On Wed, Nov 9, 2011 at 12:28 PM, Pavel Lebedynskiy wrote:
> There is a way to do this using supported APIs but it’s a bit convoluted:
>
> 1. Mdl1 = MmAllocatePagesForMdlEx (1 MB);
> 2. UserVa =
> 3. MmMapLockedPagesSpecifyCache (Mdl1, UserMode, UserVa);
> 4. MmMapLockedPagesSpecifyCache (Mdl1, UserMode, UserVa + 1 MB);
> 5. Repeat steps 2-4 until both mappings succeed.
> 6. Mdl2 = IoAllocateMdl (UserVa, 2 MB);
> 7. MmProbeAndLockPages (Mdl2, UserMode);
> 8. SystemVa = MmGetSystemAddressForMdlSafe (Mdl2);
> 9. MmUnmapLockedPages (UserVa, Mdl1);
> 10. MmUnmapLockedPages (UserVa + 1 MB, Mdl1);
>
> Now SystemVa will contain two virtually contiguous mappings of the same
> physical buffer. If the second mapping doesn’t need to cover the entire
> buffer, you can supply a smaller size to IoAllocateMdl in step 6, and maybe
> also use IoBuildPartialMdl instead of mapping the same MDL twice.
>
> -----Original Message-----
> From: xxxxx@lists.osr.com [mailto:
> xxxxx@lists.osr.com] On Behalf Of
> xxxxx@technolution.nl
> Sent: Monday, November 07, 2011 1:54 AM
> To: Windows System Software Devs Interest List
> Subject: [ntdev] mapping a DMA buffer twice in vitual memory contiguously
>
> Hello,
>
> I’m writing a driver for a device that receives a high speed data stream.
> The data is written in a DMA buffer (size > 1MB) at the host system. The
> device writes the data cyclical in the buffer. In a later stage messages
> are read from the cyclic buffer. This implicates that the message at the
> end of the buffer will be fragmented in two parts, one at the end of the
> buffer, and one at the start. I would like to prevent that software has
> handle the fragmentation. Therefore I would like to map the start of the
> DMA buffer for the second time in virtual memory, behind the end of the DMA
> buffer. This way the fragmented message can still be read contiguously from
> virtual memory. In whit way could this be done?
>
> I looked int the MDL structure. The MDL of the DMA buffer should be
> modified to add the pages of the start to the end. But thereis no API for
> it as far as I can see.
>
> I also looked into MmAllocateMappingAddress, but that seems to fail with
> the 1MB MDL. Besides that, the issue can not be solved with
> MmAllocateMappingAddress MmMapLockedPagesWithReservedMapping, because
> MmMapLockedPagesWithReservedMapping accepts only the start address of the
> VM area returned by MmAllocateMappingAddress. I cannot use an address
> half-way the VM area returned by MmAllocateMappingAddress.
>
> So, does anyone have any suggestion?
>
> Thanks in advance…
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
Pavel,
Thank you for your hint. I did already notice that when I call MmMapLockedPagesSpecifyCache twice in a row with the same MDL, I get the MDL mapped, just as I need to. But this nechanism workt too much on coincidence, that I don’t want to use it.
I wonder why you don’t use MmAllocateMappingAddress() first to get UserVA. It would guarentee that both MDLs can be mapped.
For now I managed to do it with modifying the pages array of the MDL. But msdn says the following:
Note Changing the contents of the array can cause subtle system problems that are difficult to diagnose. We recommend that you do not read or change the contents of this array.
So I prefer mapping the MDL twice using MmMapLockedPagesSpecifyCache() somehow. I’ll keep the hints of Pavel in my mind.
First I have to get rid of the SYSTEM_SERVICE_EXCEPTION on MmMapLockedPagesSpecifyCache()
RMW
MmAllocateMappingAddress will not help here because each MmMapLockedPagesWithReservedMapping call requires its own reserved mapping, and you can’t create two such mappings that are contiguous with each other (at least not with any degree of reliability).
MmMapLockedPagesSpecifyCache(UserMode) is documented to raise exceptions on failures, so you need to wrap it in try/except. As for the reason it fails, are you trying to use it with a base address returned by MmAllocateMappingAddress? This will not work because MmMapLockedPagesSpecifyCache(UserMode) expects the base address to be NULL, or to point to a free user-space region.
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@technolution.nl
Sent: Monday, November 14, 2011 12:46 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] mapping a DMA buffer twice in vitual memory contiguously
Pavel,
Thank you for your hint. I did already notice that when I call MmMapLockedPagesSpecifyCache twice in a row with the same MDL, I get the MDL mapped, just as I need to. But this nechanism workt too much on coincidence, that I don’t want to use it.
I wonder why you don’t use MmAllocateMappingAddress() first to get UserVA. It would guarentee that both MDLs can be mapped.
For now I managed to do it with modifying the pages array of the MDL. But msdn says the following:
Note Changing the contents of the array can cause subtle system problems that are difficult to diagnose. We recommend that you do not read or change the contents of this array.
So I prefer mapping the MDL twice using MmMapLockedPagesSpecifyCache() somehow. I’ll keep the hints of Pavel in my mind.
First I have to get rid of the SYSTEM_SERVICE_EXCEPTION on MmMapLockedPagesSpecifyCache()