16.4.1.3 Allocating System-Space Memory

The system-space virtual memory shown in Figure 16.3 consists of a limited amount of paged pool and an even more limited amount of nonpaged pool.

Nonpaged pool is guaranteed to be resident at all times. Consequently, it can be accessed safely while running at any IRQL.

    For NT drivers, paged pool can be allocated and accessed only under the following condition:

The routine using the corresponding paged-pool virtual addresses must be running at IRQL <= APC_LEVEL. As mentioned in Section 16.1, if a page fault occurs while running at IRQL > APC_LEVEL, it is a fatal error.

Except during their initialization or, possibly, while unloading, NT device and intermediate drivers seldom allocate memory from paged pool because these types of drivers so frequently run at IRQL greater than APC_LEVEL. Any pageable storage that such a driver allocates cannot be accessed safely except by driver-created threads or by the DriverEntry, Reinitialize (if any), and Unload (if any) routines, which can use paged pool allocations to contain data, objects, and resources needed only during initialization or while unloading.

Since several standard NT driver routines run at an IRQL higher than APC_LEVEL, memory allocated from paged pool is inaccessible to most of an NT intermediate or device driver’s routines. For example, higher-level drivers’ IoCompletion routines execute in an arbitrary thread context, usually at DISPATCH_LEVEL IRQL. Such a driver should never allocate pageable storage for data to be accessed from an IoCompletion routine. For more information about the IRQLs at which standard driver routines execute, see Section 16.1.

For specific information about any of the support routines mentioned in this section, see also the Kernel-Mode Driver Reference.

Allocating Driver Buffer Space

For an I/O buffer space, an NT driver can call MmAllocateNonCachedMemory, MmAllocateContiguousMemory, HalAllocateCommonBuffer if the driver’s device uses busmaster DMA or a system DMA controller’s autoinitialize mode, or ExAllocatePool.

Nonpaged pool tends to become fragmented as the system runs, so an NT 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 possibly ExAllocatePool, allocates memory that is aligned on a processor-specific boundary (determined by the processor’s data-cache-line size) to prevent cache and coherency problems.

NT drivers should allocate their internal I/O buffers, if any, as economically as possible because nonpaged pool memory is a limited system resource. In general, a DriverEntry routine should avoid calling these support routines repeatedly to request allocations of less than PAGE_SIZE.

    In particular, driver writers should consider the following facts in order to allocate I/O buffer memory economically:
Allocating Memory with ExAllocatePool or ExAllocatePoolWithTag

NT drivers also can call ExAllocatePool or ExAllocatePoolWithTag, specifying one of the following system-defined values for the PoolType parameter:

Because the must-succeed pool is a very limited system resource, allocations must be released by calling ExFreePool as soon as possible. Most NT drivers should not call ExAllocatePool or ExAllocatePoolWithTag with the PoolType values NonPagedPoolMustSucceed or NonPagedPoolCacheAlignedMustS, unless the system cannot continue to run if the driver’s allocation request does not succeed. For these PoolType specifications, ExAllocatePool brings down the system if it cannot allocate the requested memory.

For all other PoolType specifications, ExAllocatePool or ExAllocatePoolWithTag returns a NULL pointer if it cannot allocate the requested NumberOfBytes. NT drivers should always check the pointer returned by ExAllocatePool or ExAllocatePoolWithTag. If its value is NULL, the DriverEntry routine (or any other driver routine that returns NTSTATUS) should return STATUS_INSUFFICIENT_RESOURCES or handle the error condition if possible. For more information about handling I/O errors, see Section 16.6.

For the CacheAligned PoolType specifications, ExAllocatePool or ExAllocatePoolWithTag allocates memory that is aligned on a processor-specific boundary (determined by the processor’s data-cache-line size) to prevent cache and coherency problems.