Hello Peter:
Thanks for bearing with me and for the good info:
I attempted the common buffer approach last night and ran into an issue with my User SW getting an access violation. I had done everything from creating the DmaEnabler to MmMapLockedPagesSpecifyCache in my EvtDeviceAdd; Storing the addresses in the device context. Then I created an IOCTL for my User SW to call and retrieve the Virtual User Address.
Searching the forum, I found a post, by you actually, pointing out that the MmMapLockedPagesSpecifyCache call needs to be done in the correct Context and that a good location for this would be EvtIoInCallerContext and not EvtIoDeviceControl (which is where I was going to move it to next, as a part of the IOCTL).
https://community.osr.com/discussion/279797
@“Peter_Viscarola_(OSR)”
…EvtIoDeviceControl (in fact, EvtIoXxxx) is called in an arbitrary process and thread context. You need to use the EvtIoInCallerContext callback…
So, I added an EvtIoInCallerContext and moved the MmMapLockedPagesSpecifyCache to the method.
Unfortunately, I am still getting the access violation. Code Snippets below ( to give further context ).
I will play around with this some more; My first guess is it may be how I set up the enabler or the common buffer.
EvtDeviceAdd
WDF_DMA_ENABLER_CONFIG dmaEnablerConfig;
WDF_DMA_ENABLER_CONFIG_INIT( &dmaEnablerConfig, WdfDmaProfilePacket64, 128 );
dmaEnablerConfig.EvtDmaEnablerFill = NULL;
dmaEnablerConfig.EvtDmaEnablerFlush = NULL;
dmaEnablerConfig.EvtDmaEnablerDisable = NULL;
dmaEnablerConfig.EvtDmaEnablerEnable = NULL;
dmaEnablerConfig.EvtDmaEnablerSelfManagedIoStart = NULL;
dmaEnablerConfig.EvtDmaEnablerSelfManagedIoStop = NULL;
dmaEnablerConfig.AddressWidthOverride = 0;
dmaEnablerConfig.WdmDmaVersionOverride = 3;
dmaEnablerConfig.Flags = WDF_DMA_ENABLER_CONFIG_REQUIRE_SINGLE_TRANSFER;
NTSTATUS status{ WdfDmaEnablerCreate( wdfDevice, &dmaEnablerConfig, WDF_NO_OBJECT_ATTRIBUTES, &( deviceContextP->myDmaEnabler ) ) };
if( NT_SUCCESS( status ) )
{
WDF_COMMON_BUFFER_CONFIG CommonBufferConfig;
WDF_COMMON_BUFFER_CONFIG_INIT( &CommonBufferConfig, FILE_128_BYTE_ALIGNMENT );
status = WdfCommonBufferCreateWithConfig( deviceContextP->myDmaEnabler,
deviceContextP->myCommonBufferByteSize,
&CommonBufferConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&( deviceContextP->myCommonBuffer ) );
if( NT_SUCCESS( status ) )
{
deviceContextP->virtualKernelAddr = WdfCommonBufferGetAlignedVirtualAddress( deviceContextP->myCommonBuffer );
deviceContextP->LogicalAddr = WdfCommonBufferGetAlignedLogicalAddress( deviceContextP->myCommonBuffer );
RtlZeroMemory( deviceContextP->virtualKernelAddr, deviceContextP->myCommonBufferByteSize );
deviceContextP->pMdl = IoAllocateMdl( deviceContextP->virtualKernelAddr,
( ULONG ) deviceContextP->myCommonBufferByteSize,
FALSE,
FALSE,
NULL );
if( NULL == deviceContextP->pMdl )
{
status = STATUS_INSUFFICIENT_RESOURCES;
TraceEvents( TRACE_LEVEL_ERROR, DBG_INIT, "IoAllocateMdl() failed with status=[%!STATUS!]", status );
}
else
{
MmBuildMdlForNonPagedPool( deviceContextP->mySystemMemoryChannelDataBuffer.pMdl );
}
}
else
{
TraceEvents( TRACE_LEVEL_ERROR, DBG_INIT, "WdfCommonBufferCreateWithConfig() failed with status=[%!STATUS!]", status );
}
}
else
{
TraceEvents( TRACE_LEVEL_ERROR, DBG_INIT, "WdfDmaEnablerCreate() failed with status=[%!STATUS!]", status );
}
EvtIoInCallerContext
if( ( NULL != deviceContextP->myCommonBuffer ) &&
( NULL == deviceContextP->virtualUserAddr ) )
{
__try
{
deviceContextP->virtualUserAddr = MmMapLockedPagesSpecifyCache( deviceContextP->pMdl,
UserMode,
MmCached,
NULL,
FALSE,
HighPagePriority );
if( NULL == deviceContextP->virtualUserAddr )
{
TraceEvents( TRACE_LEVEL_ERROR, DBG_IOCTLS, "MmMapLockedPagesSpecifyCache() failed.");
}
else
{
TraceEvents( TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "VirtualUserAddr=[0x%p]", deviceContextP->virtualUserAddr );
}
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
TraceEvents( TRACE_LEVEL_ERROR, DBG_IOCTLS, "MmMapLockedPagesSpecifyCache() threw an exception!]" );
}
}
WdfDeviceEnqueueRequest( device, request );
EvtIoDeviceControl - IOCTL_GET_DMA_USER_ADDRESS
if( NULL == deviceContextP->myCommonBuffer )
{
TraceEvents( TRACE_LEVEL_WARNING, DBG_IOCTLS, "NO COMMON BUFFER!!" );
}
else if( NULL == deviceContextP->virtualUserAddr )
{
TraceEvents( TRACE_LEVEL_WARNING, DBG_IOCTLS, "NO VIRTUAL ADDRESS" );
}
else
{
PDMA_USER_ADDRESS pDmaUserAddress{ nullptr };
status = WdfRequestRetrieveOutputBuffer( request, outputBufferLength, ( PVOID* ) &pDmaUserAddress, NULL );
if( NT_SUCCESS( status ) )
{
pDmaUserAddress->virtualAddr = reinterpret_cast<UINT64>( deviceContextP->virtualUserAddr );
bytesTransferred = sizeof( DMA_USER_ADDRESS );
}
else
{
TraceEvents( TRACE_LEVEL_ERROR, DBG_IOCTLS, "WdfRequestRetrieveOutputBuffer() failed with status=[%!STATUS!]", status );
}
}
...
...
WdfRequestCompleteWithInformation( request, status, bytesTransferred );
As always, thank you!
Juan