Phys --> User memory mapping under XP

Hi All,

I have a PCI hardware for video editing with memory on it. I map the pysical
memory address to a user mode address in order to perform unbuffered disk
I/O from/to the hardware memory (SCSI controller directly DMAs to hardware).

I’m using the following (simplified) code to perform the mapping:

PVOID MapPhysToUser(PVOID pPhys, DWORD dwLen, DWORD Flags)
{
PHYSICAL_ADDRESS pa;
PVOID pKern,pUser,pTmp;
PMDL pMDL;

pa.LowPart = (DWORD)pPhys;
pa.HighPart = 0;
pKern = MmMapIoSpace(pa, dwLen, (Flags & HLP_F_CachPages)!=0);
pMDL = IoAllocateMdl(pKern, dwLen, FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(pMDL);
pTmp = MmMapLockedPages(pMDL, UserMode);
pUser = (PVOID)(((ULONG)PAGE_ALIGN(pTmp)) + MmGetMdlByteOffset(pMDL));
return pUser;
}

I do this in a legacy NT driver and this worked fine under NT4 and W2K. Under XP the mapping also works ok and the memory is accessible via CPU. But when the SCSI controller tries to write to that memory, it always crashes in the kernel - not for the first page, but somewhere. Same behaviour with XP SP1. Please see the trace below.

Is this a known problem?

Thanks,
Günter Bögel
Pinnacle, Germany

*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

IRQL_NOT_LESS_OR_EQUAL (a)
An attempt was made to access a pagable (or completely invalid) address at an
interrupt request level (IRQL) that is too high. This is usually
caused by drivers using improper addresses.
If a kernel debugger is available get the stack backtrace.
Arguments:
Arg1: 820efecc, memory referenced
Arg2: 00000002, IRQL
Arg3: 00000000, value 0 = read operation, 1 = write operation
Arg4: 804d624f, address which re
ferenced memory

Debugging Details:

READ_ADDRESS: 820efecc Nonpaged pool

CURRENT_IRQL: 2

FAULTING_IP:
nt!MmMapLockedPagesSpecifyCache+188
804d624f 8b460c mov eax,[esi+0xc]

DEFAULT_BUCKET_ID: DRIVER_FAULT

BUGCHECK_STR: A

TRAP_FRAME: f31c93dc – (.trap fffffffff31c93dc)
ErrCode = 00000000
eax=00293dd8 ebx=00000963 ecx=80c51000 edx=2d83009d esi=820efec0
edi=81962008
eip=804d624f esp=f31c9450 ebp=f31c946c iopl=0 nv up ei pl zr na po
nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000
efl=00010246
nt!MmMapLockedPagesSpecifyCache+188:
804d624f 8b460c mov eax,[esi+0xc]
Resetting default context

LAST_CONTROL_TRANSFER: from f84a7ebd to 804d624f

STACK_TEXT:
f31c946c f84a7ebd 81962024 1f000000 c03e0408
nt!MmMapLockedPagesSpecifyCache+0x188
f31c94a8 806bd1e8 81f9ea30 81f53e70 00000000
SCSIPORT!SpBuildScatterGather+0x1e5
f31c94d4 80510d17 81f9fd78 81f9ea64 0000000b
hal!HalAllocateAdapterChannel+0x124
f31c94ec f84a82ab 81f9fd78 81f9ea30 0000000b
nt!IoAllocateAdapterChannel+0x28
f31c9524 804d32e7 81f9ea30 81f53e70 81f9eae8 SCSIPORT!ScsiPortStartIo+0x255
f31c9544 804d3337 81f9ea30 81f53e70 00000000 nt!IopStartPacket+0x9f
f31c9564 f84a7970 81f9ea30 81f53e70 00000000 nt!IoStartPacket+0x88
f31c9598 f84a65cd 81f9ea30 00f53f04 81f66874
SCSIPORT!ScsiPortFdoDispatch+0x26c
f31c95b0 f84a9918 81f7f0e8 81f53e70 81f53f04 SCSIPORT!SpDispatchRequest+0x65
f31c95cc f84a5450 81f7f030 81f53e70 81f9ff38 SCSIPORT!ScsiPortPdoScsi+0xea
f31c95dc 804d607d 81f7f030 81f53e70 81f667c8
SCSIPORT!ScsiPortGlobalDispatch+0x1a
f31c95ec f85c5cf1 05d10800 8195d008 00000000 nt!IopfCallDriver+0x31
f31c95fc f85c5bb2 81f667c8 81f6e930 8195d09c
CLASSPNP!SubmitTransferPacket+0x7e
f31c9628 f85c60b3 0000a000 0000a000 8194d440
CLASSPNP!ServiceTransferRequest+0xe0
f31c964c 804d607d 81f6e878 00000000 81fd3b90 CLASSPNP!ClassReadWrite+0xfd
f31c965c f87bd36c 00000000 8195d0c0 f31c96c8 nt!IopfCallDriver+0x31
f31c966c 804d607d 81f6e598 8195d008 8195d008 PartMgr!PmReadWrite+0x93
f31c967c f84d2bfe 81f668c0 81941818 81fd2d68 nt!IopfCallDriver+0x31
f31c96c8 f84e92f1 81941818 00f668c0 00000000 dmio!voldiskiostart+0x430
f31c9718 f84db7f3 81941818 f31c9770 f31c9764 dmio!vol_subdisksio_start+0x105
f31c9788 f84d3ef3 8193e508 00000001 00000001 dmio!volkiostart+0x32b
f31c97b4 f84d592d 81fa5340 8194d440 81fa7b28 dmio!volrdwr+0xa9
f31c97c4 804d607d 81fa5340 8194d440 8194d538 dmio!volwrite+0x57
f31c97d4 f8585a4b 8194d400 81c24100 81fd3a98 nt!IopfCallDriver+0x31
f31c97e8 804d607d 81f0a658 8194d440 8194d440 VolSnap!VolSnapWrite+0xb9
f31c97f8 f833f6b8 81aacd60 8194d440 f31c99e0 nt!IopfCallDriver+0x31
f31c9808 f833f98d 81aacd60 81f0a5a0 a1586000 Ntfs!NtfsSingleAsync+0x6b
f31c99e0 f833ecf5 81aacd60 8194d440 e23520d0 Ntfs!NtfsNonCachedIo+0x363
f31c9bd8 f833f4e7 81aacd60 8194d440 8194d440 Ntfs!NtfsCommonWrite+0x1970
f31c9c3c 804d607d 81c24020 8194d440 81f57948 Ntfs!NtfsFsdWrite+0xf3
f31c9c4c f84933b8 81968bd0 8194d440 f31c9c94 nt!IopfCallDriver+0x31
f31c9c5c 804d607d 81c22020 e1091120 81aa92c0 sr!SrWrite+0xa8
f31c9c6c f8875668 804d607d 81b2f368 8194d440 nt!IopfCallDriver+0x31
WARNING: Stack unwind information not available. Following frames may be
wrong.
f31c9c94 80554621 81b2f368 8194d440 8193da70 TmPreFlt!TmpSetFilterNet+0x11a
f31c9d38 804fa334 000000b0 000000ac 00000000 nt!NtWriteFile+0x5b5
f31c9d38 7ffe0304 000000b0 000000ac 00000000 nt!KiSystemService+0xc9
0012e9d4 00000000 00000000 00000000 00000000
SharedUserData!SystemCallStub+0x4

FOLLOWUP_IP:
CLASSPNP!SubmitTransferPacket+7e
f85c5cf1 5f pop edi

FOLLOWUP_NAME: MachineOwner

SYMBOL_NAME: CLASSPNP!SubmitTransferPacket+7e

MODULE_NAME: CLASSPNP

IMAGE_NAME: CLASSPNP

STACK_COMMAND: .trap fffffffff31c93dc ; kb

BUCKET_ID: 0xA_CLASSPNP!SubmitTransferPacket+7e

Some little observations:

  1. The DDK reads:

" For Windows NT 4.0 SP3 and earlier versions, MmMapLockedPages returns the
base virtual address (a page-aligned address) that maps the locked pages for
the range described by the MDL. For versions later than Windows NT 4.0 SP3,
MmMapLockedPages returns the actual virtual address (page-aligned address
with offset). "
Pay attention at “with offset”.

  1. That memory IS in user mode , so be extra carefull at any attempt to use
    it. I dont know how exactly you attempt to access the user mode mapping, but
    be sure is legal how you doit.

  2. Always use __try / __except when calling MmMapLockedPages with
    AccessMode set to user mode. In this case , this API can raise exceptions to
    indicate the exact reason for failure.

  3. Is wise to always validate the results. For example

pMdl = IoAllocateMdl()

if (!pMdl) goodbye;

  1. Watch out for cache parameters always. XP Mm was imporved , and it
    considers illegal to have 2 or more memory mappings with conflicting cache
    attributtes. MmMapLockedPages always assumes that the memory it tryes to map
    is cached.

Dan,

thanks for your hints:

  1. Right, this should be covered by the expression
    pUser = (PVOID)(((ULONG)PAGE_ALIGN(pTmp)) + MmGetMdlByteOffset(pMDL));

  2. I hand this address to user mode and use it there in a call to
    WriteFile()

  3. Ok. But the mapping itself works fine. I can access the memory via CPU
    with no problems. Only the SCSI driver crashes when using this memory, as
    visible in the crash dump.

  4. I do that. I just removed all this to make the code easier to read.

  5. Right, I also ran into this problem and found the answer in Hector’s
    Memos to Developers!

Günter

“Dan Partelly” wrote in message news:xxxxx@ntdev…
>
> Some little observations:
>
> 1. The DDK reads:
>
> " For Windows NT 4.0 SP3 and earlier versions, MmMapLockedPages returns
the
> base virtual address (a page-aligned address) that maps the locked pages
for
> the range described by the MDL. For versions later than Windows NT 4.0
SP3,
> MmMapLockedPages returns the actual virtual address (page-aligned address
> with offset). "
> Pay attention at “with offset”.
>
> 2. That memory IS in user mode , so be extra carefull at any attempt to
use
> it. I dont know how exactly you attempt to access the user mode mapping,
but
> be sure is legal how you doit.
>
> 3. Always use try / except when calling MmMapLockedPages with
> AccessMode set to user mode. In this case , this API can raise exceptions
to
> indicate the exact reason for failure.
>
> 4. Is wise to always validate the results. For example
>
>
>
> pMdl = IoAllocateMdl()
>
> if (!pMdl) goodbye;
>
> 5. Watch out for cache parameters always. XP Mm was imporved , and it
> considers illegal to have 2 or more memory mappings with conflicting cache
> attributtes. MmMapLockedPages always assumes that the memory it tryes to
map
> is cached.
>
>
>
>
>
>
>
>
>
>
>