Scatter Gather Lists

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;
}

sorry, my mistake… stupid printing mistake.

“Ashok Bruno” wrote in message news:xxxxx@ntdev…
> 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;
> }
>