Hi all,
I am using KMDF 1.5 on Windows XP 64 bit, Core2 Duo Processor.
I allocated a buffer in user mode and passed the pointer(PCHAR) into the
kernel mode driver. I then proceed to call the AllocateAndLockMdl which is
pasted below, which locks and generates an MDL for the usermode buffer.
I then get a scatter gather list by doing the following.
pVirtualAddress =
MmGetMdlVirtualAddress(pInternalDMABuffer->pMdlForDataBuffer);
ulLength = MmGetMdlByteCount(pInternalDMABuffer->pMdlForDataBuffer);
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DMA, “Virtual Add: %p, Length :
0x%x(%d)\n”, pVirtualAddress, ulLength, ulLength);
// Initialize this new DmaTransaction.
status = WdfDmaTransactionInitialize(
pInternalDMABuffer->DmaTransaction,
EvtProgramReadDma,
WdfDmaDirectionReadFromDevice,
pInternalDMABuffer->pMdlForDataBuffer,
pVirtualAddress,
ulLength
);
and WdfDmaTransactionExecute after that, in the callback I get a scatter
gather list that is much larger than the one that was allocated in user
mode. for instance when I allocated 2MB in user mode the sum of the scatter
gather elements gave me about 16MB.
Is passing the pointer to kernel mode right? If not, how do I go about
allocating a buffer in user mode that I could be using for DMA transfers
over and over until the size changes? I want to avoid the overhead of
allocating a scatter gather buffer for every transaction, because our system
has about 8 buffers whose size(4K - 256MB) change infrequently and does
about 100 to 250 DMA transactions a sec or more.
Thanks,
Ashok
//------------------------------------------------------------------------------------------
NTSTATUS AllocateAndLockMdl(IN PVOID uva, UINT64 ui64Bytes, PMDL *ppMdl)
{
ULONG offset = 0;
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DMA, “AllocateAndLockMdl –
Entry\n”);
if (ui64Bytes > MAX_TRANSFER_SIZE)
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_DMA, “AllocateAndLockMdl – Output
buffer exceeds max size of 0x%X\n”, MAX_TRANSFER_SIZE);
return STATUS_INVALID_PARAMETER;
}
// Check buffer alignment and size
__try
{
ProbeForWrite( uva, (SIZE_T)ui64Bytes, sizeof(UCHAR) );
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_DMA, “AllocateAndLockMdl –
ProbeForWrite thru exception\n”);
return STATUS_INVALID_PARAMETER;
}
// Allocate MDL(s) to describe buffer
while (ui64Bytes)
{
ULONG mdlSize = (ui64Bytes > MAX_MDL_SIZE) ? MAX_MDL_SIZE :
(ULONG)ui64Bytes;
PCHAR address = &((PCHAR)uva)[offset];
PMDL pMdl = NULL;
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DMA, “AllocateAndLockMdl – Alloc
MDL, addr 0x%08X, size 0x%08X\n”,
address, mdlSize);
pMdl = IoAllocateMdl(address, mdlSize, FALSE, TRUE, NULL);
if (!pMdl)
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_DMA, “AllocateAndLockMdl – Can’t
alloc MDL\n”);
return STATUS_INSUFFICIENT_RESOURCES;
}
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DMA, “AllocateAndLockMdl – No
IRP to associate, link ourselves\n”);
if (NULL == *ppMdl)
{
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DMA, “AllocateAndLockMdl – Link
0x%08X as primary\n”, pMdl);
*ppMdl = pMdl;
}
else
{
PMDL pList = *ppMdl;
while (pList && pList->Next) pList = pList->Next;
pList->Next = pMdl;
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DMA, “AllocateAndLockMdl – Link
0x%08X to 0x%08X\n”, pMdl, pList);
}
__try
{
MmProbeAndLockPages(pMdl, UserMode, IoWriteAccess);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_DMA, “AllocateAndLockMdl –
MmProbeAndLockPages thru exception, UserMode\n”);
return STATUS_INSUFFICIENT_RESOURCES;
}
offset += mdlSize;
ui64Bytes -= mdlSize;
}
return STATUS_SUCCESS;
}