What Is Memory Allocation Techniques?

Table 3. Summary of Memory Allocation Routines
Name
Description
ExAllocatePoolXxx
Allocates paged or nonpaged, cached, and cache-aligned memory from the kernel-mode pool.
ExAllocatePoolWithTag is the primary function for memory allocation.
AllocateCommonBuffer
Allocates a buffer for common-buffer DMA and ensures cross-platform compatibility.
MmAllocateContiguousMemory
[SpecifyCache]
Allocates nonpaged, physically contiguous, cache-aligned memory.
Drivers should not use these functions to allocate memory for DMA because the addresses that they return are not guaranteed to be compatible across all hardware configurations. Drivers should use AllocateCommonBuffer instead.
MmAllocateMappingAddress
Reserves virtual addresses in a specific range for later use in an MDL, but does not map them to physical memory.
The driver can later use IoAllocateMdl, MmProbeAndLockPages, and MmMapLockedPagesWithReservedMapping to map the virtual addresses to physical memory. 
MmAllocateNoncachedMemory
Allocates nonpaged, noncached, page-aligned memory. Drivers rarely use this function; they must not use it to allocate buffers for DMA.
MmAllocatePagesForMdl
Allocates nonpaged, noncontiguous pages from physical memory, specifically for an MDL. An MDL can describe up to 4 GB. This function might return fewer pages than the caller requested. Therefore, the driver must call MmGetMdlByteCount to verify the number of allocated bytes.
A driver can call this function to allocate physical memory from a particular address range, such as allocating memory for a device that cannot address memory above 4 GB. However, drivers should not use this function to allocate buffers for DMA. Only the Windows DMA routines guarantee the cross-platform compatibility that drivers require.


·         Pool memory for long-term storage
·         Lookaside lists
·         Contiguous memory

Allocating Memory for Long-Term Storage

·         The device or driver requires more than a page of physically contiguous memory. (Remember that page size varies depending on the machine architecture.)
·         The device requires noncached or write-combined memory. Some video devices fall into this category.
·         The device has constraints that limit the range of addresses it can use.

Pool memory is a limited resource, so drivers should allocate it economically. When you design your driver, plan your memory allocations according to memory type, allocation size, and allocation lifetime. Free the allocated memory as soon as you are done using it.
If your driver requires large amounts of nonpaged pool for long-term use, allocate the memory at startup if possible, either in the DriverEntry routine or in an AddDevice routine. Because the nonpaged pool becomes fragmented as the system runs, later attempts to allocate memory from the nonpaged pool could fail.

A driver should not, however, preallocate excessively large blocks of memory (several megabytes, for example) and try to manage its own allocations within that block. Although this technique might work for your driver, it often results in inefficient memory usage across the system and thus poor performance system-wide. Remember that other drivers and applications also require memory. Never allocate lots of memory “just in case” your driver might need it. As a general design guideline, consider preallocating only enough memory for one I/O transaction and then process the transactions serially. If the transactions all require same-sized allocations, consider using lookaside lists because these buffers are dynamically allocated.

·         ExAllocatePoolWithTag
·         ExAllocatePoolWithTagPriority
·         ExAllocatePoolWithQuotaTag

Drivers must use the tagged versions of the pool allocation routines because the nontagged versions are obsolete. Both WinDbg and Driver Verifier use pool tags to track memory allocations. Tagging pool allocations can simplify finding memory-related bugs, including leaks. Be sure to use unique tags so that the debugging and testing tools can provide useful information.
Note
The pool type NonPagedPoolMustSucceed has been deprecated. Drivers should specify the pool type NonPagedPool or NonPagedPoolCacheAligned instead and should return the NTSTATUS value STATUS_INSUFFICIENT_RESOURCES if the allocation fails. The Driver Verifier flags any pool allocation that is specified as NonPagedPoolMustSucceed as fatal and causes a bug check. (Note that on versions of Windows earlier than Microsoft Windows Vista™ specifying NonPagedPoolCacheAligned is the same as specifying NonPagedPool. On Windows Vista, however, specifying NonPagedPoolCacheAligned ensures that the system allocates cache-aligned memory.)

MyBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
                 MAX_BUFFER_SIZE,
                 'tseT');

if (MyBuffer == NULL)
{
    DebugPrint((1, " Can't allocate MyBuffer \n"));
    return(STATUS_INSUFFICIENT_RESOURCES);
    }

The example specifies the pool tag in reverse order so that it appears as “Test” in the debugger. (You should use a tag that uniquely identifies your driver.) In the example, MAX_BUFFER_SIZE specifies the number of bytes to allocate. Because of rounding and alignment, the driver might receive a buffer of exactly the requested size or a larger buffer. The ExAllocatePoolXxx routines align and round allocations as follows:

Size requested
Size allocated
Default alignment
Less than or equal to
(PAGE_SIZE –
sizeof (POOL_HEADER))
Number of bytes requested
8-byte boundary (16-byte on 64-bit Windows). Allocation is contiguous and does not cross page boundary.
Greater than
(PAGE_SIZE –
sizeof (POOL_HEADER))
Number of bytes requested, rounded up to next full page size
Page-aligned. Pages are not necessarily physically contiguous, but they are always virtually contiguous.

The pool header is 8 bytes long on 32-bit systems and 16-bytes long on 64-bit systems. The size of the pool header does not affect the caller.

To use the pool most efficiently, avoid calling the memory allocation routines repeatedly to request small allocations of less than PAGE_SIZE. If your driver normally uses several related structures together, consider bundling those structures into a single allocation at driver start-up. For example, the SCSI port driver bundles an IRP, a SCSI request block (SRB), and an MDL into a single allocation. By allocating the memory at start-up, you reduce the number of times your driver calls memory allocation routines and therefore the number of situations in which it must be prepared to handle an allocation failure. Eliminating such failure scenarios greatly simplifies the error paths in your driver.

