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.
-
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.
Development Guidelines
Available APIs
Table 1 Physical memory management module APIs
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