How to allocate continuous physical memory in KMDF

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 .

Your queue callback is not guaranteed to be called in the context if the calling application. Instead you must register an EvtIoInCallerContext callback and handle the mapping there

d

Bent from my phone


From: xxxxx@gmail.commailto:xxxxx
Sent: ?12/?17/?2013 1:57 AM
To: Windows System Software Devs Interest Listmailto:xxxxx
Subject: [ntdev] How to allocate continuous physical memory in KMDF

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 .


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx>

This looks like another of the cases Peter referred to, when someone feels
the need to re-invent DO_DIRECT_IO or METHOD_[IN OUT]_DIRECT because they
don’t understand them. Question to the OP: why do you think DMA involves
a copy to the user buffers? The DMA engine should be able to handle
scatter/gather, unless it was designed by someone more familiar with the
S100 bus. So where is the copy required? And do you actually have
numbers you can tell us about data rates and buffer sizes?
joe

Your queue callback is not guaranteed to be called in the context if the
calling application. Instead you must register an EvtIoInCallerContext
callback and handle the mapping there

d

Bent from my phone


From: xxxxx@gmail.commailto:xxxxx
> Sent: ý12/ý17/ý2013 1:57 AM
> To: Windows System Software Devs Interest Listmailto:xxxxx
> Subject: [ntdev] How to allocate continuous physical memory in KMDF
>
>
> 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 .
>
>
>
>
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>
> —
> NTDEV is sponsored by OSR
>
> Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
>
> OSR is HIRING!! See http://www.osr.com/careers
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx>

xxxxx@gmail.com wrote:

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.

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 .

What you’re describing here is called a “common buffer”. You would use
WdfCommonBufferCreate and his friends. That will return the physical
and kernel virtual address. From that, you can use
MmMapLockedPagesSpecifyCache to get a user-mode address (assuming you
are in the proper process context).


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

> DevExt->BufferLogicalAddress = MmAllocateContiguousMemory( DevExt->BufferSize ,

Why are you ever calling this in KMDF, which has a rich set of DMA objects which should be used?

Can you create a KMDF common buffer instead?


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

What I puzzled is that do all the buffer operation function is associated with the DMA ?

Can I manager the memory buffer purely ?

> What I puzzled is that do all the buffer operation function is associated with the DMA ?

Can I manager the memory buffer purely ?

Physical contiguous memory? and what is the need on this in the driver?

The driver only needs physical contiguous memory for DMA.

MmAllocateContiguousMemory and friends are provided if you want to implement or decorate the DMA adapter object.

And, if you do not need DMA, then you have MmAllocatePagesForMdl for huge allocations and the usual ExAllocatePoolWithTag for non-huge ones.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com