Hi
I am working with a driver that needs to handle a large amout of data very fast.
It is an embedded system, so security is not an issue, but speed is.
Our adapter is doing DMA (does not support scatterGather) in 4MB chunks,
but for the user mode program to be able to handle the data fast enough,
I need to concatenate these 4MB physical contigous chunks into one large virtual
contigous memory block. We have to support a virtual buffer of up 64GB.
What I am doing until now is that I am allocating a virtual buffer using
ZwAllocateVirtualMemory in order to find an empty area. The I free the memory
again. Now I have a start address of a free memory area. Using this start
address and the commands IoAllocateMdl, MmBuildMdlForNonPagedPool and
MmMapLockedPagesSpecifyCache, I am able to map the physical chunks into
a contigous virtual memory buffer.
The problem by doing this is that I cannot be sure that the memory area
continues to be free. I works fine for buffers up to 2GB, but for larger
buffer is fails a lot.
Here is an example of my code:
totalSize = 0;
for (i = 0; i < pMmap->count; i++) {
totalSize += pMmap->map[i].bufferSize;
}
// Reserve memory
nextAddress = NULL;
if (pMmap->count > 1) {
int retry = 0;
reservedSize = totalSize;
status = ZwAllocateVirtualMemory(NtCurrentProcess(), &nextAddress, 0L, &reservedSize, MEM_RESERVE, PAGE_NOACCESS);
if (STATUS_SUCCESS != status) {
return status;
}
ZwFreeVirtualMemory(NtCurrentProcess(), &nextAddress, &reservedSize, MEM_RELEASE);
}
for (i = 0; i < pMmap->count; i++) {
pMdl = IoAllocateMdl((PVOID)pMmap->map[i].driver.u.dataAddress, (ULONG)pMmap->map[i].bufferSize, FALSE, FALSE, NULL);
if (pMdl == NULL) {
log(ERR, “Error: IoAllocateMdl failed\n”);
return STATUS_INSUFFICIENT_RESOURCES;
}
MmBuildMdlForNonPagedPool(pMdl);
try
{
pMmap->map[i].user.u.pVirt = MmMapLockedPagesSpecifyCache(pMdl, UserMode, MmCached, nextAddress, FALSE, NormalPagePriority);
pMmap->map[i].base.u.dataAddress = (uint64_t)pMdl;
}
except(EXCEPTION_EXECUTE_HANDLER)
{
status = GetExceptionCode();
IoFreeMdl(pMdl);
return status;
}
// Map complete…
if (pMmap->count > 1) {
// If we have more than one mapping we need to be sure the mapping is contiguous.
if (nextAddress != pMmap->map[i].user.u.pVirt) {
// We did not get the wanted address range. Free all mapping.
// The other mappings will be freed by the fallback
MmUnmapLockedPages(pMmap->map[i].user.u.pVirt, pMdl);
IoFreeMdl(pMdl);
return STATUS_INSUFFICIENT_RESOURCES;
}
}
nextAddress = (PCHAR)nextAddress + pMmap->map[i].bufferSize;
}
Anyone who know a better (right) way to do this. I thought about using
chained MDL, but MmMapLockedPagesSpecifyCache does not support this.
Regards
Bent