# 物ç†å†…å˜ç®¡ç† ## 基本概念 物ç†å†…å˜æ˜¯è®¡ç®—机上最é‡è¦çš„资æºä¹‹ä¸€ï¼ŒæŒ‡çš„æ˜¯å®žé™…的内å˜è®¾å¤‡æä¾›çš„ã€å¯ä»¥é€šè¿‡CPU总线直接进行寻å€çš„内å˜ç©ºé—´ï¼Œå…¶ä¸»è¦ä½œç”¨æ˜¯ä¸ºæ“作系统åŠç¨‹åºæä¾›ä¸´æ—¶å˜å‚¨ç©ºé—´ã€‚LiteOS-Aå†…æ ¸ç®¡ç†ç‰©ç†å†…å˜æ˜¯é€šè¿‡åˆ†é¡µå®žçŽ°çš„ï¼Œé™¤äº†å†…æ ¸å †å 用的一部分内å˜å¤–,其余å¯ç”¨å†…å˜å‡ä»¥4KiB为å•ä½åˆ’分æˆé¡µå¸§ï¼Œå†…å˜åˆ†é…和内å˜å›žæ”¶ä¾¿æ˜¯ä»¥é¡µå¸§ä¸ºå•ä½è¿›è¡Œæ“ä½œã€‚å†…æ ¸é‡‡ç”¨ä¼™ä¼´ç®—æ³•ç®¡ç†ç©ºé—²é¡µé¢ï¼Œå¯ä»¥é™ä½Žä¸€å®šçš„内å˜ç¢Žç‰‡çŽ‡ï¼Œæé«˜å†…å˜åˆ†é…和释放的效率,但是一个很å°çš„å—往往也会阻塞一个大å—çš„åˆå¹¶ï¼Œå¯¼è‡´ä¸èƒ½åˆ†é…较大的内å˜å—。 ## è¿è¡Œæœºåˆ¶ 如下图所示,LiteOS-Aå†…æ ¸çš„ç‰©ç†å†…å˜ä½¿ç”¨åˆ†å¸ƒè§†å›¾ï¼Œä¸»è¦ç”±å†…æ ¸é•œåƒã€å†…æ ¸å †åŠç‰©ç†é¡µç»„æˆã€‚å†…æ ¸å †éƒ¨åˆ†è§å †å†…å˜ç®¡ç†ä¸€èŠ‚ã€‚ **图1** 物ç†å†…å˜ä½¿ç”¨åˆ†å¸ƒå›¾  伙伴算法把所有空闲页帧分æˆ9个内å˜å—组,æ¯ç»„ä¸å†…å˜å—包å«2的幂次方个页帧,例如:第0组的内å˜å—包å«2çš„0次方个页帧,å³1个页帧;第8组的内å˜å—包å«2çš„8次方个页帧,å³256个页帧。相åŒå¤§å°çš„内å˜å—挂在åŒä¸€ä¸ªé“¾è¡¨ä¸Šè¿›è¡Œç®¡ç†ã€‚ - ç”³è¯·å†…å˜ ç³»ç»Ÿç”³è¯·12KiB内å˜ï¼Œå³3个页帧时,9个内å˜å—组ä¸ç´¢å¼•为3的链表挂ç€ä¸€å—大å°ä¸º8个页帧的内å˜å—æ»¡è¶³è¦æ±‚,分é…出12KiB内å˜åŽè¿˜å‰©ä½™20KiB内å˜ï¼Œå³5个页帧,将5个页帧分æˆ2的幂次方之和,å³4è·Ÿ1,å°è¯•查找伙伴进行åˆå¹¶ã€‚4个页帧的内å˜å—没有伙伴则直接æ’到索引为2çš„é“¾è¡¨ä¸Šï¼Œç»§ç»æŸ¥æ‰¾1个页帧的内å˜å—æ˜¯å¦æœ‰ä¼™ä¼´ï¼Œç´¢å¼•为0çš„é“¾è¡¨ä¸Šæ¤æ—¶æœ‰1个,如果两个内å˜å—地å€è¿žç»åˆ™è¿›è¡Œåˆå¹¶ï¼Œå¹¶å°†å†…å˜å—挂到索引为1的链表上,å¦åˆ™ä¸åšå¤„ç†ã€‚ **图2** 内å˜ç”³è¯·ç¤ºæ„图  - é‡Šæ”¾å†…å˜ ç³»ç»Ÿé‡Šæ”¾12KiB内å˜ï¼Œå³3个页帧,将3个页帧分æˆ2的幂次方之和,å³2è·Ÿ1,å°è¯•查找伙伴进行åˆå¹¶ï¼Œç´¢å¼•为1的链表上有1个内å˜å—,若地å€è¿žç»åˆ™åˆå¹¶ï¼Œå¹¶å°†åˆå¹¶åŽçš„内å˜å—挂到索引为2的链表上,索引为0çš„é“¾è¡¨ä¸Šæ¤æ—¶ä¹Ÿæœ‰1个,如果地å€è¿žç»åˆ™è¿›è¡Œåˆå¹¶ï¼Œå¹¶å°†åˆå¹¶åŽçš„内å˜å—挂到索引为1çš„é“¾è¡¨ä¸Šï¼Œæ¤æ—¶ç»§ç»åˆ¤æ–æ˜¯å¦æœ‰ä¼™ä¼´ï¼Œé‡å¤ä¸Šè¿°æ“作。 **图3** 内å˜é‡Šæ”¾ç¤ºæ„图  ## 开呿Œ‡å¯¼ ### 接å£è¯´æ˜Ž **表1** 物ç†å†…å˜ç®¡ç†æ¨¡å—æŽ¥å£ | 功能分类 | æŽ¥å£æè¿° | | -------- | -------- | | 申请物ç†å†…å˜ | - LOS_PhysPageAlloc:申请一个物ç†é¡µ<br/>- LOS_PhysPagesAlloc:申请物ç†é¡µå¹¶æŒ‚在对应的链表上<br/>- LOS_PhysPagesAllocContiguous:申请多页地å€è¿žç»çš„物ç†å†…å˜ | | 释放物ç†å†…å˜ | - LOS_PhysPageFree:释放一个物ç†é¡µ<br/>- LOS_PhysPagesFree:释放挂在链表上的物ç†é¡µ<br/>- LOS_PhysPagesFreeContiguous:释放多页地å€è¿žç»çš„物ç†å†…å˜ | | æŸ¥è¯¢åœ°å€ | - LOS_VmPageGetï¼šæ ¹æ®ç‰©ç†åœ°å€èŽ·å–其对应的物ç†é¡µç»“构体指针<br/>- LOS_PaddrToKVaddrï¼šæ ¹æ®ç‰©ç†åœ°å€èŽ·å–å…¶å¯¹åº”çš„å†…æ ¸è™šæ‹Ÿåœ°å€ | ### 开呿µç¨‹ 内å˜ç”³è¯·æ—¶æ ¹æ®éœ€è¦è°ƒç”¨ç›¸å…³æŽ¥å£ï¼Œå°å†…å˜ç”³è¯·å»ºè®®ä½¿ç”¨å †å†…å˜ç”³è¯·ç›¸å…³æŽ¥å£ï¼Œ4KiBåŠä»¥ä¸Šå†…å˜ç”³è¯·å¯ä»¥ä½¿ç”¨ä¸Šè¿°ç‰©ç†å†…å˜ç›¸å…³æŽ¥å£ã€‚ >  **说明:** > - 物ç†å†…å˜ç”³è¯·ç›¸å…³æŽ¥å£éœ€è¦åœ¨OsSysMemInit接å£å®Œæˆåˆå§‹åŒ–之åŽå†ä½¿ç”¨ï¼› > > - 内å˜ç”³è¯·çš„基本å•使˜¯é¡µå¸§ï¼Œå³4KiBï¼› > > - 物ç†å†…å˜ç”³è¯·æ—¶ï¼Œæœ‰åœ°å€è¿žç»è¦æ±‚的使用LOS_PhysPagesAllocContiguous接å£ï¼Œæ— 地å€è¿žç»çš„è¦æ±‚å°½é‡ä½¿ç”¨LOS_PhysPagesAlloc接å£ï¼Œå°†è¿žç»çš„大å—内å˜ç•™ç»™æœ‰éœ€è¦çš„æ¨¡å—使用。 ### 编程实例 ç¼–ç¨‹ç¤ºä¾‹ä¸»è¦æ˜¯è°ƒç”¨ç”³è¯·ã€é‡Šæ”¾æŽ¥å£å¯¹å†…å˜è¿›è¡Œæ“作,包括申请一个页以åŠå¤šä¸ªé¡µçš„示例。 ``` #include "los_vm_phys.h" #define PHYS_PAGE_SIZE 0x4000 // 申请一个页 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); } // 申请多个页,ä¸è¦æ±‚è¿žç» 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); } // 申请多个连ç»é¡µ 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; } ``` ### ç»“æžœéªŒè¯ ç¼–è¯‘è¿è¡Œå¾—到的结果为: ``` LOS_PhysPagesAllocContiguous success LOS_PhysPagesAlloc success LOS_PhysPageAlloc success ```