IoAllocateMdl failed in 2003 server x64

Hi,ALL

I want to map PCI device base memory into Process Address Space in driver.
I used the following method.

  1. Get the translated physical address of the base memory.
    WdfCmResourceListGetDescriptor…

  2. Map the memory into nonpaged system address space as follows:
    SystemVirtualAddress = MmMapIoSpace(PhysicalAddress, SizeofMemory,CacheEnable);

  3. Allocate an Mdl:
    Mdl = IoAllocateMdl(SystemVirtualAddress, SizeOfMemory, FALSE, FALSE,NULL);

  4. Build the MDL to describe the memory pages:
    MmBuildMdlForNonPagedPool(Mdl);

  5. Map the memory into the process’s user-space using MmMapLockedPages.
    UserVirtualAddress = MmMapLockedPagesSpecifyCache(Mdl,UserMode,MmCached,NULL,FALSE,NormalPagePriority)

I found in XP x64 and 2003 sever x64,there comes problem:
The device’s base3 is 32MB,the third process “IoAllocateMdl” failed,return Mdl is NULL,
but other base is OK,and I can get the process address correctly.
And more strangely is that in 32 bit OS and vista x64 OS,
IoAllocateMdl never failed.

I found on WDK doc,it said the second parameter “Length”
“This value must be less than PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR).”
So maybe in XP x64 and 2003 sever x64,32MB is more than this value?

In this case,how can I map PCI device base memory into Process Address Space?
Allocate more than one MDLs for this base?
How can guarantee that these MDLs is continuous?

Any help is appreciated.Thanks.

Best Regards
Zhou ChengJun

in which KMDF callback are you calling MmMapLockedPagesSpecifyCache?

> In this case,how can I map PCI device base memory into Process Address Space?

Allocate more than one MDLs for this base?

Yes.

How can guarantee that these MDLs is continuous?

No ways.


Maxim S. Shatskih
Windows DDK MVP
xxxxx@storagecraft.com
http://www.storagecraft.com

Thanks two.

1

in which KMDF callback are you calling MmMapLockedPagesSpecifyCache?

I called MmMapLockedPagesSpecifyCache in driver’s queue-specific EvtIoDeviceControl callback function.

2

In this case,how can I map PCI device base memory into Process Address Space?
Allocate more than one MDLs for this base?

Yes.

How can guarantee that these MDLs is continuous?

No ways.

So it can not guarantee that these MDLs is continuous.
In this case, how to map PCI device base memory into Process Address Space?
I just want to access PCI device base memory in App.

Best Regards

> I found on WDK doc,it said the second parameter “Length”

“This value must be less than PAGE_SIZE * (65535 - sizeof(MDL)) /
sizeof(ULONG_PTR).”
So maybe in XP x64 and 2003 sever x64,32MB is more than this value?

In this case,how can I map PCI device base memory into Process Address
Space?

The size limit in IoAllocateMdl is mostly artificial anyways (which is why
it was removed in Vista). If you need an MDL that is larger than what
IoAllocateMdl supports, you can manually allocate an appropriately
sized buffer from the nonpaged pool and call MmInitializeMdl on it.
This is what IoAllocateMdl does internally.


Pavel Lebedinsky/Windows Kernel Test
This posting is provided “AS IS” with no warranties, and confers no rights.

is EvtIoDeviceControl assigned to a power managed queue? to guarantee that you are in the right process context when mapping, you should do the mapping in EvtIoInCallersContext

d

Thanks.

to guarantee that you
are in the right process context when mapping, you should do the mapping in
EvtIoInCallersContext

I tried call IoAllocateMdl in EvtIoInCallersContext, it still failed in 2003 server x64 OS when
base size is 32MB.

>If you need an MDL that is larger than what
IoAllocateMdl supports, you can manually allocate an appropriately
sized buffer from the nonpaged pool and call MmInitializeMdl on it.
This is what IoAllocateMdl does internally.

appropriately sized buffe?how calculated it?
As Pavel suggest,I used the following two function:

//0x2000000 32MB,I think this will be big enough
Mdl = MmAllocateContiguousMemorySpecifyCache(0x2000000, LowestAcceptableAddress, HighestPhysicalAddress, BoundaryAddressMultiple,
MmCached);
MmInitializeMdl(Mdl,SystemVirtualAddress,0x2000000);

to replace the original function:

Mdl = IoAllocateMdl(SystemVirtualAddress, 0x2000000, FALSE, FALSE,NULL);

In this case,driver can be installed,
But when I tried to access base memory in App,BSOD happened.
(Windows xp 32-bit system is OK,2003 server x64 have this case)

Can Pavel give me some more explanation of this point.

Thanks

>> If you need an MDL that is larger than what

> IoAllocateMdl supports, you can manually allocate an appropriately
> sized buffer from the nonpaged pool and call MmInitializeMdl on it.
> This is what IoAllocateMdl does internally.

appropriately sized buffe?how calculated it?

The required size is mentioned in MmInitializeMdl docs:

sizeof(MDL) + sizeof(PFN_NUMBER)*ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseVa,
Length)

As Pavel suggest,I used the following two function:

//0x2000000 32MB,I think this will be big enough
Mdl = MmAllocateContiguousMemorySpecifyCache(0x2000000,
LowestAcceptableAddress, HighestPhysicalAddress,
BoundaryAddressMultiple,
MmCached);

You should use ExAllocatePoolWithTag(NonPagedPool) with the size
mentioned above instead of MmAllocateContiguousMemorySpecifyCache.

But when I tried to access base memory in App,BSOD happened.
(Windows xp 32-bit system is OK,2003 server x64 have this case)

What’s the output of !analyze -v ?

>>The required size is mentioned in MmInitializeMdl docs:


Thanks.
I found BSOD was caused by another reason.

And I tried as Pavel suggest,
It is Ok now,I can an MDL that is larger than what
IoAllocateMdl supports in 2003 server x64 .

Best Regards