To close off this thread:
I haven’t had any luck making this work. I continue to get STATUS_INSUFFICIENT_RESOURCES from CalculateScatterGatherList.
- For now, I will set aside the “Hanging Direct I/O” approach and use the method of exposing a Common_Buffer to UserSW approach as it is working.
- Still, it’s on the back burner, so if you have any suggestions / comments, please post away - thanks in advance.
Recap of my [failed] implementation (Note: Code snippets have been “simplified” for brevity):
User SW:
// SW is allocating a data buffer using Large Pages (2MB). For this, SW needs to be running as Admin + have SE Privilege.
tp.Privileges[ 0 ].Attributes = SE_PRIVILEGE_ENABLED;
// enable privilege
status = AdjustTokenPrivileges( hToken, FALSE, &tp, 0, ( PTOKEN_PRIVILEGES ) NULL, 0 );
// For testing, allocate 4MB (2 pages) but will eventually need much more than this.
pointerToMemory = VirtualAlloc( NULL,
memorySize,
MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES,
PAGE_EXECUTE_READWRITE );
DeviceIoControl( pDevice->hFile,
IOCTL_SETUP_HOST_MEMORY_DMA,
inDataHostMemoryInfoP, sizeof( SetupHostMemoryInputBufferType ),
pointerToMemory , memorySize,
&bytesReturned, NULL ) );
Driver Device Add:
WDF_DMA_ENABLER_CONFIG dmaEnablerConfig;
WDF_DMA_ENABLER_CONFIG_INIT( &dmaEnablerConfig, WdfDmaProfileScatterGather64Duplex, 1024*4 );
dmaEnablerConfig.AddressWidthOverride = 0;
NTSTATUS status{ WdfDmaEnablerCreate( wdfDevice, &dmaEnablerConfig, WDF_NO_OBJECT_ATTRIBUTES, &( myDmaEnabler ) ) };
if( !NT_SUCCESS( status ) )
{
TraceEvents( TRACE_LEVEL_ERROR, DBG_INIT, "WdfDmaEnablerCreate() failed with status=[%!STATUS!]", status );
}
Driver Device Process IOCTL:
void EvtIoInCallerContext( IN WDFDEVICE device, IN WDFREQUEST request )
// Get the outbuffer from the IOCTL request
WDFMEMORY outputBufferObj{ nullptr };
WdfRequestRetrieveOutputMemory( request, &outputBufferObj );
// Get the outbuffer size. Note: outBuffP not actually needed, we just want the size.
PVOID outBuffP = WdfMemoryGetBuffer( outputBufferObj, &outBuffByteSize );
// Get the MDL from the outbuffer
WdfRequestRetrieveOutputWdmMdl( request, &hostMemoryMdlP );
// Get the DMA adapter.
PDMA_ADAPTER dmaAdapter = WdfDmaEnablerWdmGetDmaAdapter( myDmaEnabler,
WdfDmaDirectionReadFromDevice );
// Get the Kernel Virtual Address for the MDL
hostMemoryKvaP = MmGetSystemAddressForMdlSafe( hostMemoryMdlP,
HighPagePriority );
// Get the SG List size
dmaAdapter->DmaOperations->CalculateScatterGatherList( dmaAdapter,
hostMemoryMdlP,
hostMemoryKvaP,
hostMemoryMdlP->ByteCount,
&sgByteSize,
&numMapRegisters );
// Allocate memory for the SG List
PVOID scatterGatherListBuffP{ nullptr };
WdfMemoryCreate( &buffAttributes, PagedPool, 0,
static_cast<size_t>( sgByteSize ),
&scatterGatherMemoryObj, &scatterGatherListBuffP );
// Get the Device Object
PDEVICE_OBJECT deviceObjectP = WdfDeviceWdmGetDeviceObject( device );
// Get the SG List
dmaAdapter->DmaOperations->BuildScatterGatherList( dmaAdapter, deviceObjectP,
hostMemoryMdlP, hostMemoryKvaP,
static_cast<ULONG>( outBuffByteSize ),
&(MyAdapterListControl), deviceContextP, FALSE,
scatterGatherListBuffP, sgByteSize );