From 0ebba54c565da641bc90b7bdfa172916c0b07124 Mon Sep 17 00:00:00 2001 From: kuangyufei Date: Tue, 20 Oct 2020 19:25:43 +0800 Subject: [PATCH] =?UTF-8?q?=E9=B8=BF=E8=92=99=E5=86=85=E6=A0=B8=E6=BA=90?= =?UTF-8?q?=E7=A0=81=E5=88=86=E6=9E=90=E7=B3=BB=E5=88=97=E7=AF=87=20https:?= =?UTF-8?q?//blog.csdn.net/kuangyufei?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/base/include/los_vm_map.h | 20 +++---- kernel/base/include/los_vm_page.h | 4 +- kernel/base/include/los_vm_phys.h | 6 +- kernel/base/mem/bestfit/los_memory.c | 2 +- kernel/base/vm/los_vm_boot.c | 6 +- kernel/base/vm/los_vm_page.c | 4 +- kernel/base/vm/los_vm_phys.c | 82 ++++++++++++++-------------- wtest/main.c | 2 + wtest/push.sh | 3 + 9 files changed, 67 insertions(+), 62 deletions(-) create mode 100644 wtest/push.sh diff --git a/kernel/base/include/los_vm_map.h b/kernel/base/include/los_vm_map.h index fce961c2..f4c85811 100644 --- a/kernel/base/include/los_vm_map.h +++ b/kernel/base/include/los_vm_map.h @@ -171,10 +171,10 @@ typedef struct VmSpace { #define VM_MAP_REGION_FLAG_FLAG_MASK (3<<7) //掩码用途 #define VM_MAP_REGION_FLAG_STACK (1<<9) //栈区 #define VM_MAP_REGION_FLAG_HEAP (1<<10) //堆区 -#define VM_MAP_REGION_FLAG_DATA (1<<11) //数据区 +#define VM_MAP_REGION_FLAG_DATA (1<<11) //data数据区 编译在ELF中 #define VM_MAP_REGION_FLAG_TEXT (1<<12) //代码区 -#define VM_MAP_REGION_FLAG_BSS (1<<13) //bbs数据区 -#define VM_MAP_REGION_FLAG_VDSO (1<<14) //映射区 +#define VM_MAP_REGION_FLAG_BSS (1<<13) //bbs数据区 由运行时动态分配 +#define VM_MAP_REGION_FLAG_VDSO (1<<14) //虚拟动态链接对象(Virtual Dynamically Shared Object、vDSO #define VM_MAP_REGION_FLAG_MMAP (1<<15) //映射区 #define VM_MAP_REGION_FLAG_SHM (1<<16) //共享内存区 #define VM_MAP_REGION_FLAG_INVALID (1<<17) /* indicates that flags are not specified */ @@ -224,7 +224,7 @@ STATIC INLINE BOOL LOS_IsRegionPermUserReadOnly(LosVmMapRegion* region) return ((region->regionFlags & VM_MAP_REGION_FLAG_PROT_MASK) == (VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ)); } -//私有线性区 +//是否为私有线性区 STATIC INLINE BOOL LOS_IsRegionFlagPrivateOnly(LosVmMapRegion* region) { return ((region->regionFlags & VM_MAP_REGION_FLAG_FLAG_MASK) == VM_MAP_REGION_FLAG_PRIVATE); @@ -234,33 +234,33 @@ STATIC INLINE VOID LOS_SetRegionTypeFile(LosVmMapRegion* region) { region->regionType = VM_MAP_REGION_TYPE_FILE; } - +//是否为设备映射线性区 STATIC INLINE BOOL LOS_IsRegionTypeDev(LosVmMapRegion* region) { return region->regionType == VM_MAP_REGION_TYPE_DEV; } - +//设为设备映射线性区 STATIC INLINE VOID LOS_SetRegionTypeDev(LosVmMapRegion* region) { region->regionType = VM_MAP_REGION_TYPE_DEV; } - +//是否为匿名swap映射线性区 STATIC INLINE BOOL LOS_IsRegionTypeAnon(LosVmMapRegion* region) { return region->regionType == VM_MAP_REGION_TYPE_ANON; } - +//设为匿名swap映射线性区 STATIC INLINE VOID LOS_SetRegionTypeAnon(LosVmMapRegion* region) { region->regionType = VM_MAP_REGION_TYPE_ANON; } - +//虚拟地址是否在用户空间 STATIC INLINE BOOL LOS_IsUserAddress(VADDR_T vaddr) { return ((vaddr >= USER_ASPACE_BASE) && (vaddr <= (USER_ASPACE_BASE + (USER_ASPACE_SIZE - 1)))); } - +//从vaddr 到 vaddr + len 这段虚拟地址是否在用户空间 STATIC INLINE BOOL LOS_IsUserAddressRange(VADDR_T vaddr, size_t len) { return (vaddr + len > vaddr) && LOS_IsUserAddress(vaddr) && (LOS_IsUserAddress(vaddr + len - 1)); diff --git a/kernel/base/include/los_vm_page.h b/kernel/base/include/los_vm_page.h index 2fbde278..e787c737 100644 --- a/kernel/base/include/los_vm_page.h +++ b/kernel/base/include/los_vm_page.h @@ -54,8 +54,8 @@ typedef struct VmPage { UINT16 nPages; /**< the vm page is used for kernel heap */ } LosVmPage; -extern LosVmPage *g_vmPageArray;//物理内存所有页记录数组 -extern size_t g_vmPageArraySize;//物理内存总页数 +extern LosVmPage *g_vmPageArray;//物理内存所有页框(page frame)记录数组 +extern size_t g_vmPageArraySize;//物理内存总页框(page frame)数 LosVmPage *LOS_VmPageGet(PADDR_T paddr); VOID OsVmPageStartup(VOID); diff --git a/kernel/base/include/los_vm_phys.h b/kernel/base/include/los_vm_phys.h index 110afb5a..58de4424 100644 --- a/kernel/base/include/los_vm_phys.h +++ b/kernel/base/include/los_vm_phys.h @@ -52,12 +52,12 @@ extern "C" { #define VM_PAGE_TO_PHYS(page) (page->physAddr)//获取页面物理地址 #define VM_ORDER_TO_PAGES(order) (1 << (order))//伙伴算法由order 定位到该块组的页面单位,例如:order=2时,page[4] -#define VM_ORDER_TO_PHYS(order) (1 << (PAGE_SHIFT + (order)))//通过order找物理地址 +#define VM_ORDER_TO_PHYS(order) (1 << (PAGE_SHIFT + (order)))//跳块例如 order=2 就是跳4页 #define VM_PHYS_TO_ORDER(phys) (min(LOS_LowBitGet((phys) >> PAGE_SHIFT), VM_LIST_ORDER_MAX - 1))//通过物理地址定位到order struct VmFreeList { - LOS_DL_LIST node; - UINT32 listCnt; + LOS_DL_LIST node; //双循环链表 + UINT32 listCnt; //双循环链表节点总数 }; //针对匿名页和文件页各拆分成一个活跃,一个不活跃的链表。 enum OsLruList { diff --git a/kernel/base/mem/bestfit/los_memory.c b/kernel/base/mem/bestfit/los_memory.c index 29d5e6c2..11ce3198 100644 --- a/kernel/base/mem/bestfit/los_memory.c +++ b/kernel/base/mem/bestfit/los_memory.c @@ -1561,7 +1561,7 @@ STATIC INLINE INT32 OsMemPoolExpand(VOID *pool, UINT32 size, UINT32 intSave) endNode = (LosMemDynNode *)OS_MEM_END_NODE(pool, poolInfo->poolSize); RETRY: - newNode = (LosMemDynNode *)LOS_PhysPagesAllocContiguous(size >> PAGE_SHIFT); + newNode = (LosMemDynNode *)LOS_PhysPagesAllocContiguous(size >> PAGE_SHIFT);//分配连续的物理内存 if (newNode == NULL) { if (tryCount > 0) { tryCount--; diff --git a/kernel/base/vm/los_vm_boot.c b/kernel/base/vm/los_vm_boot.c index 4bdd1638..d8fd2538 100644 --- a/kernel/base/vm/los_vm_boot.c +++ b/kernel/base/vm/los_vm_boot.c @@ -44,9 +44,9 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ -UINTPTR g_vmBootMemBase = (UINTPTR)&__bss_end;//内核空间的 +UINTPTR g_vmBootMemBase = (UINTPTR)&__bss_end;//内核空间可用于分配的区域 BOOL g_kHeapInited = FALSE;//内核堆区初始化变量 - +//虚拟内存区间检查, 需理解 los_vm_zone.h 中画出的鸿蒙虚拟内存全景图 UINT32 OsVmAddrCheck(size_t tempAddr, size_t length) { if ((tempAddr >= KERNEL_VMM_BASE) && ((tempAddr + length) <= (PERIPH_UNCACHED_BASE + PERIPH_UNCACHED_SIZE))) { @@ -60,7 +60,7 @@ VOID *OsVmBootMemAlloc(size_t len) { UINTPTR ptr; - if (g_kHeapInited) {//g_kHeapInited 在什么时候会变成 true?没找到代码 + if (g_kHeapInited) {// ??? g_kHeapInited 在什么时候会变成 true,没找到代码 VM_ERR("kernel heap has been inited, should not to use boot mem alloc!"); return NULL; } diff --git a/kernel/base/vm/los_vm_page.c b/kernel/base/vm/los_vm_page.c index f44e079a..edeb7416 100644 --- a/kernel/base/vm/los_vm_page.c +++ b/kernel/base/vm/los_vm_page.c @@ -94,8 +94,8 @@ LosVmPage *LOS_VmPageGet(PADDR_T paddr) INT32 segID; LosVmPage *page = NULL; - for (segID = 0; segID < g_vmPhysSegNum; segID++) { - page = OsVmPhysToPage(paddr, segID); + for (segID = 0; segID < g_vmPhysSegNum; segID++) {//物理内存采用段页管理 + page = OsVmPhysToPage(paddr, segID);//通过物理地址和段ID找出物理页框 if (page != NULL) { break; } diff --git a/kernel/base/vm/los_vm_phys.c b/kernel/base/vm/los_vm_phys.c index f8c0a8fd..fc21e357 100644 --- a/kernel/base/vm/los_vm_phys.c +++ b/kernel/base/vm/los_vm_phys.c @@ -45,35 +45,35 @@ extern "C" { #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,//整个物理内存总大小 }, }; -struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX];//32段 -INT32 g_vmPhysSegNum = 0; - +struct VmPhysSeg g_vmPhysSeg[VM_PHYS_SEG_MAX];//最大32段 +INT32 g_vmPhysSegNum = 0; //段数 +//获取段数组,全局变量,变量放在 .bbs 区 LosVmPhysSeg *OsGVmPhysSegGet() { return g_vmPhysSeg; } - +//初始化Lru置换 LRU list 在 VmPhysSeg中管理 STATIC VOID OsVmPhysLruInit(struct VmPhysSeg *seg) { INT32 i; UINT32 intSave; - LOS_SpinInit(&seg->lruLock); + 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]); + for (i = 0; i < VM_NR_LRU_LISTS; i++) { //五个双循环链表 + 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; @@ -98,14 +98,14 @@ VOID OsVmPhysSegAdd(VOID) LOS_ASSERT(g_vmPhysSegNum <= VM_PHYS_SEG_MAX); - for (i = 0; i < (sizeof(g_physArea) / sizeof(g_physArea[0])); i++) { + 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"); } } } - +//段区域大小调整 VOID OsVmPhysAreaSizeAdjust(size_t size) { INT32 i; @@ -127,24 +127,24 @@ UINT32 OsVmPhysPageNumGet(VOID) 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); + LOS_ListInit(&list->node);//初始化9个链表 2|0,2|1,2|2 分配页框 |代表次方的意思 list->listCnt = 0; } LOS_SpinUnlockRestore(&seg->freeListLock, intSave); } - +//段初始化 VOID OsVmPhysInit(VOID) { struct VmPhysSeg *seg = NULL; @@ -153,13 +153,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; - OsVmPhysFreeListInit(seg); - OsVmPhysLruInit(seg); + seg->pageBase = &g_vmPageArray[nPages];// + nPages += seg->size >> PAGE_SHIFT;//偏移12位,因以页管理,本段总页数 + OsVmPhysFreeListInit(seg); //初始化空闲链表,分配页框使用伙伴算法 + OsVmPhysLruInit(seg); //初始化LRU置换链表 } } - +//将页框挂入空闲链表,供分配 STATIC VOID OsVmPhysFreeListAdd(LosVmPage *page, UINT8 order) { struct VmPhysSeg *seg = NULL; @@ -169,12 +169,12 @@ STATIC VOID OsVmPhysFreeListAdd(LosVmPage *page, UINT8 order) LOS_Panic("The page segment id(%d) is invalid\n", page->segID); } - page->order = order; - seg = &g_vmPhysSeg[page->segID]; + page->order = order;// page记录 块组号 + seg = &g_vmPhysSeg[page->segID];//先找到所属段 - list = &seg->freeList[order]; - LOS_ListTailInsert(&list->node, &page->node); - list->listCnt++; + list = &seg->freeList[order];//找到对应List + LOS_ListTailInsert(&list->node, &page->node);//将page节点挂入链表 + list->listCnt++;//链表内的节点总数++ } STATIC VOID OsVmPhysFreeListAddUnsafe(LosVmPage *page, UINT8 order) @@ -264,23 +264,23 @@ VOID *OsVmPageToVaddr(LosVmPage *page)// //内核空间的vmPage是不会被置换的,所以是常驻内存,内核空间初始化mmu时就映射好了L1表 return (VOID *)(UINTPTR)vaddr; } - +//通过虚拟地址找映射的物理页框 LosVmPage *OsVmVaddrToPage(VOID *ptr) { struct VmPhysSeg *seg = NULL; - PADDR_T pa = LOS_PaddrQuery(ptr); + PADDR_T pa = LOS_PaddrQuery(ptr);//通过虚拟地址查询物理地址 UINT32 segID; for (segID = 0; segID < g_vmPhysSegNum; segID++) { seg = &g_vmPhysSeg[segID]; if ((pa >= seg->start) && (pa < (seg->start + seg->size))) { - return seg->pageBase + ((pa - seg->start) >> PAGE_SHIFT); + return seg->pageBase + ((pa - seg->start) >> PAGE_SHIFT);//段基地址+页偏移索引 得到虚拟地址经映射所在物理页框 } } return NULL; } - +//从段中分配指定页框数 LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages) { struct VmFreeList *list = NULL; @@ -293,7 +293,7 @@ LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages) } order = OsVmPagesToOrder(nPages);//根据页数计算出用哪个块组 - if (order < VM_LIST_ORDER_MAX) { + 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)) {//没找到 @@ -309,7 +309,7 @@ DONE: OsVmPhysPagesSpiltUnsafe(page, order, newOrder); return page; } - +//释放物理页,所谓释放物理页就是把页挂到空闲链表中 VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order) { paddr_t pa; @@ -320,14 +320,14 @@ VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order) } if (order < VM_LIST_ORDER_MAX - 1) {//order[0,7] - pa = VM_PAGE_TO_PHYS(page); + pa = VM_PAGE_TO_PHYS(page);//获取物理地址 do { - pa ^= VM_ORDER_TO_PHYS(order); - buddyPage = OsVmPhysToPage(pa, page->segID); + pa ^= VM_ORDER_TO_PHYS(order);//注意这里是高位和低位的^=,也就是说跳到 order块组 物理地址处,此处处理甚妙! + buddyPage = OsVmPhysToPage(pa, page->segID);//如此就能拿到以2的order次方跳的buddyPage if ((buddyPage == NULL) || (buddyPage->order != order)) { break; } - OsVmPhysFreeListDel(buddyPage); + OsVmPhysFreeListDel(buddyPage);//注意buddypage是连续的物理页框 例如order=2时,连续的4页就是一个块组 |_|_|_|_| order++; pa &= ~(VM_ORDER_TO_PHYS(order) - 1); page = OsVmPhysToPage(pa, page->segID); @@ -363,7 +363,7 @@ VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages) page += n; } } - +//获取一定数量的页框 STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages) { UINT32 intSave; @@ -378,11 +378,11 @@ STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages) for (segID = 0; segID < g_vmPhysSegNum; segID++) { seg = &g_vmPhysSeg[segID]; LOS_SpinLockSave(&seg->freeListLock, &intSave); - page = OsVmPhysPagesAlloc(seg, nPages); + page = OsVmPhysPagesAlloc(seg, nPages);//分配指定页数的物理页, 可分析出 nPages 不能大于 256个 if (page != NULL) { /* */ LOS_AtomicSet(&page->refCounts, 0);//设置引用次数为0 - page->nPages = nPages; + page->nPages = nPages;//页数 LOS_SpinUnlockRestore(&seg->freeListLock, intSave); return page; } @@ -398,7 +398,7 @@ VOID *LOS_PhysPagesAllocContiguous(size_t nPages) if (nPages == 0) { return NULL; } - + //鸿蒙 nPages 不能大于 2的8 次方,即256个页,1M内存,仅限于内核态,用户态不限制分配大小. page = OsVmPhysPagesGet(nPages);//通过伙伴算法获取物理上连续的页 if (page == NULL) { return NULL; @@ -542,7 +542,7 @@ struct VmPhysSeg *OsVmPhysSegGet(LosVmPage *page) return (OsGVmPhysSegGet() + page->segID); } - +//通过总页数 ,获取块组 ,例如需要分配 8个页,返回就是 3 ,例如 1023个 返回就是 10 UINT32 OsVmPagesToOrder(size_t nPages) { UINT32 order; diff --git a/wtest/main.c b/wtest/main.c index 58d7f830..e1b635a3 100644 --- a/wtest/main.c +++ b/wtest/main.c @@ -5,6 +5,8 @@ typedef unsigned long PTE_T; typedef unsigned long VADDR_T; #define IS_ALIGNED(a, b) (!(((UINTPTR)(a)) & (((UINTPTR)(b)) - 1))) +//鸿蒙内核源码分析系列篇 https://blog.csdn.net/kuangyufei + void b(){ UINT8 w[3]={0}; PTE_T pte1BasePtr = 0x11100000; diff --git a/wtest/push.sh b/wtest/push.sh new file mode 100644 index 00000000..6a53ad5e --- /dev/null +++ b/wtest/push.sh @@ -0,0 +1,3 @@ +git add -A +git commit -m "鸿蒙内核源码分析系列篇 https://blog.csdn.net/kuangyufei" +git push -- GitLab