KMDF extra probe and lock required on embedded pointer

I am doing something that should be simple.

  1. In user space there is a structure that has an embedded pointer. This is a READ where the hardware will write data into the buffer for the user.
  2. An IOCTL is used to pass the structure to a driver. The IOCTL is BUFFERED, but i don’t think that matters in this case.
  3. The IoEvtUserContext is catching the IOCTL and doing a “wdf … probeandlock… for write…” call … successfully., There is a unique CONTEXT block bound to the request that carries the pointer returned from the probe and lock to the device control event handler.
  4. the IOCTL is handled as normal.
  5. An Mdl is created from the extracted pointer. …that succeeds.
  6. A request is synchonously posted to some firewire gizmo. … that succeeds
  7. The buffer is not correct when the call returns. The user does not see the correct data. of course that succeeds.

More background.
I know the gizmo works because I also have a much simpler “READ” interface thru the IoEvtRead handler. It works.
If I probe and lock after the Mdl is created above (step 5) and unlock prior to return, it works.
If I use the MmGetSystemAddressForMdlSafe (without the probe and lock), I get an address whereby I can see the data from my kernel driver, but the user program still can not.
I don’t mind using the extra probe and lock, but the “in user context” one is supposed to do the trick…
Thanks!

>If I probe and lock after the Mdl is created above (step 5) and unlock

prior to return, it works.

How are you building the MDL if you don’t probe and lock it? Are you just
allocating the memory with IoAllocateMdl? Or are you saying that you use
MmBuildMdlForNonPagedPool?

This sounds overly complicated though, you’re essentially building two MDLs
(one internally in WdfRequestProbe and one when you build your own). Any
reason that you can’t just build the one MDL in your in caller context and
pass that as part of your context?

-scott


Scott Noone
Consulting Associate and Chief System Problem Analyst
OSR Open Systems Resources, Inc.
http://www.osronline.com

well said… way more complex than I would have liked it to be.

This is my second venture into KMDF and I am expecting that there is something happening for me that I am not taking advantage of- - or simply missed something.

The Mdl is getting build from a pointer derived from the InCallerContext pinned memory object representing the user buffer reference. The sequence is:
@InCallerContext

  • get my IOCTL structure that has the user pointer embedded within using WdfRequestRetrieveInputBuffer
  • pin my user buffer from the reference (bufffer will be used as a READ) using WdfRequestProbeAndLockUserBufferForWrite. (base structure passed is good data)
  • put the returned Memory obect that references the bufferpointer into a created context that is attached to the Request. (just like they say i should in the docs)(And that should do the business)

@InDeviceIoControl

  • get the pinned pointer memory object from the context object associated with the Request
  • get the buffer from the memory object
    QUESTION - can I get the Mdl directly from the memory object so i don’t have to allocate the mdl?
  • IoAllocateMdl on the buffer.
    – I should not have to do this, but it only works this way…
    – Probeandlockpages over the Mdl
  • pass the Mdl along to the firewire stack (synchronous call to ASYNC_READ)

– I should not have to do this, but it only works this way…
– MmFreePages

  • IoFreeMdl on return.

If I don’t do the extra probe and lock and free, the memory is not correct coming back from the hardware. If I use the more simple “IoEvtRead” path where the user buffer is already pinned and set, then it simply works – no extra pinnings.

If I Call a “get unsafe user buffer mdl” call, I can see the data in kernel space, but the buffer is not coherent in user space.

My IOCTL is “buffered”, but my understanding is that this only means the structure I am passing. The “right way” to do this – i think – is to have the data block below the structure so that it can get pulled in along with the structure I am passing down to the IOCTL.
typedef struct _goo { int foo; int bar; char data[1]; } goo;

The ASYNC_WRITE path works without issue using the “InCallerContext” probe and lock of the “read” buffer.

Thanks!

>The sequence is:

@InCallerContext

This all looks OK to me.

@InDeviceIoControl

  • get the pinned pointer memory object from the context object associated
    with the Request
  • get the buffer from the memory object
    QUESTION - can I get the Mdl directly from the memory object so i don’t
    have to allocate the mdl?

