Physical Memory Management

Basic Concepts

Physical memory is one of the most important resources on a computer. It is the memory space that is provided by the physical memory devices and can be directly addressed through the CPU bus. The physical memory provides temporary storage space for the OS and programs. The LiteOS-A kernel manages the physical memory via memory paging. Except the memory occupied by the kernel heap, other available memory is divided into page frames in the unit of 4 KiB. Memory is allocated and reclaimed by page frame. The kernel uses the buddy algorithm to manage free pages to reduce the fragmentation rate and improve the memory allocation and release efficiency. However, a small block may block the merge of a large block, causing a failure to allocate a large memory block.

Working Principles

As shown in the following figure, the physical memory distribution of the LiteOS-A kernel consists of the kernel image, kernel heap, and physical pages. For details about the kernel heap, see "Heap Memory Management."

Figure 1 Physical memory usage distribution

The buddy algorithm divides all free page frames into 9 memory block groups, each of which contains 2N page frames. For example, the memory block in group 0 has 20, that is, 1 page frame. The memory block in the eighth group has 28, that is, 256 page frames. Memory blocks of the same size are added to the same linked list for management.

  • Requesting memory

    When 12 KiB memory (3 page frames) is requested, the list in group 3 (with 8 page frames) meets the requirement. After 12 KiB memory is allocated, 20 KiB memory (5 page frames) is left. The 5 page frames can be divided into 4 (22) page frames and 1 (20) page frame. The 4 page frames have no buddy in the list, and therefore are inserted into list 2. The 1 page frame has a buddy in list 0. If the addresses of the two (20) memory blocks are contiguous, the memory blocks are merged as 2 page frames (21) and inserted to list 2. If the addresses are not contiguous, the two (20) page frames are left in list 0.

    Figure 2 Requesting memory

  • Releasing memory

    When 12 KiB memory (3 page frames) is released, the 3 page frames can be divided into 2 (21) page frames and 1 (20) page frame. The 2 page frames can be merged with the memory in linked list 1 if their addresses are contiguous and inserted to list 2. The one page frame can be merged with the memory in linked list 0 if their addresses are contiguous and inserted to list 1. In this way, the memory is released based on the buddy mechanism.

    Figure 3 Releasing memory

Development Guidelines

Available APIs

Table 1 Physical memory management module APIs

Function

API

Description

Requesting physical memory

LOS_PhysPageAlloc

Requests a physical page.

LOS_PhysPagesAlloc

Requests a physical page and adds it to the corresponding linked list.

LOS_PhysPagesAllocContiguous

Requests memory of contiguous pages.

Releasing physical memory

LOS_PhysPageFree

Releases a physical page.

LOS_PhysPagesFree

Releases the physical pages added to a linked list.

LOS_PhysPagesFreeContiguous

Releases memory of contiguous pages.

Querying memory address

LOS_VmPageGet

Obtains the physical page structure pointer based on the physical address.

LOS_PaddrToKVaddr

Obtains the kernel virtual address based on the physical address.

How to Develop

Use different APIs to request memory. Heap management APIs are recommended for requesting small amount of memory. Physical memory management APIs are recommended for requesting 4 KiB or larger memory.

NOTE:

  • APIs used for requesting physical memory can be used only after memory initialization is complete by calling OsSysMemInit.
  • The basic unit for memory allocation is page frame, that is, 4 KiB.
  • To leave contiguous memory blocks for the modules that demand them, use LOS_PhysPagesAllocContiguous to request contiguous memory blocks and use LOS_PhysPagesAlloc to request memory blocks that are not contiguous.

Development Example

This example calls APIs to request and release memory, including requesting one and multiple memory pages.

#include "los_vm_phys.h"

#define PHYS_PAGE_SIZE 0x4000

// Request a page.
VOID OsPhysPagesAllocTest3(VOID)
{
    PADDR_T newPaddr;
    VOID *kvaddr = NULL;
    LosVmPage *newPage = NULL;

    newPage = LOS_PhysPageAlloc();
    if (newPage == NULL) {
        printf("LOS_PhysPageAlloc fail\n");
        return;
    }
    printf("LOS_PhysPageAlloc success\n");

    newPaddr = VM_PAGE_TO_PHYS(newPage);
    kvaddr = OsVmPageToVaddr(newPage);

    // Handle the physical memory

    // Free the physical memory
    LOS_PhysPageFree(newPage);
}

// Request multiple pages that do not need to be contiguous.
VOID OsPhysPagesAllocTest2(VOID)
{
    UINT32 sizeCount;
    UINT32 count;
    UINT32 size = PHYS_PAGE_SIZE;
    LosVmPage *vmPageArray[PHYS_PAGE_SIZE >> PAGE_SHIFT] = { NULL };
    UINT32 i = 0;
    LosVmPage *vmPage = NULL;
    PADDR_T pa;

    size = LOS_Align(size, PAGE_SIZE);
    if (size == 0) {
        return;
    }
    sizeCount = size >> PAGE_SHIFT;

    LOS_DL_LIST_HEAD(pageList);

    count = LOS_PhysPagesAlloc(sizeCount, &pageList);
    if (count < sizeCount) {
        printf("failed to allocate enough pages (ask %zu, got %zu)\n", sizeCount, count);
        goto ERROR;
    }
    printf("LOS_PhysPagesAlloc success\n");
    while ((vmPage = LOS_ListRemoveHeadType(&pageList, LosVmPage, node))) {
        pa = vmPage->physAddr;
        vmPageArray[i++] = vmPage;
        // Handle the physical memory
    }

    // Free the physical memory
    for (i = 0; i < sizeCount; ++i) {
        LOS_PhysPageFree(vmPageArray[i]);
    }

    return;

ERROR:
    (VOID)LOS_PhysPagesFree(&pageList);
}

// Request multiple contiguous memory pages.
VOID OsPhysPagesAllocTest1(VOID)
{
    VOID *ptr = NULL;
    LosVmPage *page = NULL;
    UINT32 size = PHYS_PAGE_SIZE;

    ptr = LOS_PhysPagesAllocContiguous(ROUNDUP(size, PAGE_SIZE) >> PAGE_SHIFT);
    if (ptr == NULL) {
        printf("LOS_PhysPagesAllocContiguous fail\n");
        return;
    }

    printf("LOS_PhysPagesAllocContiguous success\n");

    // Handle the physical memory

    // Free the physical memory
    page = OsVmVaddrToPage((VOID *)ptr);
    LOS_PhysPagesFreeContiguous((VOID *)ptr, size >> PAGE_SHIFT);
}

UINT32 ExamplePhyMemCaseEntry(VOID)
{
    OsPhysPagesAllocTest1();
    OsPhysPagesAllocTest2();
    OsPhysPagesAllocTest3();
    return LOS_OK;
}

Verification

The development is successful if the return result is as follows:

LOS_PhysPagesAllocContiguous success
LOS_PhysPagesAlloc success
LOS_PhysPageAlloc success