User space memory windows

Allocating System-Space Memory

The ExAllocatePool DDIs discussed in this topic have been deprecated in Windows 10, version 2004 and have been replaced by ExAllocatePool2 and ExAllocatePool3. For more information, see Updating deprecated ExAllocatePool calls to ExAllocatePool2 and ExAllocatePool3.

Drivers can use system-allocated space within their device extensions as global storage areas for device-specific information. Drivers can use only the kernel stack to pass small amounts of data to their internal routines. Some drivers have to allocate additional, larger amounts of system-space memory, typically for I/O buffers.

To allocate I/O buffer space, the best memory allocation routines to use are MmAllocateNonCachedMemory, MmAllocateContiguousMemorySpecifyCache, AllocateCommonBuffer (if the driver’s device uses bus-master DMA or a system DMA controller’s auto-initialize mode), or ExAllocatePoolWithTag.

Nonpaged pool typically becomes fragmented as the system runs, so a driver’s DriverEntry routine should call these routines to set up any long-term I/O buffers the driver needs. Each of these routines, except ExAllocatePoolWithTag, allocates memory that is aligned on a processor-specific boundary (determined by the processor’s data-cache-line size) to provide best performance.

Drivers should allocate I/O buffers as economically as possible, because nonpaged pool memory is a limited system resource. Typically, a driver should avoid calling these support routines repeatedly to request allocations of less than PAGE_SIZE because each allocation that is less than PAGE_SIZE also comes with a pool header that is used to internally manage the allocation.

Tips for Allocating Driver Buffer Space Economically

To allocate I/O buffer memory economically, be aware of the following:

Each call to MmAllocateNonCachedMemory or MmAllocateContiguousMemorySpecifyCache always returns a full multiple of the system’s page size, of nonpaged system-space memory, whatever the size of the requested allocation. Therefore, requests for less than a page are rounded up to a full page and any remainder bytes on the page are wasted; they are inaccessible by the driver that called the function and are unusable by other kernel-mode code.

Each call to AllocateCommonBuffer uses at least one adapter object map register, which maps at least one byte and at most one page. For more information about map registers and using common buffers, see Adapter Objects and DMA.

Allocating Memory with ExAllocatePoolWithTag

Drivers can also call ExAllocatePoolWithTag, specifying one of the following system-defined POOL_TYPE values for the PoolType parameter:

PoolType = NonPagedPool for any objects or resources not stored in a device extension or controller extension that the driver might access while it is running at IRQL > APC_LEVEL.

For this PoolType value, ExAllocatePoolWithTag allocates the amount of memory that is requested if the specified NumberOfBytes is less than or equal to PAGE_SIZE. Otherwise, any remainder bytes on the last-allocated page are wasted: inaccessible to the caller and unusable by other kernel-mode code.

For example, on an x86, an allocation request of 5 kilobytes (KB) returns two 4-KB pages. The last 3 KB of the second page is unavailable to the caller or another caller. To avoid wasting nonpaged pool, the driver should allocate multiple pages efficiently. In this case, for example, the driver could make two allocations, one for PAGE_SIZE and the other for 1 KB, to allocate a total of 5 KB.

NoteВ В Starting with Windows Vista, the system automatically adds the additional memory so two allocations are unnecessary.

PoolType = PagedPool for memory that is always accessed at IRQL —>

Virtual address spaces

When a processor reads or writes to a memory location, it uses a virtual address. As part of the read or write operation, the processor translates the virtual address to a physical address. Accessing memory through a virtual address has these advantages:

Читайте также:  Как установить alpine linux

A program can use a contiguous range of virtual addresses to access a large memory buffer that is not contiguous in physical memory.

A program can use a range of virtual addresses to access a memory buffer that is larger than the available physical memory. As the supply of physical memory becomes small, the memory manager saves pages of physical memory (typically 4 kilobytes in size) to a disk file. Pages of data or code are moved between physical memory and the disk as needed.

The virtual addresses used by different processes are isolated from each other. The code in one process cannot alter the physical memory that is being used by another process or the operating system.