I don’t see an API that will easily grab this for you, maybe there’s some
way you can though an someone else will chime in.

  • IoAllocateMdl on the buffer.
    – I should not have to do this, but it only works this way…
    – Probeandlockpages over the Mdl

Aha! That’s it! Yes, you absolutely have to do something other than just
allocate the MDL structure. When you create an MDL, you do two steps:

  1. Allocate enough space for the MDL structure. The MDL structure is
    variable length, a fixed portion at the beginning and a variable length tail
    that has one entry per-page of memory that the allocation consumes. All
    IoAllocateMdl does is allocate enough space for the structure and initialize
    the fixed portion.

  2. Populate the variable length tail with the actual physical pages of the
    allocation. This is what MmProbeAndLockPages does.

Without doing step #2, you’re doing DMA to whatever pages the garbage at the
end of the MDL structure point to. I’m surprised you haven’t experienced a
fiery death yet.

As an optimization here, you could actually call MmBuildMdlForNonPagedPool
instead of MmProbeAndLockPages. Sounds strange, yes, but the API is poorly
named. It should really be, “MmBuildMdlForNonPageableMemory”. You’re
basically saying that the memory is already guaranteed to be resident for
the lifetime of the MDL and that it doesn’t need to be probed for access, so
the memory manager can shortcut a lot of processing and just fill in the
tail of the MDL with the physical page numbers.

That should fix your current design. However, I still think that you have
created an extra step by being good and using the KMDF APIs.

The easiest thing to do is to build your MDL as part of your in caller
context callback. So, extract the pointer from the system buffer and do:

IoAllocateMdl()
MmProbeAndLockPages()
MmGetSystemAddressForMdlSafe() - this is optional, only if you need a kernel
virtual address to the buffer

Then stuff the MDL someplace. Then in InDeviceIoControl, pass the MDL to
your hardware. When you’re done, MmUnlockPages and IoFreeMdl.

This is essentially what WdfProbe is doing for you, so you’re just
duplicating the work.

-scott


Scott Noone
Consulting Associate and Chief System Problem Analyst
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntdev…

well said… way more complex than I would have liked it to be.

This is my second venture into KMDF and I am expecting that there is
something happening for me that I am not taking advantage of- - or simply
missed something.

The Mdl is getting build from a pointer derived from the InCallerContext
pinned memory object representing the user buffer reference. The sequence
is:
@InCallerContext

  • get my IOCTL structure that has the user pointer embedded within using
    WdfRequestRetrieveInputBuffer
  • pin my user buffer from the reference (bufffer will be used as a READ)
    using WdfRequestProbeAndLockUserBufferForWrite. (base structure passed is
    good data)
  • put the returned Memory obect that references the bufferpointer into a
    created context that is attached to the Request. (just like they say i
    should in the docs)(And that should do the business)

@InDeviceIoControl

  • get the pinned pointer memory object from the context object associated
    with the Request
  • get the buffer from the memory object
    QUESTION - can I get the Mdl directly from the memory object so i don’t have
    to allocate the mdl?
  • IoAllocateMdl on the buffer.
    – I should not have to do this, but it only works this way…
    – Probeandlockpages over the Mdl
  • pass the Mdl along to the firewire stack (synchronous call to ASYNC_READ)

– I should not have to do this, but it only works this way…
– MmFreePages

  • IoFreeMdl on return.

If I don’t do the extra probe and lock and free, the memory is not correct
coming back from the hardware. If I use the more simple “IoEvtRead” path
where the user buffer is already pinned and set, then it simply works – no
extra pinnings.

If I Call a “get unsafe user buffer mdl” call, I can see the data in kernel
space, but the buffer is not coherent in user space.

My IOCTL is “buffered”, but my understanding is that this only means the
structure I am passing. The “right way” to do this – i think – is to have
the data block below the structure so that it can get pulled in along with
the structure I am passing down to the IOCTL.
typedef struct _goo { int foo; int bar; char data[1]; } goo;

