diff --git a/kernel/base/include/los_vm_page.h b/kernel/base/include/los_vm_page.h index c3009206a8cd03a46db9c89adfe9af7ac8df4d0f..f7ecb00db44815dd824e6eb945c3a3967fa1d002 100644 --- a/kernel/base/include/los_vm_page.h +++ b/kernel/base/include/los_vm_page.h @@ -42,16 +42,20 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ +/****************************************************************************** + 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。 + 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组 +******************************************************************************/ //注意: vmPage 中并没有虚拟地址,只有物理地址 -typedef struct VmPage { //虚拟内存描述符 - LOS_DL_LIST node; /**< vm object dl list */ //虚拟内存节点,通过它挂到全局虚拟页上 +typedef struct VmPage { //物理页框描述符 + LOS_DL_LIST node; /**< vm object dl list */ //虚拟内存节点,通过它挂到全局g_vmPhysSeg[segID]->freeList[order]物理页框链表上 UINT32 index; /**< vm page index to vm object */ //索引位置 - PADDR_T physAddr; /**< vm page physical addr */ //物理地址 + PADDR_T physAddr; /**< vm page physical addr */ //物理页框起始物理地址,只能用于计算,不会用于操作(读/写数据==) Atomic refCounts; /**< vm page ref count */ //被引用次数,共享内存会被多次引用 - UINT32 flags; /**< vm page flags */ //页标签,(共享/引用/活动/被锁==) + UINT32 flags; /**< vm page flags */ //页标签,同时可以有多个标签(共享/引用/活动/被锁==) UINT8 order; /**< vm page in which order list */ //被安置在伙伴算法的几号序列( 2^0,2^1,2^2,...,2^order) - UINT8 segID; /**< the segment id of vm page */ //所在段ID - UINT16 nPages; /**< the vm page is used for kernel heap */ //vm页面用于内核堆 + UINT8 segID; /**< the segment id of vm page */ //所属段ID + UINT16 nPages; /**< the vm page is used for kernel heap */ //页总数,页大小4K的倍数 } LosVmPage; extern LosVmPage *g_vmPageArray;//物理内存所有页框(page frame)记录数组 diff --git a/kernel/base/include/los_vm_phys.h b/kernel/base/include/los_vm_phys.h index 25f1d17b8df56854ec81770c26a9b321e6c3664e..fbe05d6245592ef6e437385af0e8e13deb47a344 100644 --- a/kernel/base/include/los_vm_phys.h +++ b/kernel/base/include/los_vm_phys.h @@ -43,8 +43,13 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ -#define VM_LIST_ORDER_MAX 9 -#define VM_PHYS_SEG_MAX 32 +/****************************************************************************** +LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的, +是根据页面调入内存后的使用情况进行决策了。由于无法预测各页面将来的使用情况,只能利用 +“最近的过去”作为“最近的将来”的近似,因此,LRU算法就是将最近最久未使用的页面予以淘汰。 +******************************************************************************/ +#define VM_LIST_ORDER_MAX 9 //伙伴算法分组,即物理内存层面一次最大分配 2^8 * 4K = 1M +#define VM_PHYS_SEG_MAX 32 //最大支持32个段 #ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) @@ -69,20 +74,20 @@ enum OsLruList {//Lru全称是Least Recently Used,即最近最久未使用的 VM_NR_LRU_LISTS }; -typedef struct VmPhysSeg { - PADDR_T start; /* The start of physical memory area */ - size_t size; /* The size of physical memory area */ - LosVmPage *pageBase; /* The first page address of this area */ +typedef struct VmPhysSeg {//物理段描述符 + PADDR_T start; /* The start of physical memory area */ //物理内存的开始地址 + size_t size; /* The size of physical memory area */ //物理内存的大小 + LosVmPage *pageBase; /* The first page address of this area */ //本段首个物理页框地址 - SPIN_LOCK_S freeListLock; /* The buddy list spinlock */ - struct VmFreeList freeList[VM_LIST_ORDER_MAX]; /* The free pages in the buddy list */ + SPIN_LOCK_S freeListLock; /* The buddy list spinlock */ //伙伴算法自旋锁,用于操作freeList上锁 + struct VmFreeList freeList[VM_LIST_ORDER_MAX]; /* The free pages in the buddy list */ //伙伴算法的分组,默认分成10组 2^0,2^1,...,2^VM_LIST_ORDER_MAX SPIN_LOCK_S lruLock;//置换锁 size_t lruSize[VM_NR_LRU_LISTS]; //5个双循环链表大小,如此方便得到size - LOS_DL_LIST lruList[VM_NR_LRU_LISTS]; //5个双循环链表头,它们分别描述五中不同类型的链表 + LOS_DL_LIST lruList[VM_NR_LRU_LISTS]; //页面置换算法,5个双循环链表头,它们分别描述五中不同类型的链表 } LosVmPhysSeg; -struct VmPhysArea { +struct VmPhysArea {//物理区描述,仅用于方案商区划分 PADDR_T start; size_t size; }; diff --git a/kernel/base/vm/los_vm_page.c b/kernel/base/vm/los_vm_page.c index cb5153c5ebef1764ede0ecb28ff56693b9f85136..9a0f326a00b4da398ccf58d76126e71535d48a3f 100644 --- a/kernel/base/vm/los_vm_page.c +++ b/kernel/base/vm/los_vm_page.c @@ -1,111 +1,111 @@ -/* - * Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved. - * Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "los_vm_page.h" -#include "los_vm_common.h" -#include "los_vm_phys.h" -#include "los_vm_boot.h" -#include "los_vm_filemap.h" - -#ifdef __cplusplus -#if __cplusplus -extern "C" { -#endif /* __cplusplus */ -#endif /* __cplusplus */ - -LosVmPage *g_vmPageArray = NULL; -size_t g_vmPageArraySize; -//虚拟页初始化 -STATIC VOID OsVmPageInit(LosVmPage *page, paddr_t pa, UINT8 segID) -{ - LOS_ListInit(&page->node); //页节点初始化 - page->flags = FILE_PAGE_FREE; //映射文件初始标识 - LOS_AtomicSet(&page->refCounts, 0); //引用次数0 - page->physAddr = pa; //物理地址 - page->segID = segID; //物理地址使用段管理,段ID - page->order = VM_LIST_ORDER_MAX; //所属伙伴算法块组 -} - -STATIC INLINE VOID OsVmPageOrderListInit(LosVmPage *page, size_t nPages) -{ - OsVmPhysPagesFreeContiguous(page, nPages);//释放页面使可用于伙伴算法分配 -} -// page初始化 -VOID OsVmPageStartup(VOID) -{ - struct VmPhysSeg *seg = NULL; - LosVmPage *page = NULL; - paddr_t pa; - UINT32 nPage; - INT32 segID; - - OsVmPhysAreaSizeAdjust(ROUNDUP((g_vmBootMemBase - KERNEL_ASPACE_BASE), PAGE_SIZE));//校正 g_physArea size - - nPage = OsVmPhysPageNumGet();//得到 g_physArea 总页数 - g_vmPageArraySize = nPage * sizeof(LosVmPage);//页表总大小 - g_vmPageArray = (LosVmPage *)OsVmBootMemAlloc(g_vmPageArraySize);//申请页表存放区域 - - OsVmPhysAreaSizeAdjust(ROUNDUP(g_vmPageArraySize, PAGE_SIZE));// g_physArea 变小 - - OsVmPhysSegAdd();// 段页绑定 - OsVmPhysInit();// 加入空闲链表和设置置换算法,LRU(最近最久未使用)算法 - - for (segID = 0; segID < g_vmPhysSegNum; segID++) { - seg = &g_vmPhysSeg[segID]; - nPage = seg->size >> PAGE_SHIFT; - for (page = seg->pageBase, pa = seg->start; page <= seg->pageBase + nPage; - page++, pa += PAGE_SIZE) { - OsVmPageInit(page, pa, segID);//page初始化 - } - OsVmPageOrderListInit(seg->pageBase, nPage);// 页面分配的排序 - } -} -//通过物理地址获取页框 -LosVmPage *LOS_VmPageGet(PADDR_T paddr) -{ - INT32 segID; - LosVmPage *page = NULL; - - for (segID = 0; segID < g_vmPhysSegNum; segID++) {//物理内存采用段页管理 - page = OsVmPhysToPage(paddr, segID);//通过物理地址和段ID找出物理页框 - if (page != NULL) { - break; - } - } - - return page; -} - -#ifdef __cplusplus -#if __cplusplus -} -#endif /* __cplusplus */ -#endif /* __cplusplus */ +/* + * Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "los_vm_page.h" +#include "los_vm_common.h" +#include "los_vm_phys.h" +#include "los_vm_boot.h" +#include "los_vm_filemap.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +LosVmPage *g_vmPageArray = NULL; +size_t g_vmPageArraySize; +//虚拟页初始化 +STATIC VOID OsVmPageInit(LosVmPage *page, paddr_t pa, UINT8 segID) +{ + LOS_ListInit(&page->node); //页节点初始化 + page->flags = FILE_PAGE_FREE; //页标签,初始为空闲页 + LOS_AtomicSet(&page->refCounts, 0); //引用次数0 + page->physAddr = pa; //物理地址 + page->segID = segID; //物理地址使用段管理,段ID + page->order = VM_LIST_ORDER_MAX; //所属伙伴算法块组 +} + +STATIC INLINE VOID OsVmPageOrderListInit(LosVmPage *page, size_t nPages) +{ + OsVmPhysPagesFreeContiguous(page, nPages);//释放页面使可用于伙伴算法分配 +} +// page初始化 +VOID OsVmPageStartup(VOID) +{ + struct VmPhysSeg *seg = NULL; + LosVmPage *page = NULL; + paddr_t pa; + UINT32 nPage; + INT32 segID; + + OsVmPhysAreaSizeAdjust(ROUNDUP((g_vmBootMemBase - KERNEL_ASPACE_BASE), PAGE_SIZE));//校正 g_physArea size + + nPage = OsVmPhysPageNumGet();//得到 g_physArea 总页数 + g_vmPageArraySize = nPage * sizeof(LosVmPage);//页表总大小 + g_vmPageArray = (LosVmPage *)OsVmBootMemAlloc(g_vmPageArraySize);//申请页表存放区域 + + OsVmPhysAreaSizeAdjust(ROUNDUP(g_vmPageArraySize, PAGE_SIZE));// g_physArea 变小 + + OsVmPhysSegAdd();// 完成对段的初始化,将段切成一页一页 + OsVmPhysInit();// 加入空闲链表和设置置换算法,LRU(最近最久未使用)算法 + + for (segID = 0; segID < g_vmPhysSegNum; segID++) { + seg = &g_vmPhysSeg[segID]; + nPage = seg->size >> PAGE_SHIFT; + for (page = seg->pageBase, pa = seg->start; page <= seg->pageBase + nPage; + page++, pa += PAGE_SIZE) { + OsVmPageInit(page, pa, segID);//page初始化 + } + OsVmPageOrderListInit(seg->pageBase, nPage);// 页面分配的排序 + } +} +//通过物理地址获取页框 +LosVmPage *LOS_VmPageGet(PADDR_T paddr) +{ + INT32 segID; + LosVmPage *page = NULL; + + for (segID = 0; segID < g_vmPhysSegNum; segID++) {//物理内存采用段页管理 + page = OsVmPhysToPage(paddr, segID);//通过物理地址和段ID找出物理页框 + if (page != NULL) { + break; + } + } + + return page; +} + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ diff --git a/kernel/base/vm/los_vm_phys.c b/kernel/base/vm/los_vm_phys.c index f8fca82d5474ec1261f7f80b34b5bc3ac520cbf5..717d17c0fd2fabc87db3e6e7ee37233f54e050c6 100644 --- a/kernel/base/vm/los_vm_phys.c +++ b/kernel/base/vm/los_vm_phys.c @@ -41,14 +41,17 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ - +/****************************************************************************** +鸿蒙物理内存采用段页式管理 + +******************************************************************************/ #define ONE_PAGE 1 /* Physical memory area array */ -STATIC struct VmPhysArea g_physArea[] = {//这里只整了一个区域,即只生成一个段,鸿蒙物理内存采用段页式管理 +STATIC struct VmPhysArea g_physArea[] = {//这里只有一个区域,即只生成一个段 { - .start = SYS_MEM_BASE, //整个物理内存基地址 - .size = SYS_MEM_SIZE_DEFAULT,//整个物理内存总大小 + .start = SYS_MEM_BASE, //整个物理内存基地址,#define SYS_MEM_BASE DDR_MEM_ADDR , 0x80000000 + .size = SYS_MEM_SIZE_DEFAULT,//整个物理内存总大小 0x07f00000 }, }; @@ -59,21 +62,21 @@ LosVmPhysSeg *OsGVmPhysSegGet() { return g_vmPhysSeg; } -//初始化Lru置换 LRU list 在 VmPhysSeg中管理 +//初始化Lru置换链表 STATIC VOID OsVmPhysLruInit(struct VmPhysSeg *seg) { INT32 i; UINT32 intSave; - LOS_SpinInit(&seg->lruLock);//自旋锁,自旋锁用户CPU多核同步 + LOS_SpinInit(&seg->lruLock);//初始化自旋锁,自旋锁用于CPU多核同步 LOS_SpinLockSave(&seg->lruLock, &intSave); for (i = 0; i < VM_NR_LRU_LISTS; i++) { //五个双循环链表 - seg->lruSize[i] = 0; //记录链表节点数 - LOS_ListInit(&seg->lruList[i]);//初始化LRU链表 + seg->lruSize[i] = 0; //记录链表节点数 + LOS_ListInit(&seg->lruList[i]); //初始化LRU链表 } LOS_SpinUnlockRestore(&seg->lruLock, intSave); } -//创建物理段 +//创建物理段,由区划分转成段管理 STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size) { struct VmPhysSeg *seg = NULL; @@ -82,7 +85,7 @@ STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size) return -1; } - seg = &g_vmPhysSeg[g_vmPhysSegNum++]; + seg = &g_vmPhysSeg[g_vmPhysSegNum++];//拿到一段数据 for (; (seg > g_vmPhysSeg) && ((seg - 1)->start > (start + size)); seg--) { *seg = *(seg - 1); } @@ -91,15 +94,15 @@ STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size) return 0; } - +//添加物理段 VOID OsVmPhysSegAdd(VOID) { INT32 i, ret; LOS_ASSERT(g_vmPhysSegNum <= VM_PHYS_SEG_MAX); - for (i = 0; i < (sizeof(g_physArea) / sizeof(g_physArea[0])); i++) {//将g_physArea转化成段 - ret = OsVmPhysSegCreate(g_physArea[i].start, g_physArea[i].size);//一个区对应一个段 + for (i = 0; i < (sizeof(g_physArea) / sizeof(g_physArea[0])); i++) {//遍历g_physArea数组 + ret = OsVmPhysSegCreate(g_physArea[i].start, g_physArea[i].size);//由区划分转成段管理 if (ret != 0) { VM_ERR("create phys seg failed"); } @@ -115,36 +118,36 @@ VOID OsVmPhysAreaSizeAdjust(size_t size) g_physArea[i].size -= size; } } - +//获得物理内存的总页数 UINT32 OsVmPhysPageNumGet(VOID) { UINT32 nPages = 0; INT32 i; for (i = 0; i < (sizeof(g_physArea) / sizeof(g_physArea[0])); i++) { - nPages += g_physArea[i].size >> PAGE_SHIFT;//右移12位,相当于除以4K,得出总页数 + nPages += g_physArea[i].size >> PAGE_SHIFT;//右移12位,相当于除以4K, 计算出总页数 } - return nPages; + return nPages;//返回所有物理内存总页数 } -//初始化空闲链表,分配页框使用伙伴算法 +//初始化空闲链表,分配物理页框使用伙伴算法 STATIC INLINE VOID OsVmPhysFreeListInit(struct VmPhysSeg *seg) { int i; UINT32 intSave; struct VmFreeList *list = NULL; - LOS_SpinInit(&seg->freeListLock);//自旋锁 + LOS_SpinInit(&seg->freeListLock);//初始化用于分配的自旋锁 LOS_SpinLockSave(&seg->freeListLock, &intSave); for (i = 0; i < VM_LIST_ORDER_MAX; i++) { list = &seg->freeList[i]; - LOS_ListInit(&list->node);//初始化9个链表 2^0,2^1,2^2 分配页框 ^代表次方的意思 - list->listCnt = 0; + LOS_ListInit(&list->node); //初始化9个链表, 链表上挂分配大小为 2^0,2^1,2^2 ..的页框(LosVmPage) + list->listCnt = 0; //链表上的数量默认0 } LOS_SpinUnlockRestore(&seg->freeListLock, intSave); } -//段初始化 +//物理段初始化 VOID OsVmPhysInit(VOID) { struct VmPhysSeg *seg = NULL; @@ -153,13 +156,13 @@ VOID OsVmPhysInit(VOID) for (i = 0; i < g_vmPhysSegNum; i++) { seg = &g_vmPhysSeg[i]; - seg->pageBase = &g_vmPageArray[nPages];// - nPages += seg->size >> PAGE_SHIFT;//偏移12位,因以页管理,本段总页数 + seg->pageBase = &g_vmPageArray[nPages];//记录本段首页物理页框地址 + nPages += seg->size >> PAGE_SHIFT;//偏移12位,按4K一页,算出本段总页数 OsVmPhysFreeListInit(seg); //初始化空闲链表,分配页框使用伙伴算法 OsVmPhysLruInit(seg); //初始化LRU置换链表 } } -//将页框挂入空闲链表,供分配 +//将页框挂入空闲链表,分配物理内存从空闲链表里拿 STATIC VOID OsVmPhysFreeListAdd(LosVmPage *page, UINT8 order) { struct VmPhysSeg *seg = NULL; @@ -169,14 +172,14 @@ STATIC VOID OsVmPhysFreeListAdd(LosVmPage *page, UINT8 order) LOS_Panic("The page segment id(%d) is invalid\n", page->segID); } - page->order = order;// page记录 块组号 + page->order = order;// page记录伙伴算法的组序号 seg = &g_vmPhysSeg[page->segID];//先找到所属段 list = &seg->freeList[order];//找到对应List LOS_ListTailInsert(&list->node, &page->node);//将page节点挂入链表 - list->listCnt++;//链表内的节点总数++ + list->listCnt++;//链表节点总数++ } - +//同上 STATIC VOID OsVmPhysFreeListAddUnsafe(LosVmPage *page, UINT8 order) { struct VmPhysSeg *seg = NULL; @@ -193,23 +196,23 @@ STATIC VOID OsVmPhysFreeListAddUnsafe(LosVmPage *page, UINT8 order) LOS_ListTailInsert(&list->node, &page->node); list->listCnt++; } - +//将物理页框从空闲链表上摘除,见于物理页框被分配的情况 STATIC VOID OsVmPhysFreeListDelUnsafe(LosVmPage *page) { struct VmPhysSeg *seg = NULL; struct VmFreeList *list = NULL; - if ((page->segID >= VM_PHYS_SEG_MAX) || (page->order >= VM_LIST_ORDER_MAX)) { + if ((page->segID >= VM_PHYS_SEG_MAX) || (page->order >= VM_LIST_ORDER_MAX)) {//等于VM_LIST_ORDER_MAX也不行,说明伙伴算法最大支持 2^8的分配 LOS_Panic("The page segment id(%u) or order(%u) is invalid\n", page->segID, page->order); } - seg = &g_vmPhysSeg[page->segID]; - list = &seg->freeList[page->order]; - list->listCnt--; - LOS_ListDelete(&page->node); - page->order = VM_LIST_ORDER_MAX; + seg = &g_vmPhysSeg[page->segID]; //找到物理页框对应的段 + list = &seg->freeList[page->order]; //根据伙伴算法组序号找到空闲链表 + list->listCnt--; //链表节点总数减一 + LOS_ListDelete(&page->node); //将自己从链表上摘除 + page->order = VM_LIST_ORDER_MAX; //告诉系统物理页框已不在空闲链表上, 已妙用于OsVmPhysPagesSpiltUnsafe的断言 } - +//同上 STATIC VOID OsVmPhysFreeListDel(LosVmPage *page) { struct VmPhysSeg *seg = NULL; @@ -226,19 +229,24 @@ STATIC VOID OsVmPhysFreeListDel(LosVmPage *page) page->order = VM_LIST_ORDER_MAX; } +/****************************************************************************** + 本函数很像卖猪肉的,拿一大块肉剁,先把多余的放回到小块肉堆里去. + oldOrder:原本要买 2^2肉 + newOrder:却找到个 2^8肉块 +******************************************************************************/ STATIC VOID OsVmPhysPagesSpiltUnsafe(LosVmPage *page, UINT8 oldOrder, UINT8 newOrder) { UINT32 order; LosVmPage *buddyPage = NULL; - for (order = newOrder; order > oldOrder;) { - order--; - buddyPage = &page[VM_ORDER_TO_PAGES(order)]; - LOS_ASSERT(buddyPage->order == VM_LIST_ORDER_MAX); - OsVmPhysFreeListAddUnsafe(buddyPage, order); + for (order = newOrder; order > oldOrder;) {//把肉剁碎的过程,把多余的肉块切成2^7,2^6...标准块, + order--;//逐一放回仓库,一直切到最后的2^2块 + buddyPage = &page[VM_ORDER_TO_PAGES(order)];//@note_why 先把多余的肉割出来,但 没有理解是怎么做到的? + LOS_ASSERT(buddyPage->order == VM_LIST_ORDER_MAX);//@note_why 同样没理解为什么能下这个断言 + OsVmPhysFreeListAddUnsafe(buddyPage, order);//将劈开的节点挂到对应序号的链表上 } } -//通过物理地址获取所属页面 +//通过物理地址获取所属物理页框 LosVmPage *OsVmPhysToPage(paddr_t pa, UINT8 segID) { struct VmPhysSeg *seg = NULL; @@ -252,7 +260,7 @@ LosVmPage *OsVmPhysToPage(paddr_t pa, UINT8 segID) return NULL; } - offset = pa - seg->start;//得到偏移地址 + offset = pa - seg->start;//得到物理地址的偏移量 return (seg->pageBase + (offset >> PAGE_SHIFT));//得到第n页page } @@ -286,7 +294,7 @@ LosVmPage *OsVmVaddrToPage(VOID *ptr) return NULL; } -//从段中分配指定页框数 +//从参数段中分配参数页数 LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages) { struct VmFreeList *list = NULL; @@ -297,22 +305,22 @@ LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages) if ((seg == NULL) || (nPages == 0)) { return NULL; } - + //因为伙伴算法分配单元是 1,2,4,8 页,比如nPages = 3时,就需要从 4号空闲链表中分,剩余的1页需要劈开放到1号空闲链表中 order = OsVmPagesToOrder(nPages);//根据页数计算出用哪个块组 if (order < VM_LIST_ORDER_MAX) {//order不能大于9 即:256*4K = 1M 可理解为向内核堆申请内存一次不能超过1M for (newOrder = order; newOrder < VM_LIST_ORDER_MAX; newOrder++) {//没有就找更大块 list = &seg->freeList[newOrder];//从最合适的块处开始找 - if (LOS_ListEmpty(&list->node)) {//没找到 + if (LOS_ListEmpty(&list->node)) {//理想情况链表为空,说明没找到 continue;//继续找更大块的 } - page = LOS_DL_LIST_ENTRY(LOS_DL_LIST_FIRST(&list->node), LosVmPage, node);//找到 + page = LOS_DL_LIST_ENTRY(LOS_DL_LIST_FIRST(&list->node), LosVmPage, node);//找第一个节点就行,因为链表上挂的都是同样大小物理页框 goto DONE; } } return NULL; DONE: - OsVmPhysFreeListDelUnsafe(page); - OsVmPhysPagesSpiltUnsafe(page, order, newOrder); + OsVmPhysFreeListDelUnsafe(page);//将物理页框从链表上摘出来 + OsVmPhysPagesSpiltUnsafe(page, order, newOrder);//将物理页框劈开,把用不了的页再挂到对应的空闲链表上 return page; } //释放物理页,所谓释放物理页就是把页挂到空闲链表中 diff --git a/zzz/git/push.sh b/zzz/git/push.sh index 973750ba7b22568deb66187c9d6671d43066e048..501615a43b3dfa1f93c80f145a9200aaf57da1c3 100644 --- a/zzz/git/push.sh +++ b/zzz/git/push.sh @@ -1,5 +1,5 @@ git add -A -git commit -m '文件如何被分页读到页高速缓存,脏页数据又如何回写? +git commit -m '注解物理内存是如何管理的?伙伴算法/LRU如何分配/置换物理页框? 搜索 @note_pic 可以查看全部字符图 搜索 @note_why 是注者尚未看明白的地方,如果您看明白了,请告诉注者完善 搜索 @note_thinking 是注者的思考和吐槽的地方 diff --git "a/zzz/pic/turing/\347\211\251\347\220\206\351\241\265\346\241\206\344\270\216\347\211\251\347\220\206\345\206\205\345\255\230\345\205\263\347\263\273\345\233\276.png" "b/zzz/pic/turing/\347\211\251\347\220\206\351\241\265\346\241\206\344\270\216\347\211\251\347\220\206\345\206\205\345\255\230\345\205\263\347\263\273\345\233\276.png" new file mode 100644 index 0000000000000000000000000000000000000000..15c6257efc7c96994a50423fdfc8aea1fb2a675f Binary files /dev/null and "b/zzz/pic/turing/\347\211\251\347\220\206\351\241\265\346\241\206\344\270\216\347\211\251\347\220\206\345\206\205\345\255\230\345\205\263\347\263\273\345\233\276.png" differ