HOWTO: Share Memory Between User Mode and Kernel Mode
ID: Q191840
|
The information in this article applies to:
-
Microsoft Win32 Device Driver Kit (DDK) for Windows NT, versions 3.1, 3.5, 3.51, 4.0
-
Microsoft Windows 2000
This article discusses a Beta release of a Microsoft
product. The information in this article is provided as-is
and is subject to change without notice.
No formal product support is available from Microsoft for
this Beta product. For information about obtaining support
for a Beta release, please see the documentation included
with the Beta product files, or check the Web location
from which you downloaded the release.
SUMMARY
This articles discusses three possible methods for sharing memory between
user mode and kernel mode, depending on whether the memory buffer is
allocated by an application or by a device driver.
MORE INFORMATION
IOCTL Method: Application Allocates Shared Memory
The easiest and best way to share memory between user mode and kernel mode
is to use IOCTLs. Of the four different types, the following three IOCTLs
enable you to access the user buffer directly in a device driver:
- METHOD_IN_DIRECT
- METHOD_OUT_DIRECT
- METHOD_NEITHER
No intermediate system buffer is created in any of these methods.
METHOD_IN_DIRECT and METHOD_OUT_DIRECT automatically lock the user-
specified buffer in DeviceIoControl and create a memory descriptor list
(MDL) for the driver. The driver can get a system address from the MDL and
transfer information in and out of the buffer, depending on the IOCTL
transfer type. This is a simple, clean approach because all buffer
validation, locking, and MDL creation is done by the I/O manager.
In contrast, METHOD_NEITHER directly provides the user buffers to the
driver, and the driver must validate and lock the buffer appropriately and,
if needed, get a system address for the buffer. Even though this is the
fastest path through the I/O subsystem for a device driver, there are
several cautions you should take when using this method. For additional
information, please see the following article in the Microsoft Knowledge
Base:
Q12646
Cautions on Using METHOD_NEITHER IOCTL
To understand how these three different IOCTLs work, please see the
following article in the Microsoft Knowledge Base:
Q178317
FILE: IOCTL.exe: How to Use Various Types of IOCTL
MmMapLockedPages Method: Device Driver Allocates Shared Memory
In this method, the driver allocates memory using the
MmAllocateContiguousMemory or ExAllocatePoolXxx function, and it maps the
memory in the user process address space using MmMapLockedPages. The driver
should create and build an MDL that describes the buffer before mapping
into the user process address space. The user application can use the
virtual address returned by MmMapLockPages to access the system memory
directly.
Because the mapping should be done while running in the context of the
process by which the memory is accessed, this can be done only in a
monolithic driver where the dispatch routine is guaranteed to run in the
calling process context. You can map the same system buffer in any number
of user processes address spaces. However, you should devise a protection
mechanism to synchronize access to the memory by the driver and all the
applications. Further, the buffer should be unmapped in the context of the
same process in which it is mapped before the termination of the process or
as soon as the usage of the buffer is over. Here is an outline of the steps
you need to take to map a driver buffer into a user process:
- First allocate the memory as follows:
SystemVirtualAddress = MmAllocateContiguousMemory(NumberOfBytes,
HighestAcceptableAddress); or
SystemVirtualAddress = ExAllocatePool(PoolType, NumberOfBytes);
- Allocate an MDL as follows:
Mdl = IoAllocateMdl(SystemVirtualAddress, NumberOfBytes, FALSE,
FALSE, NULL);
- Build the MDL to describe the memory pages. If you have allocated memory
from a non-paged pool, use the following:
MmBuildMdlForNonPagedPool(Mdl);
Otherwise, use:
MmProbeAndLockPages(Mdl);
- Map the locked pages into process's user address space as follows:
UserVirtualAddress = MmMapLockedPages(Mdl, UserMode);
The first three steps can be done in either DriverEntry or DispatchRoutine.
However, the last step of mapping the buffer into the user address space
should be done in a routine that runs in the context of the calling process
(typically, this is the dispatch routine of a monolithic driver).
You can use SystemVirtualAddress in the driver at a raised IRQL level and
in any process context, namely, interrupt service routine (ISR) and
deferred procedure call (DPC), and the UserVirtualAddress in the
application or even in the driver while running in the right process
context.
To unmap and free the buffer, do the following:
- First unlock the pages. You should call this function while running in
the context of process in which you got UserVirtualAddress:
MmUnmapLockedPages(UserVirtualAddress, Mdl);
- Free the MDL:
IoFreeMdl(Mdl);
- Free the system memory:
MmFreeContiguousMemory(SystemVirtualAddress); or
ExFreePool(SystemVirtualAddress);
Shared Memory Object Method
A memory-mapped file backed by the paging file is a common technique used
for sharing memory among user processes. However, you can use the same
technique to share memory between user processes and a device driver. There
are two approaches to this technique. In the first method, a driver can
create a named memory object (called a section object) and one or more user
applications can open the same object by using OpenFileMapping and then
calling the MapViewOfFile function to get a pointer to a section or all of
the shared memory. By specifying protection attributes to the section
object, you can define the manner in which a process can manipulate the
memory.
In the second method, an application can create a named memory object in
user mode with CreateFileMapping. A driver can open the same memory object
by using ZwOpenSection function and calling ZwMapViewOfSection to get a
pointer to it. You should always access this memory address in kernel mode
with an exception handler. For a sample that demonstrates this technique,
please see the following article in the Microsoft Knowledge Base:
Q194945
SAMPLE: Section.exe On Sharing Memory Between Kernel & User Mode
Because the object is always mapped in the user address space (below
0x80000000) of a process (regardless of whether the object is created in
kernel mode or user mode) the address is valid only if it is accessed in
the context of the process. Every call to MapViewOfFile or
ZwMapViewOfSection on the same memory object would return a different
memory address even for the same process. This method is not recommended
and is used least by low-level device drivers because, as explained
earlier, the scope of the address is limited to the process in which the
object is mapped, and it cannot be accessed in a DPC or ISR. Also, the API
to create a memory object in kernel mode is not documented in the DDK.
However, to use the address at raised IRQL, such as in DPC or ISR, you have
to probe and lock the buffer pages and get a system virtual address
(MmGetSystemAddressForMdl) as described in the IOCTL method.
This method is simple and easy only if the memory is going to be shared
between two or more user processes and one or more device drivers.
Otherwise, it is much easier and more efficient to use the IOCTL technique
for sharing memory between a user process and a device driver.
Keywords : kbDDK kbKMode kbNTOS400 kbWinOS2000
Version :
Platform :
Issue type : kbhowto
Last Reviewed: March 5, 1999