The ASYNC_WRITE path works without issue using the “InCallerContext” probe
and lock of the “read” buffer.

Thanks!

> As an optimization here, you could actually call MmBuildMdlForNonPagedPool

instead of MmProbeAndLockPages. Sounds strange, yes, but the API is poorly
named. It should really be, “MmBuildMdlForNonPageableMemory”.

Yes.

And the third way to populate the MDL is IoBuildPartialMdl (slave side, the master must be already populated).

And the fourth way is MmAllocatePagesForMdl.


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

Thanks guys!

That makes absolute sense… I thought IoAllocateMdl took care of the SG at the tail for me.
I guess until there is another call in KMDF to create an mdl from the probed list I will resort to the old ways.

Scott’s intuition sounds right. The InUserContext callback has the base address of the user buffer as well as all the page info for the rest of the buffer. When I pop out of that context and try to make an MDL, the addresses wouldn’t make sense.

I tried to make this work last night from the IoEvtControl context (my kernel driver context) and it still did not with the IoAllocateMdl and MmBuildMdlforNonPageableMemory. I even added an extra buffer copy… (it “kindof worked”). Indications are that the addresses i am trying to get at aren’t right… or not wholly converted in the evtInUserContext callback.

so ? there is something else going on with respect to what is being used in the WdfRequestProbeAndLockUserBufferForWrite vs Read. Why is this call not doing what its expect it to? The docs even indicate that the probe and lock will create and MDL… that would be great. I am doing something wrong and don’t have insight into it.

(I am working firewire on windows 7 and don’t have a serial port for windbg - A breakpoint would be useful right now! )

Another point… the IOCTL is BUFFERED not DIRECT. Does that drive the Wdf call in different directions? within the InUserContext callback, the memory block that was allocated should be able to be locked in totality and correctly.

Ideally… is there an example of actually doing this sort of thing using WDF in the samples? NonPnp does not appear to have an embedded pointer example.

Thanks again!

>I tried to make this work last night from the IoEvtControl context (my

kernel driver context) and it still did not with the IoAllocateMdl >and
MmBuildMdlforNonPageableMemory

If you’re directly building the MDL using the user’s buffer in your in
caller context, you need to call MmProbeAndLockPages and NOT
MmBuildMdlForNonPagedPool. You’re building the MDL for the user’s buffer, so
you need to make sure that you probe it for access and lock it in memory.

In the case where you were building the MDL out of the pointer returned from
WdfProbeAndLock, the buffer was already probed and locked and you were
building an MDL to describe the kernel mapping of the MDL.

-scott


Scott Noone
Consulting Associate and Chief System Problem Analyst
OSR Open Systems Resources, Inc.
http://www.osronline.com

wrote in message news:xxxxx@ntdev…

Scott’s intuition sounds right. The InUserContext callback has the base
address of the user buffer as well as all the page info for the rest of the
buffer. When I pop out of that context and try to make an MDL, the addresses
wouldn’t make sense.

I tried to make this work last night from the IoEvtControl context (my
kernel driver context) and it still did not with the IoAllocateMdl and
MmBuildMdlforNonPageableMemory. I even added an extra buffer copy… (it
“kindof worked”). Indications are that the addresses i am trying to get at
aren’t right… or not wholly converted in the evtInUserContext callback.

so ? there is something else going on with respect to what is being used in
the WdfRequestProbeAndLockUserBufferForWrite vs Read. Why is this call not
doing what its expect it to? The docs even indicate that the probe and lock
will create and MDL… that would be great. I am doing something wrong and
don’t have insight into it.

(I am working firewire on windows 7 and don’t have a serial port for
windbg - A breakpoint would be useful right now! )

Another point… the IOCTL is BUFFERED not DIRECT. Does that drive the Wdf
call in different directions? within the InUserContext callback, the memory
block that was allocated should be able to be locked in totality and
correctly.

Ideally… is there an example of actually doing this sort of thing using WDF
in the samples? NonPnp does not appear to have an embedded pointer example.

Thanks again!