I am developing a KMDF PCIE driver , and there will be a DMA operation .
I find a demo , it allocates a continous physical memory for the hardware , and then map this area of memory into virtual address ,so the upper application program can write and read this memory directly avoiding data copy operation between the app and the dirver.
but code of the demo :
/**************************************************************************************************/
// Allocate The Buffer for DMA
// DWORD X 0x20 X MAXCount(1024) = 4 x 32 x 1024 = 128 K
DevExt->BufferSize = PCIE_BUFFER_SIZE ; // 16 M
DevExt->Buffer2Size = PCIE_BUFFER_SIZE ; // 16 M
physicalAddress.LowPart = 0x80000000;
physicalAddress.HighPart = 0;
//contiguous, nonpaged physical memory
DevExt->BufferLogicalAddress = MmAllocateContiguousMemory( DevExt->BufferSize , physicalAddress );
DevExt->Buffer2LogicalAddress = MmAllocateContiguousMemory( DevExt->Buffer2Size , physicalAddress );
if ( DevExt->BufferLogicalAddress )
{
//The MmGetPhysicalAddress routine returns the physical address corresponding to a valid nonpaged virtual address
physicalAddress = MmGetPhysicalAddress( (PVOID)DevExt->BufferLogicalAddress ) ;
DevExt->BufferPhysicalAddress = ( PUCHAR )physicalAddress.LowPart;
KdPrint((“PCIE: Alloc Physical Buffer OK!”));
}
else
{
KdPrint((“PCIE: Alloc Physical Buffer FAILED!”));
}
if ( DevExt->Buffer2LogicalAddress )
{
physicalAddress = MmGetPhysicalAddress( (PVOID)DevExt->Buffer2LogicalAddress );
DevExt->Buffer2PhysicalAddress = ( PUCHAR )physicalAddress.LowPart;
KdPrint((“PCIE: Alloc Physical Buffer 2 OK!”));
}
else
{
KdPrint((“PCIE: Alloc Physical Buffer 2 FAILED!”));
}
/****************************************************************************************************/
case IOCTL_GET_BUFFERADDRESS:
{
// SIZE_T length
if (OutputBufferLength != sizeof(ULONG) * 6)
{
status = STATUS_INVALID_PARAMETER;
length = 0;
KdPrint((“Length: %d”, OutputBufferLength));
break;
}
//---------------------------------------------------------------------------------------------------------
// buffer
KdPrint((“PHYADDRESS : 0X%08X”, devExt->BufferPhysicalAddress));
KdPrint((“LogicalADDRESS: 0X%08X”, devExt->BufferLogicalAddress));
phyAddress.HighPart = 0;
phyAddress.LowPart = (ULONG)devExt->BufferPhysicalAddress;
devExt->BufferSystemVirtualAddress = MmMapIoSpace( phyAddress ,
PCIE_BUFFER_SIZE,
MmNonCached ) ;
//
devExt->BufferMdl = IoAllocateMdl( devExt->BufferSystemVirtualAddress ,
PCIE_BUFFER_SIZE ,
FALSE ,
FALSE ,
NULL ) ;
//
//
//MmBuildMdlForNonPagedPool updates the MDL to describe the underlying physical pages
MmBuildMdlForNonPagedPool( devExt->BufferMdl ) ;
devExt->BufferUserVirtualAddress = (PVOID)( ( (ULONG)PAGE_ALIGN( MmMapLockedPages( devExt->BufferMdl , UserMode ) ) )
- MmGetMdlByteOffset( devExt->BufferMdl ) ) ;
KdPrint((“SystemVirtualAddress: 0x%08X”, devExt->BufferSystemVirtualAddress));
KdPrint((“UserVirtualAddress: 0x%08X”, devExt->BufferUserVirtualAddress));
//---------------------------------------------------------------------------------------------------------
// buffer2
KdPrint((“PHYADDRESS2 : 0X%08X”, devExt->Buffer2PhysicalAddress));
KdPrint((“LogicalADDRESS2: 0X%08X”, devExt->Buffer2LogicalAddress));
phyAddress.HighPart = 0;
phyAddress.LowPart = (ULONG)devExt->Buffer2PhysicalAddress;
devExt->Buffer2SystemVirtualAddress = MmMapIoSpace(phyAddress, PCIE_BUFFER_SIZE, MmNonCached);
devExt->Buffer2Mdl = IoAllocateMdl(devExt->Buffer2SystemVirtualAddress, PCIE_BUFFER_SIZE, FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(devExt->Buffer2Mdl);
devExt->Buffer2UserVirtualAddress = (PVOID)(((ULONG)PAGE_ALIGN(MmMapLockedPages(devExt->Buffer2Mdl, UserMode))) + MmGetMdlByteOffset(devExt->Buffer2Mdl));
KdPrint((“SystemVirtualAddress2: 0x%08X”, devExt->Buffer2SystemVirtualAddress));
KdPrint((“UserVirtualAddress2: 0x%08X”, devExt->Buffer2UserVirtualAddress));
//---------------------------------------------------------------------------------------------------------
*(PULONG)outBuffer = (ULONG)devExt->BufferUserVirtualAddress;
*(PULONG)((PUCHAR)outBuffer + sizeof(ULONG)) = (ULONG)devExt->BufferPhysicalAddress;
*(PULONG)((PUCHAR)outBuffer + sizeof(ULONG) * 2) = PCIE_BUFFER_SIZE;
*(PULONG)((PUCHAR)outBuffer + sizeof(ULONG) * 3) = (ULONG)devExt->Buffer2UserVirtualAddress;
*(PULONG)((PUCHAR)outBuffer + sizeof(ULONG) * 4) = (ULONG)devExt->Buffer2PhysicalAddress;
*(PULONG)((PUCHAR)outBuffer + sizeof(ULONG) * 5) = PCIE_BUFFER_SIZE;
status = STATUS_SUCCESS;
length = sizeof(ULONG) * 6;
break ;
/******************************************************************/
From the msnd :
The MmMapLockedPages routine is obsolete for Windows 2000 and later versions of Windows, and for Windows Me. It is supported only for WDM drivers that must run on Windows 98. Otherwise, use MmMapLockedPagesSpecifyCache.
and when I use this code in my project , the buffer ONE can be run ok , but the buffer TWO fail , I use windows 7 x64 and WDK 7600
But I appreciate its method , I want to know how to realize this method through the WDF ( KMDF ) style .