The range of virtual addresses that is available to a process is called the virtual address space for the process. Each user-mode process has its own private virtual address space. For a 32-bit process, the virtual address space is usually the 2-gigabyte range 0x00000000 through 0x7FFFFFFF. For a 64-bit process on 64-bit Windows, virtual address space is the 128-terabyte range 0x000’00000000 through 0x7FFF’FFFFFFFF. A range of virtual addresses is sometimes called a range of virtual memory. For more info, see Memory and Address Space Limits.

This diagram illustrates some of the key features of virtual address spaces.

The diagram shows the virtual address spaces for two 64-bit processes: Notepad.exe and MyApp.exe. Each process has its own virtual address space that goes from 0x000’0000000 through 0x7FF’FFFFFFFF. Each shaded block represents one page (4 kilobytes in size) of virtual or physical memory. Notice that the Notepad process uses three contiguous pages of virtual addresses, starting at 0x7F7’93950000. But those three contiguous pages of virtual addresses are mapped to noncontiguous pages in physical memory. Also notice that both processes use a page of virtual memory beginning at 0x7F7’93950000, but those virtual pages are mapped to different pages of physical memory.

User space and system space

Processes like Notepad.exe and MyApp.exe run in user mode. Core operating system components and many drivers run in the more privileged kernel mode. For more information about processor modes, see User mode and kernel mode. Each user-mode process has its own private virtual address space, but all code that runs in kernel mode shares a single virtual address space called system space. The virtual address space for a user-mode process is called user space.

In 32-bit Windows, the total available virtual address space is 2^32 bytes (4 gigabytes). Usually the lower 2 gigabytes are used for user space, and the upper 2 gigabytes are used for system space.

In 32-bit Windows, you have the option of specifying (at boot time) that more than 2 gigabytes are available for user space. The consequence is that fewer virtual addresses are available for system space. You can increase the size of user space to as much as 3 gigabytes, in which case only 1 gigabyte is available for system space. To increase the size of user space, use BCDEdit /set increaseuserva.

In 64-bit Windows, the theoretical amount of virtual address space is 2^64 bytes (16 exabytes), but only a small portion of the 16-exabyte range is actually used.

Code running in user mode has access to user space but does not have access to system space. This restriction prevents user-mode code from reading or altering protected operating system data structures. Code running in kernel mode has access to both user space and system space. That is, code running in kernel mode has access to system space and the virtual address space of the current user-mode process.

Читайте также:  Курсор mac os для виндовс

Drivers that run in kernel mode must be very careful about directly reading from or writing to addresses in user space. This scenario illustrates why.

A user-mode program initiates a request to read some data from a device. The program supplies the starting address of a buffer to receive the data.

A device driver routine, running in kernel mode, starts the read operation and returns control to its caller.

Later the device interrupts whatever thread is currently running to say that the read operation is complete. The interrupt is handled by kernel-mode driver routines running on this arbitrary thread, which belongs to an arbitrary process.

At this point, the driver must not write the data to the starting address that the user-mode program supplied in Step 1. This address is in the virtual address space of the process that initiated the request, which is most likely not the same as the current process.

Paged pool and Nonpaged pool

In user space, all physical memory pages can be paged out to a disk file as needed. In system space, some physical pages can be paged out and others cannot. System space has two regions for dynamically allocating memory: paged pool and nonpaged pool.

Memory that is allocated in paged pool can be paged out to a disk file as needed. Memory that is allocated in nonpaged pool can never be paged out to a disk file.

Sharing memory between user space and kernel space

I am trying to share memory between user space and kernel space in windows xp.I want to write into the memory in user level and reading it from the kernel driver program.Is there any available in-build function?

1 Answer 1

User mode side: There are a couple of ways.

1) The most common / flexible way is to use DeviceIOControl to communicate between user mode and kernel mode, including passing memory.

