Passing parameters by reference from User Mode to Kernel Mode

I need to pass some values by reference (e.g. character strings, pointers
to structures) from my application (running in User Mode) to my driver
(running in Kernel Mode). I have a DLL (which runs in User Mode) that
provides the interface.

My understanding of NT Virtual Memory suggests that some part of the
application virtual memory space (the system space) can be guaranteed to
be visible to the driver. This is because this system space is shared by
all applications and so irrespective of which application is currently
“active”, data in the system space is common and always visible.

It would seem therefore that, when passing data by reference from an
application to its driver, the referenced data should appear in system
space. Whilst it might be possible for the application to locate the
referenced data in system space, or even for the DLL to copy the data to
system space, my understanding is that the preferred practice is to create
a virtual memory mapping that causes the reference data to be “mirrored”
into system space. This mapping would seem to be done in the DLL since the
referenced data is known to be visible in the application memory space at
this stage.

I was reasonably comfortable with this until I tried to implement the
mapping operation in the DLL.

My first worry was, if this is such a basic and common operation (passing
memory references from User Mode to Kernel Mode), why was I finding it so
hard to find specific details in my documentation.

And, secondly, such a mapping operation would appear to lie within the
jurisdiction of the HAL. Yet I want (need) to perform this mapping
operation in the DLL (i.e. User Mode) and significantly within the
“context” (i.e. the address space) of the application. I wasn’t aware that
I could communicate with the HAL from User Mode.

It would seem that I have got something wrong somewhere. Can someone point
out the incorrect assumption and further point me to some relevant
documentation (I have the OSR/Viscarola/Mason text and the DDK and a some
MSDN CDs).

There is mention of handling the memory references in the form of MDLs.
My understanding is that MDLs encapsulate the Physical Addresses of the
referenced memory, using an array of PFNs, which might enable the driver
to access the memory outside the context of the original application. I
can envisage that there may be functions that can perform mapping
operations on MDLs.
Unfortunately, I am unlikely to be able to coax the application writers to
use MDLs (the application code has been ported from another platform) and
any conversions that need to be done from pointers to MDLs will need to be
done by the DLL.

Thanks,
Richard


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

Thanks for your help, Max.

The best way of doing this is pass the strings to the driver in the
IOCTL
input buffer and let the driver return the new values in IOCTL output
buffer.
This would suggest that DeviceIoControl() performs the desired operation
of mapping the input and output buffers into System Space. That would make
a lot of sense.

However, I’m not sure that this will be enough in all cases. I think that
in some cases, I will need pass pointers, e.g. when a structure contains a
pointer to a string or when I need to reference non-contiguous lumps of
data. In this case, what would be the appropriate method to ensure that
the referenced data is suitably mapped, i.e. which OS calls are available
from the DLL to do this?

In other cases, the pointer will point to a buffer to be used for DMA
transfers. I am happy that I can do what is necessary in the driver to
perform the Busmaster DMA transfer, if I can represent the buffer as an
MDL. Can I create an MDL that represents the buffer from UserMode?

Any help is appreciated.

Thanks again,
Richard


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

> I need to pass some values by reference (e.g. character strings, pointers

to structures) from my application (running in User Mode) to my driver
(running in Kernel Mode). I have a DLL (which runs in User Mode) that
provides the interface.

The best way of doing this is pass the strings to the driver in the IOCTL
input buffer and let the driver return the new values in IOCTL output
buffer.
METHOD_BUFFERED seems to be the best way (both input and output buffers are
Irp->AssociatedIrp.SystemBuffer).

Don’t forget to fill Irp->IoStatus.Information with number of bytes returned
in the output buffer.

Max


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com

> Thanks for your help, Max.

> The best way of doing this is pass the strings to the driver in the
> IOCTL
> input buffer and let the driver return the new values in IOCTL output
> buffer.
This would suggest that DeviceIoControl() performs the desired operation
of mapping the input and output buffers into System Space. That would make

No. Declare IOCTL with METHOD_BUFFERED - and IO manager will do this for
you.
It will allocate the temporary system space buffer to
Irp->AssociatedIrp.SystemBuffer and copy the user buffer there. You must not
ever touch the user buffer if you use METHOD_BUFFERED.

However, I’m not sure that this will be enough in all cases. I think that
in some cases, I will need pass pointers, e.g. when a structure contains a
pointer to a string or when I need to reference non-contiguous lumps of
data.

Bad idea. A good idea is to make the IOCTL buffer layout self-relative -
having no pointers outside it. Embed all strings to the buffer at the
structure tail, for instance.

In this case, what would be the appropriate method to ensure that

the referenced data is suitably mapped, i.e. which OS calls are available
from the DLL to do this?

If you really want to do this highly unrecommended thing:

  • use __try/__catch in all code which touches the user buffers
  • never touch them from IRQL > PASSIVE_LEVEL
  • be sure that you touch your buffers only in the correct process context.

In other cases, the pointer will point to a buffer to be used for DMA
transfers. I am happy that I can do what is necessary in the driver to
perform the Busmaster DMA transfer, if I can represent the buffer as an
MDL. Can I create an MDL that represents the buffer from UserMode?

In this cases, use METHOD_IN_DIRECT or METHOD_OUT_DIRECT.
The IO manager will create the MDL for you.

Max


You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com