Saturday 3 December 2016

Driver Development and Memory Management


Driver development – memory management
       Physical memory and virtual memory
       Virtual memory organisation
       Physical and virtual memory mapping
       Accessing physical memory
       Allocators in kernel memory
       Kmalloc alocator and APIs
       Vmalloc allocator and APIs

Virtual memory organization: 1GB/3GB
       1GB reserved for kernel-space
       Contains kernel code and core data structures identical in all address spaces
       Most memory can be a direct mapping of physical memory at a fixed offset
       Complete 3GB exclusive mapping available for each user-space process
       Process code and data (program, stack, …)
       Memory-mapped files
       Not necessarily mapped to physical memory
       (demand fault paging used for dynamic mapping to physical memory pages)
       Differs from one address space to the other





Physical and virtual address


Kernel memory
       Kernel memory allocators allocate physical pages, and kernel allocated memory cannot be swapped out, so
no fault handling required for kernel memory.
       Most kernel memory allocation functions also return a kernel virtual address to be used within the kernel space.
       Kernel memory low-level allocator manages pages. This is the finest granularity (usually 4 kB, architecture dependent).
       However, the kernel memory management handles smaller
memory allocations through its allocator (see slabs / SLUB
allocator – used by kmalloc).

Allocators in the kernel


Page allocators
       Appropriate for large allocations
       A page is usually 4K, but can be made greater in some architectures.
       Buddy allocator strategy, so only allocations of power of two number of pages are possible: 1 page, 2 pages, 4 pages, 8 pages, 16 pages, etc.
       The allocated area is virtually contiguous (of course), but also physically contiguous. It is allocated in the identity-mapped part of the kernel memory space.
       This means that large areas may not be available or hard to retrieve due to physical memory fragmentation.

Page allocator APIs
       unsigned long get_zeroed_page(int flags);
       Returns the virtual address of a free page, initialized to zero
       unsigned long __get_free_page(int flags);
       Same, but doesn't initialize the contents
       unsigned long __get_free_pages(int flags, unsigned int order);
       Returns the starting virtual address of an area of several contiguous pages in physical RAM, with order being log2(<number_of_pages>).Can be computed from the size with the get_order() function.
       void free_page(unsigned long addr);
       Frees one page.
       void free_pages(unsigned long addr, unsigned int order);
       Frees multiple pages. Need to use the same order as in allocation.

Page allocator flags
       The most common ones are:
       GFP_KERNEL
       Standard kernel memory allocation. The allocation may block in order to find enough available memory. Fine for most needs, except in interrupt handler context.
       GFP_ATOMIC
       RAM allocated from code which is not allowed to block (interrupt handlers or critical sections). Never blocks, allows to access emergency pools, but can fail if no free memory is readily available.
       GFP_DMA
       Allocates memory in an area of the physical memory usable for  DMA transfers.
       Others are defined in include/linux/gfp.h
       (GFP: __get_free_pages).

SLAB allocator
       The SLAB allocator allows to create caches, which contains a set of objects of the same size
       The object size can be smaller or greater than the page size
       The SLAB allocator takes care of growing or reducing the size of the cache as needed, depending on the number of allocated objects. It uses the page allocator to allocate and free pages.
       SLAB caches are used for data structures that are present in many instances in the kernel: directory entries, file objects, network packet descriptors, process descriptors, etc.
       See /proc/slabinfo
       They are rarely used for individual drivers.
       See include/linux/slab.h for the API

Kmalloc allocator
       The kmalloc allocator is the general purpose memory allocator in the Linux kernel, for objects from 8 bytes to 128 KB
       For small sizes, it relies on generic SLAB caches, named kmalloc-XXX in /proc/slabinfo
       For larger sizes, it relies on the page allocator
       The allocated area is guaranteed to be physically contiguous
       The allocated area size is rounded up to the next power of two size
       It uses the same flags as the page allocator (GFP_KERNEL,
       GFP_ATOMIC, GFP_DMA, etc.) with the same semantics.
       Should be used as the primary allocator unless there is a strong reason to use another one.

Kmalloc API
       #include <linux/slab.h>
       void *kmalloc(size_t size, int flags);
       Allocate size bytes, and return a pointer to the area (virtual address)
       size: number of bytes to allocate
       flags: same flags as the page allocator
       void kfree (const void *objp);
       Free an allocated area
       void *kzalloc(size_t size, gfp_t flags);
       Allocates a zero-initialized buffer

Vmalloc allocator
       The vmalloc allocator can be used to obtain virtually contiguous memory zones, but not physically contiguous.
       The requested memory size is rounded up to the next page.
       The allocated area is in the kernel space part of the address space, but outside of the identically-mapped area
       Allocations of fairly large areas is possible, since physical memory fragmentation is not an issue, but areas cannot be used for DMA, as DMA usually requires physically contiguous buffers.
       API in <linux/vmalloc.h>
       void *vmalloc(unsigned long size);
       Returns a virtual address
       void vfree(void *addr);
       Frees the allocated area
       Using the kmalloc/kfree APIs writing the read/write function of the character device dirver
       Write a kernel module to check the upper limit of kmalloc API
       Write a kernel module allocating memory using vmalloc() APIs.


No comments:

Post a Comment