It’s been a long time (six years? XP timeframe) since I wrote my last kernel driver, so this is an overview of the process not exact code. However, your user mode program should be able to obtain a handle to your ‘device’ or an open instance of your driver working on something by using CreateFile and specifying its name, such as \\.\YourNameHere for example. Use that handle to communicate with it (the first parameter to DeviceIOControl .)

The four parameters you will be interested in are:

Using these, you can give data to the driver (through the lpInBuffer pointer and nInBufferSize parameter specifying how big it is — what this data is or how to interpret it is up to your driver) and the kernel-mode layer can give data back through lpOutBuffer (a pointer to memory you, in user mode, have already allocated — this is not a pointer that the driver sets!), its size in bytes in nOutBufferSize (again you know this, since you in user mode allocate this buffer) and then the driver will tell you how much of that buffer it actually filled with lpBytesReturned .

This Wikipedia article describes the general concept of ioctl functions, of which DeviceIOControl is an example.

Note: You said «I am trying to share memory between user space and kernel space in windows». This is not exactly shared memory — it’s not memory that both user mode and kernel mode are reading from or writing to at the same time, for example. It is memory where, for the duration of the DeviceIOControl function call, kernel mode has access to your user mode-allocated memory for which you pass it pointers (although from memory it’s slightly more complicated than that, but that’s the effect.) Ie it’s only ‘shared’ while you call that method.

Читайте также:  Появился пароль после обновления windows

2) Another alternative is to use ReadFile and WriteFile if you only need simple data transfer and the kernel driver accepts it. It doesn’t allow you to have two-way communication quite as DeviceIOControl does (where you give the driver data and it gives you something back with an error code) but it’s simple and you’re probably already familiar with those APIs.

Kernel mode side: Are you writing the kernel driver as well? If so, this article has information about implementing the kernel-mode side of IOCTL. This article series also describes allowing user mode to use ReadFile and WriteFile to communicate if you choose that methods.

User Space and System Space

Windows gives each user-mode application a block of virtual addresses. This is known as the user space of that application. The other large block of addresses, known as system space or kernel space, cannot be directly accessed by the application.

When WinDbg or CDB sets a breakpoint in user space, this breakpoint is set at the specified address in the user space of a single process. During user-mode debugging, the current process determines the meaning of virtual addresses. For more information, see Controlling Processes and Threads.

In kernel mode, you can set breakpoints in user space with the bp, bu, and ba commands or with the Breakpoints dialog box. You must first use the process context to specify the user-mode process that owns that address space by using .process /i (or a process-specific breakpoint on some kernel-space function) to switch the target to the correct process context.

Breakpoints in user space are always associated with the process whose process context was active when the breakpoints were set. If a user-mode debugger is debugging this process and if a kernel debugger is debugging the computer that the process is running on, this breakpoint breaks into the user-mode debugger, even though the breakpoint was actually set from the kernel debugger. You can break into the system from the kernel debugger at this point, or use the .breakin (Break to the Kernel Debugger) command from the user-mode debugger to transfer control to the kernel debugger.

Determining the Range of User Space and System Space

If you need to determine the extent of user space and system space on the target computer, you can use the dp (Display Memory) command from a kernel debugger to display the Windows global variable MmHighestUserAddress. This variable contains the address of the top of user space. Since system space addresses are always higher than user space addresses, this value allows you to determine whether any given address is in user space or in kernel space.

For example, on a 32-bit target computer with an x86 processor and standard boot parameters, this command will show the following result:

This indicates that user space ranges from the address 0x00000000 to 0x7FFEFFFF, and system space therefore ranges from 0x80000000 up to the highest possible address (which is 0xFFFFFFFF on a standard 32-bit Windows installation).

With a 64-bit target computer, different values will occur. For example, this command might show the following:

This indicates that user space ranges from 0x00000000`00000000 to 0x000007FF`FFFEFFFF. Therefore, system space includes all addresses from 0x00000800`00000000 upward.

For more information about Windows memory management, see Microsoft Windows Internals by David Solomon and Mark Russinovich (4th edition, Microsoft Press, 2005).

Оцените статью