- Hello,
Long time ago I was advised here how to get the virtual address of a buffer allocated in a kernel driver.
The 32MB buffer is allocated successfully with the following code:
NTSTATUS AllocateContinuousPhysicalMemory(IN PDEVICE_EXTENSION devExt, int Channel, int BufferSize)
{
WDF_DMA_ENABLER_CONFIG dmaConfig;
NTSTATUS status;
//
// Configure the DMA object
//
WDF_DMA_ENABLER_CONFIG_INIT(&dmaConfig,
WdfDmaProfilePacket,
COMMON_BUFFER_SIZE);
status = WdfDmaEnablerCreate(devExt->Device,
&dmaConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&devExt->DmaEnabler[Channel]);
if (!NT_SUCCESS(status))
{
KdPrint(("WdfDmaEnblerCreate failed: %08X\n", status));
return status;
}
status = WdfCommonBufferCreate(devExt->DmaEnabler[Channel],
COMMON_BUFFER_SIZE,
WDF_NO_OBJECT_ATTRIBUTES,
&devExt->CommonBuffer[Channel]);
if (!NT_SUCCESS(status))
{
KdPrint(("WdfCommonBufferCreate failed: %08X\n", status));
return status;
}
devExt->KernelCommonBuffer[Channel] = WdfCommonBufferGetAlignedVirtualAddress(devExt->CommonBuffer[Channel]);
devExt->PhysicalKernelCommonBuffer[Channel] = WdfCommonBufferGetAlignedLogicalAddress(devExt->CommonBuffer[Channel]);
RtlFillMemory(devExt->KernelCommonBuffer[Channel], BufferSize, 0x0);
devExt->CommonBufferMdl[Channel] = IoAllocateMdl(devExt->KernelCommonBuffer[Channel], BufferSize, FALSE, FALSE, NULL);
if (!devExt->CommonBufferMdl)
{
KdPrint(("IoAllocateMdl failed.\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
MmBuildMdlForNonPagedPool(devExt->CommonBufferMdl[Channel]);
KdPrint(("Channel %d: PhysicalDataAddressLow=%08x\n", Channel, devExt->PhysicalKernelCommonBuffer[Channel].LowPart));
KdPrint(("Channel %d: PhysicalDataAddressHigh=%08x\n", Channel, devExt->PhysicalKernelCommonBuffer[Channel].HighPart));
return STATUS_SUCCESS;
}
I get the virtual address of the buffer with the following code:
VOID DeviceEvtIoInCallerContext(__in WDFDEVICE Device,
__in WDFREQUEST Request)
/*++
Routine Description:
Responds to EvtIoInCallerContext events from KMDF
It calls different functions to process different type of IOCTLs.
Arguments:
Device - handle to a WDF Device object
Request - handle to the incoming WDF Request object
Return Value:
VOID.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION devExt = NULL;
WDF_REQUEST_PARAMETERS requestParameters;
BOOLEAN processed = FALSE;
WdfRequestGetParameters(Request, &requestParameters);
devExt = PLxGetDeviceContext(Device);
// get the request parameters
WDF_REQUEST_PARAMETERS_INIT(&requestParameters);
WdfRequestGetParameters(Request, &requestParameters);
if (requestParameters.Type == WdfRequestTypeDeviceControl)
{
// 1. Requests that should be processed only in the context of the app's process
if (!processed)
{
processed = RequestDispatchToSequentialQueue(Device, Request, requestParameters);
}
if (!processed)
{
status = WdfDeviceEnqueueRequest(Device, Request);
if (!NT_SUCCESS(status))
{
KdPrint(("WdfDeviceEnqueueRequest failed\n"));
}
}
}
}
BOOLEAN
RequestDispatchToSequentialQueue(
__in WDFDEVICE Device,
__in WDFREQUEST Request,
__in WDF_REQUEST_PARAMETERS RequestParameters
)
/*++
Routine Description:
These requests can be processed in a non-serialized manner, most of them don’t need to access device.
Arguments:
Device - handle to a WDF Device object
Request - handle to the incoming WDF Request object
RequestParameters - request parameters
Return Value:
BOOLEAN - TRUE (request processed); FALSE (request is not processed in this function).
–*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_EXTENSION devExt = NULL;
ALLOCATE_COMMON_BUFFER *pAllocateRequest;
ALLOCATE_COMMON_BUFFER_REPLY *pAllocateReply;
size_t bytesReturned = 0;
void *pInBuffer;
void *pOutBuffer;
int Channel;
size_t Length;
//-->Legacy
MG_SETTING *pMgSettingsRequest;
MG_DESCRIPTOR *pMgDescriptorReply;
HANDLE EventHandle[N_CHANNELS];
MG_BOARD_STAT *pMgBoardStat;
//<--Legacy
ULONG IoControlCode = RequestParameters.Parameters.DeviceIoControl.IoControlCode;
devExt = PLxGetDeviceContext(Device);
KdPrint(("320: IoControlCode=0x%x\n", IoControlCode));
switch (IoControlCode)
{
case ALLOCATE_COMMON_BUFFER_CODE:
KdPrint(("PsGetCurrentProcessId=%x\n", PsGetCurrentProcessId()));
status = WdfRequestRetrieveInputBuffer(Request, sizeof(ALLOCATE_COMMON_BUFFER),
&pInBuffer, &Length);
pAllocateRequest = (ALLOCATE_COMMON_BUFFER *)pInBuffer;
Channel = pAllocateRequest->Channel;
status = WdfRequestRetrieveOutputBuffer(Request, sizeof(READ_WORD32_REPLY),
&pOutBuffer, &Length);
pAllocateReply = (ALLOCATE_COMMON_BUFFER_REPLY *)pOutBuffer;
bytesReturned = sizeof(ALLOCATE_COMMON_BUFFER_REPLY);
//Map common buffer to user space. This can be done only upon IOCTL request
__try
{
devExt->UserSpaceCommonBuffer[Channel] = MmMapLockedPagesSpecifyCache(devExt->CommonBufferMdl[Channel],
UserMode,
MmCached,
NULL,
FALSE,
NormalPagePriority);
if (!devExt->UserSpaceCommonBuffer)
{
KdPrint(("MmMapLockedPagesSpecifyCache failed.\n"));
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
devExt->UserSpaceCommonBuffer[Channel] = NULL;
KdPrint(("MmMapLockedPagesSpecifyCache caused exception: %x\n", GetExceptionCode()));
}
pAllocateReply->VirtualAddress = (UINT64)devExt->UserSpaceCommonBuffer[Channel];
WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, bytesReturned);
break;
}
return TRUE;
}
**Problem **: under win10 (or server 2016) , Sometimes, after sending the IOCTL to get back the virtual address, the application hangs.
Same code after PC restart works well, and after few times the application runs, it hangs again.
On another PC running windows 7 embedded, the code runs OK without any hang.
Of course, for win10, the driver code was compiled for win10.
Thank you,
Zvika