Pool memory remains allocated until the driver explicitly frees it. Before the driver exits, it must call ExFreePool or ExFreePoolWithTag to free all the memory that it allocated with any of the ExAllocatePoolXxx variants. Failing to free the memory causes memory leaks, which can eventually slow system performance and cause other components to fail.

Creating and Using Lookaside Lists

A driver calls ExInitialize[N]PagedLookasideList to set up a lookaside list, ExAllocateFrom[N]PagedLookasideList to allocate a buffer from the list, and ExFreeTo[N]PagedLookasideList to free a buffer to the list.
Even if a lookaside list is allocated in paged memory, the head of the list must be allocated in nonpaged memory because the system scans it at DISPATCH_LEVEL to perform various bookkeeping chores. Typically, drivers store a pointer to the head of the list in the device extension.
ExInitializeNPagedLookasideList
      (&FdoData->RecvLookasideList,
       NULL,
       NULL,
       0,
       RecvBlockSize,
       ‘LciN’,
       0);

The lookaside list in the example is allocated from nonpaged memory because the driver accesses it at DISPATCH_LEVEL or higher. The first parameter identifies the location in nonpaged memory where the driver stores the head of the list. This location must be at least sizeof (NPAGED_LOOKASIDE_LIST). The two NULL parameters represent the driver routines that the system calls to allocate and free buffers from the list. If the driver passes NULL, the system uses ExAllocatePoolWithTag and ExFreePoolWithTag. Although a driver can supply its own routines, using the system’s allocation routines is generally more efficient. The fourth parameter supplies internal flags and must be zero. The fifth parameter, RecvBlockSize, specifies the size of each buffer in the list, and the sixth is the tag used for the pool allocation. The final parameter is also reserved for internal use and must be zero.

pRecvBlock = ExAllocateFromNPagedLookasideList (
                 &FdoData->RecvLookasideList);

If the allocation fails for any reason, the allocation routine returns a NULL pointer. The driver should validate the result and either return an error or retry the operation until it receives a valid pointer.
ExFreeToNPagedLookasideList (
                 &FdoData->RecvLookasideList,
                 pRecvBlock);

To avoid using memory unnecessarily, drivers should free buffers as soon as they are no longer needed.

Finally, when the driver no longer needs any buffers from the list, it calls ExDeleteNPagedLookasideList.
ExDeleteNPagedLookasideList (
                 &FdoData->RecvLookasideList);

The list need not be empty because this function deletes any remaining buffers and then deletes the list itself.

Drivers that run on Windows XP and later versions can use lookaside lists to allocate scatter/gather lists for DMA, as described in “DMA Support in Windows Drivers,” which is listed in the Resources section of this paper.

Allocating Contiguous Memory

·         The DMA functions AllocateCommonBuffer or GetScatterGatherList
·         MmAllocatePagesForMdl
·         MmAllocateContiguousMemorySpecifyCache

To allocate memory for DMA buffers, drivers should call AllocateCommonBuffer or GetScatterGatherList. For more information about these DMA functions, see the Windows DDK and “DMA Support in Windows Drivers,” which are listed in the Resources section of this paper.
MmAllocatePagesForMdl allocates pages from a specified range of physical addresses. Therefore, it is useful for drivers of devices that cannot address memory in certain ranges. For example, some devices cannot address memory above 4 GB. The driver for such a device could use this function to ensure that a buffer was allocated in memory below 4 GB. However, that this function allocates independent pages that are not physically contiguous; that is, each entry in the MDL maps a page of memory, but pages are typically not contiguous with respect to each other. If your device requires no more than a page of contiguous memory at a time, but requires many such pages, MmAllocatePagesForMdl is appropriate. Do not use this function to allocate buffers for DMA—use the DMA routines instead.

Drivers that need larger amounts of physically contiguous memory should use MmAllocateContiguousMemorySpecifyCache. Drivers should try to allocate such memory during driver initialization because physical memory is likely to become fragmented as the system runs. A driver should allocate only as much contiguous memory as it needs, and it should free the memory as soon as it is no longer needed.

LowestAcceptable.QuadPart = 0;
BoundaryMultiple.QuadPart = 0;
HighestAcceptable.QuadPart = 0xFFFFFFFF;

MemBuff = MmAllocateContiguousMemorySpecifyCache(MemLength,
                LowestAcceptable,
                HighestAcceptable,
                BoundaryMultiple,
                MmNonCached);

if (MemBuff == NULL) {
    return(STATUS_INSUFFICIENT_RESOURCES);
    }

In the example, the driver allocates contiguous, noncached memory in the first 4 GB of the physical address space. MemLength specifies the number of required contiguous bytes. The driver passes zero in the LowestAcceptable parameter to indicate that the range of addresses it can use starts at zero, and it passes 0xFFFFFFFF in the HighestAcceptable parameter to indicate that the range ends at 4 GB. It sets BoundaryMultiple to zero because there are no boundaries within the specified range that the memory should not cross. The function returns a full multiple of the system’s page size. If MemLength is not a multiple of the page size, the function rounds up to the next full page.


Do not use MmAllocateContiguousMemorySpecifyCache to allocate buffers for DMA and then call MmGetPhysicalAddress to translate the returned virtual address to an address with which to program your DMA controller. This approach does not work on all hardware, and your device and driver will not be cross-platform compatible. Use AllocateCommonBuffer or GetScatterGatherList instead.

0 komentar:

Posting Komentar

 

Serba Ada Blog Copyright © 2011-2012 | Powered by Blogger