自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

鴻蒙輕內(nèi)核A核源碼分析系列三 物理內(nèi)存之二

開發(fā) 前端
本文首先了解了物理內(nèi)存管理的結(jié)構(gòu)體,接著閱讀了物理內(nèi)存如何初始化,然后分析了物理內(nèi)存的申請、釋放和查詢等操作接口的源代碼。

[[433913]]

想了解更多內(nèi)容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com

3.1.2.3 函數(shù)OsVmPhysLargeAlloc

當執(zhí)行到這個函數(shù)時,說明空閑鏈表上的單個內(nèi)存頁節(jié)點的大小已經(jīng)不能滿足要求,超過了第9個鏈表上的內(nèi)存頁節(jié)點的大小了。⑴處計算需要申請的內(nèi)存大小。⑵從最大的鏈表上進行遍歷每一個內(nèi)存頁節(jié)點。⑶根據(jù)每個內(nèi)存頁的開始內(nèi)存地址,計算需要的內(nèi)存的結(jié)束地址,如果超過內(nèi)存段的大小,則繼續(xù)遍歷下一個內(nèi)存頁節(jié)點。

⑷處此時paStart表示當前內(nèi)存頁的結(jié)束地址,接下來paStart >= paEnd表示當前內(nèi)存頁的大小滿足申請的需求;paStart < seg->start和paStart >= (seg->start + seg->size)發(fā)生溢出錯誤,內(nèi)存頁結(jié)束地址不在內(nèi)存段的地址范圍內(nèi)。⑸處表示當前內(nèi)存頁的下一個內(nèi)存頁結(jié)構(gòu)體,如果該結(jié)構(gòu)體不在空閑鏈表上,則break跳出循環(huán)。如果在空閑鏈表上,表示連續(xù)的空閑內(nèi)存頁會拼接起來,滿足大內(nèi)存申請的需要。⑹表示一個或者多個連續(xù)的內(nèi)存頁的大小滿足申請需求。

  1. STATIC LosVmPage *OsVmPhysLargeAlloc(struct VmPhysSeg *seg, size_t nPages) 
  2.     struct VmFreeList *list = NULL
  3.     LosVmPage *page = NULL
  4.     LosVmPage *tmp = NULL
  5.     PADDR_T paStart; 
  6.     PADDR_T paEnd; 
  7. ⑴  size_t size = nPages << PAGE_SHIFT; 
  8.  
  9. ⑵  list = &seg->freeList[VM_LIST_ORDER_MAX - 1]; 
  10.     LOS_DL_LIST_FOR_EACH_ENTRY(page, &list->node, LosVmPage, node) { 
  11. ⑶      paStart = page->physAddr; 
  12.         paEnd = paStart + size
  13.         if (paEnd > (seg->start + seg->size)) { 
  14.             continue
  15.         } 
  16.  
  17.         for (;;) { 
  18. ⑷          paStart += PAGE_SIZE << (VM_LIST_ORDER_MAX - 1); 
  19.             if ((paStart >= paEnd) || (paStart < seg->start) || 
  20.                 (paStart >= (seg->start + seg->size))) { 
  21.                 break; 
  22.             } 
  23. ⑸          tmp = &seg->pageBase[(paStart - seg->start) >> PAGE_SHIFT]; 
  24.             if (tmp->order != (VM_LIST_ORDER_MAX - 1)) { 
  25.                 break; 
  26.             } 
  27.         } 
  28. ⑹      if (paStart >= paEnd) { 
  29.             return page; 
  30.         } 
  31.     } 
  32.  
  33.     return NULL

3.1.2.4 函數(shù)OsVmPhysFreeListDelUnsafe和OsVmPhysFreeListAddUnsafe

內(nèi)部函數(shù)OsVmPhysFreeListDelUnsafe用于從空閑內(nèi)存頁節(jié)點鏈表上刪除一個內(nèi)存頁節(jié)點,名稱中有Unsafe字樣,是因為函數(shù)體內(nèi)并沒有對鏈表操作加自旋鎖,安全性由外部調(diào)用函數(shù)保證。⑴處進行校驗,確保內(nèi)存段和空閑鏈表索引符合要求。⑵處獲取內(nèi)存段和空閑鏈表,⑶處空閑鏈表上內(nèi)存頁節(jié)點數(shù)目減1,并把內(nèi)存塊從空閑鏈表上刪除。⑷處設(shè)置內(nèi)存頁的order索引值為最大值來標記非空閑內(nèi)存頁。

  1. STATIC VOID OsVmPhysFreeListDelUnsafe(LosVmPage *page) 
  2.     struct VmPhysSeg *seg = NULL
  3.     struct VmFreeList *list = NULL
  4.  
  5. ⑴  if ((page->segID >= VM_PHYS_SEG_MAX) || (page->order >= VM_LIST_ORDER_MAX)) { 
  6.         LOS_Panic("The page segment id(%u) or order(%u) is invalid\n", page->segID, page->order); 
  7.     } 
  8.  
  9. ⑵  seg = &g_vmPhysSeg[page->segID]; 
  10.     list = &seg->freeList[page->order]; 
  11. ⑶  list->listCnt--; 
  12.     LOS_ListDelete(&page->node); 
  13. ⑷  page->order = VM_LIST_ORDER_MAX; 

和空閑鏈表上刪除對應(yīng)的函數(shù)是空閑鏈表上插入空閑內(nèi)存頁節(jié)點函數(shù)OsVmPhysFreeListAddUnsafe。⑴處更新內(nèi)存頁的要掛載的空閑鏈表的索引值,然后獲取內(nèi)存頁所在的內(nèi)存段seg,并獲取索引值對應(yīng)的空閑鏈表。執(zhí)行⑵把空閑內(nèi)存頁節(jié)點插入到空閑鏈表并更新節(jié)點數(shù)目。

  1. STATIC VOID OsVmPhysFreeListAddUnsafe(LosVmPage *page, UINT8 order
  2.     struct VmPhysSeg *seg = NULL
  3.     struct VmFreeList *list = NULL
  4.  
  5.     if (page->segID >= VM_PHYS_SEG_MAX) { 
  6.         LOS_Panic("The page segment id(%d) is invalid\n", page->segID); 
  7.     } 
  8.  
  9. ⑴  page->order = order
  10.     seg = &g_vmPhysSeg[page->segID]; 
  11.  
  12.     list = &seg->freeList[order]; 
  13. ⑵   LOS_ListTailInsert(&list->node, &page->node); 
  14.     list->listCnt++; 

3.1.2.5 函數(shù)OsVmPhysPagesSpiltUnsafe

函數(shù)OsVmPhysPagesSpiltUnsafe用于分割內(nèi)存塊,參數(shù)中oldOrder表示需要申請的內(nèi)存頁節(jié)點對應(yīng)的鏈表索引,newOrder表示實際申請的內(nèi)存頁節(jié)點對應(yīng)的鏈表索引。如果索引值相等,則不需要拆分,不會執(zhí)行for循環(huán)塊的代碼。由于伙伴算法中的鏈表數(shù)組中元素的特點,即每個鏈表中的內(nèi)存頁節(jié)點的大小等于2的冪次方個內(nèi)存頁。在拆分時,依次從高索引newOrder往低索引oldOrder遍歷,拆分一個內(nèi)存頁節(jié)點作為空閑內(nèi)存頁節(jié)點掛載到對應(yīng)的空閑鏈表上。⑴處開始循環(huán)從高索引到低索引,索引值減1,然后執(zhí)行⑵獲取伙伴內(nèi)存頁節(jié)點,可以看出,申請的內(nèi)存塊大于需求時,會把后半部分的高地址部分放入空閑鏈表,保留前半部分的低地址部分。⑶處的斷言確?;锇閮?nèi)存頁節(jié)點索引值是最大值,表示屬于空閑內(nèi)存頁節(jié)點。⑷處調(diào)用函數(shù)把內(nèi)存頁節(jié)點放入空閑鏈表。

  1. STATIC VOID OsVmPhysPagesSpiltUnsafe(LosVmPage *page, UINT8 oldOrder, UINT8 newOrder) 
  2.     UINT32 order
  3.     LosVmPage *buddyPage = NULL
  4.  
  5.     for (order = newOrder; order > oldOrder;) { 
  6. ⑴      order--; 
  7. ⑵      buddyPage = &page[VM_ORDER_TO_PAGES(order)]; 
  8. ⑶      LOS_ASSERT(buddyPage->order == VM_LIST_ORDER_MAX); 
  9. ⑷      OsVmPhysFreeListAddUnsafe(buddyPage, order); 
  10.     } 

這里有必要放這一張圖,直觀演示一下。假如我們需要申請8個內(nèi)存頁大小的內(nèi)存節(jié)點,但是只有freeList[7]鏈表上才有空閑節(jié)點。申請成功后,超過了應(yīng)用需要的大小,需要進行拆分。把27個內(nèi)存頁分為2份大小為26個內(nèi)存頁的節(jié)點,第一份繼續(xù)拆分,第二份掛載到freeList[6]鏈表上。然后把第一份26個內(nèi)存頁拆分為2個25個內(nèi)存頁節(jié)點,第一份繼續(xù)拆分,第二份掛載到freeList[5]鏈表上。依次進行下去,最后拆分為2份2^3個內(nèi)存頁大小的內(nèi)存頁節(jié)點,第一份作為實際申請的內(nèi)存頁返回,第二份掛載到freeList[3]鏈表上。如下圖紅色部分所示。

鴻蒙輕內(nèi)核A核源碼分析系列三 物理內(nèi)存(2)-鴻蒙HarmonyOS技術(shù)社區(qū)

另外,函數(shù)OsVmRecycleExtraPages會調(diào)用OsVmPhysPagesFreeContiguous來回收申請的多余的內(nèi)存頁,后文再分析。

3.2 釋放物理內(nèi)存頁接口

3.2.1 釋放物理內(nèi)存頁接口介紹

和申請物理內(nèi)存頁接口相對應(yīng)著,釋放物理內(nèi)存頁的接口有3個,分別用于滿足不同的釋放內(nèi)存頁需求。函數(shù)LOS_PhysPagesFreeContiguous的傳入?yún)?shù)為要釋放物理頁對應(yīng)的內(nèi)核虛擬地址空間中的虛擬內(nèi)存地址和內(nèi)存頁數(shù)目。⑴處調(diào)用函數(shù)OsVmVaddrToPage把虛擬內(nèi)存地址轉(zhuǎn)換為物理內(nèi)存頁結(jié)構(gòu)體地址,然后⑵處把內(nèi)存頁的連續(xù)內(nèi)存頁數(shù)目設(shè)置為0。⑶處調(diào)用函數(shù)OsVmPhysPagesFreeContiguous()釋放物理內(nèi)存頁。函數(shù)LOS_PhysPageFree用于釋放一個物理內(nèi)存頁,傳入?yún)?shù)為要釋放的物理頁對應(yīng)的物理頁結(jié)構(gòu)體地址。⑷處對引用計數(shù)自減,當小于等于0,表示沒有其他引用時才進一步執(zhí)行釋放操作。該函數(shù)同樣會調(diào)用函數(shù)OsVmPhysPagesFreeContiguous()釋放物理內(nèi)存頁。函數(shù)LOS_PhysPagesFree用于釋放掛在雙向鏈表上的多個物理內(nèi)存頁,返回值為實際釋放的物理頁數(shù)目。⑸處遍歷內(nèi)存頁雙向鏈表,從鏈表上移除要釋放的內(nèi)存頁節(jié)點。⑹處代碼和釋放一個內(nèi)存頁的函數(shù)代碼相同。⑺處計算遍歷的內(nèi)存頁的數(shù)目,函數(shù)最后會返回該值。

  1. VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages) 
  2.     UINT32 intSave; 
  3.     struct VmPhysSeg *seg = NULL
  4.     LosVmPage *page = NULL
  5.  
  6.     if (ptr == NULL) { 
  7.         return
  8.     } 
  9.  
  10. ⑴   page = OsVmVaddrToPage(ptr); 
  11.     if (page == NULL) { 
  12.         VM_ERR("vm page of ptr(%#x) is null", ptr); 
  13.         return
  14.     } 
  15. ⑵  page->nPages = 0; 
  16.  
  17.     seg = &g_vmPhysSeg[page->segID]; 
  18.     LOS_SpinLockSave(&seg->freeListLock, &intSave); 
  19.  
  20. ⑶   OsVmPhysPagesFreeContiguous(page, nPages); 
  21.  
  22.     LOS_SpinUnlockRestore(&seg->freeListLock, intSave); 
  23.  
  24. ...... 
  25.      
  26. VOID LOS_PhysPageFree(LosVmPage *page) 
  27.     UINT32 intSave; 
  28.     struct VmPhysSeg *seg = NULL
  29.  
  30.     if (page == NULL) { 
  31.         return
  32.     } 
  33.  
  34. ⑷  if (LOS_AtomicDecRet(&page->refCounts) <= 0) { 
  35.         seg = &g_vmPhysSeg[page->segID]; 
  36.         LOS_SpinLockSave(&seg->freeListLock, &intSave); 
  37.  
  38.         OsVmPhysPagesFreeContiguous(page, ONE_PAGE); 
  39.         LOS_AtomicSet(&page->refCounts, 0); 
  40.  
  41.         LOS_SpinUnlockRestore(&seg->freeListLock, intSave); 
  42.     } 
  43. ······ 
  44. size_t LOS_PhysPagesFree(LOS_DL_LIST *list) 
  45.     UINT32 intSave; 
  46.     LosVmPage *page = NULL
  47.     LosVmPage *nPage = NULL
  48.     LosVmPhysSeg *seg = NULL
  49.     size_t count = 0; 
  50.  
  51.     if (list == NULL) { 
  52.         return 0; 
  53.     } 
  54.  
  55.     LOS_DL_LIST_FOR_EACH_ENTRY_SAFE(page, nPage, list, LosVmPage, node) { 
  56. ⑸      LOS_ListDelete(&page->node); 
  57. ⑹      if (LOS_AtomicDecRet(&page->refCounts) <= 0) { 
  58.             seg = &g_vmPhysSeg[page->segID]; 
  59.             LOS_SpinLockSave(&seg->freeListLock, &intSave); 
  60.             OsVmPhysPagesFreeContiguous(page, ONE_PAGE); 
  61.             LOS_AtomicSet(&page->refCounts, 0); 
  62.             LOS_SpinUnlockRestore(&seg->freeListLock, intSave); 
  63.         } 
  64. ⑺      count++; 
  65.     } 
  66.  
  67.     return count

3.2.2 釋放物理內(nèi)存頁內(nèi)部接口實現(xiàn)

3.2.2.1 函數(shù)OsVmVaddrToPage

函數(shù)OsVmVaddrToPage把虛擬內(nèi)存地址轉(zhuǎn)換為物理頁結(jié)構(gòu)體地址。⑴處調(diào)用函數(shù)LOS_PaddrQuery()把虛擬地址轉(zhuǎn)為物理地址,該函數(shù)在虛實映射部分會詳細講述。⑵處遍歷物理內(nèi)存段,如果物理內(nèi)存地址處于物理內(nèi)存段的地址范圍,則可以返回該物理地址對應(yīng)的物理頁結(jié)構(gòu)體地址。

  1. LosVmPage *OsVmVaddrToPage(VOID *ptr) 
  2.     struct VmPhysSeg *seg = NULL
  3. ⑴  PADDR_T pa = LOS_PaddrQuery(ptr); 
  4.     UINT32 segID; 
  5.  
  6.     for (segID = 0; segID < g_vmPhysSegNum; segID++) { 
  7.         seg = &g_vmPhysSeg[segID]; 
  8. ⑵      if ((pa >= seg->start) && (pa < (seg->start + seg->size))) { 
  9.             return seg->pageBase + ((pa - seg->start) >> PAGE_SHIFT); 
  10.         } 
  11.     } 
  12.  
  13.     return NULL

3.2.2.2 函數(shù)OsVmPhysPagesFreeContiguous

函數(shù)OsVmPhysPagesFreeContiguous()用于釋放指定數(shù)量的連續(xù)物理內(nèi)存頁。⑴處根據(jù)物理內(nèi)存頁獲取對應(yīng)的物理內(nèi)存地址。⑵處根據(jù)物理內(nèi)存地址獲取空閑內(nèi)存頁鏈表數(shù)組索引數(shù)值。⑶處獲取索引值對應(yīng)的鏈表上的內(nèi)存頁節(jié)點的內(nèi)存頁數(shù)目。⑷處如果要釋放的內(nèi)存頁數(shù)nPages小于當前鏈表上的內(nèi)存頁節(jié)點的數(shù)目,則跳出循環(huán)執(zhí)行⑹處代碼,去釋放到小索引的雙向鏈表上。⑸處調(diào)用函數(shù)OsVmPhysPagesFree()釋放指定鏈表上的內(nèi)存頁,然后更新內(nèi)存頁數(shù)量和內(nèi)存頁結(jié)構(gòu)體地址。

⑹處根據(jù)內(nèi)存頁數(shù)量計算對應(yīng)的鏈表索引,根據(jù)索引值計算鏈表上內(nèi)存頁節(jié)點的大小。⑺處調(diào)用函數(shù)OsVmPhysPagesFree()釋放指定鏈表上的內(nèi)存頁,然后更新內(nèi)存頁數(shù)量和內(nèi)存頁結(jié)構(gòu)體地址。

  1. VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages) 
  2.     paddr_t pa; 
  3.     UINT32 order
  4.     size_t n; 
  5.  
  6.     while (TRUE) { 
  7. ⑴      pa = VM_PAGE_TO_PHYS(page); 
  8. ⑵      order = VM_PHYS_TO_ORDER(pa); 
  9. ⑶      n = VM_ORDER_TO_PAGES(order); 
  10. ⑷      if (n > nPages) { 
  11.             break; 
  12.         } 
  13. ⑸      OsVmPhysPagesFree(page, order); 
  14.         nPages -= n; 
  15.         page += n; 
  16.     } 
  17.  
  18.     while (nPages > 0) { 
  19. ⑹      order = LOS_HighBitGet(nPages); 
  20.         n = VM_ORDER_TO_PAGES(order); 
  21. ⑺      OsVmPhysPagesFree(page, order); 
  22.         nPages -= n; 
  23.         page += n; 
  24.     } 

3.2.2.3 函數(shù)OsVmPhysPagesFree

函數(shù)OsVmPhysPagesFree()釋放內(nèi)存頁到對應(yīng)的空閑內(nèi)存頁鏈表。內(nèi)存頁塊釋放時,會在當前鏈表找地址連續(xù)的伙伴內(nèi)存頁塊進行合并,然后去上一級鏈表上繼續(xù)查找是否存在連續(xù)的伙伴內(nèi)存頁塊。⑴做傳入?yún)?shù)校驗。⑵處需要至少是倒數(shù)第二個鏈表,這樣內(nèi)存頁節(jié)點可以和大索引鏈表上的節(jié)點合并。⑶處獲取內(nèi)存頁對應(yīng)的物理內(nèi)存地址,然后后面會開始do-while循環(huán),查找是否存在連續(xù)的內(nèi)存頁節(jié)點。⑷處的VM_ORDER_TO_PHYS(order)計算出鏈表索引值對應(yīng)的伙伴位圖,然后進行異或運算計算出伙伴內(nèi)存頁的物理內(nèi)存地址。⑸處物理地址轉(zhuǎn)換為內(nèi)存頁結(jié)構(gòu)體,進一步判斷:如果內(nèi)存頁不存在或者不在空閑鏈表上,則跳出循環(huán)while循環(huán)。否則如果伙伴內(nèi)存節(jié)點存在,則執(zhí)行⑹把伙伴頁從鏈表上移除,然后索引值加1。⑺處鏈表索引加1,然后進行邏輯與計算得到物理內(nèi)存地址。此時物理內(nèi)存地址,和合并的兩塊內(nèi)存頁塊地址連續(xù)。該內(nèi)存地址在高一級的空閑鏈表上不一定存在,存在則繼續(xù)合并,不存在則退出循環(huán)。當索引order為8,要插入到最后一個鏈表上時,或者沒有再找到可以合并的節(jié)點時,則直接執(zhí)行⑻插入內(nèi)存頁節(jié)點到空閑鏈表上。

  1. VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order
  2.     paddr_t pa; 
  3.     LosVmPage *buddyPage = NULL
  4.  
  5. ⑴  if ((page == NULL) || (order >= VM_LIST_ORDER_MAX)) { 
  6.         return
  7.     } 
  8.  
  9. ⑵  if (order < VM_LIST_ORDER_MAX - 1) { 
  10. ⑶        pa = VM_PAGE_TO_PHYS(page);         
  11.         do { 
  12. ⑷          pa ^= VM_ORDER_TO_PHYS(order); 
  13. ⑸          buddyPage = OsVmPhysToPage(pa, page->segID); 
  14.             if ((buddyPage == NULL) || (buddyPage->order != order)) { 
  15.                 break; 
  16.             } 
  17. ⑹          OsVmPhysFreeListDel(buddyPage); 
  18.             order++; 
  19. ⑺          pa &= ~(VM_ORDER_TO_PHYS(order) - 1); 
  20.             page = OsVmPhysToPage(pa, page->segID); 
  21.         } while (order < VM_LIST_ORDER_MAX - 1); 
  22.     } 
  23.  
  24. ⑻  OsVmPhysFreeListAdd(page, order); 

3.3 查詢物理頁地址接口

3.3.1 函數(shù)LOS_VmPageGet()

函數(shù)LOS_VmPageGet用于根據(jù)物理內(nèi)存地址參數(shù)計算對應(yīng)的物理內(nèi)存頁結(jié)構(gòu)體地址。⑴處遍歷物理內(nèi)存段,調(diào)用函數(shù)OsVmPhysToPage根據(jù)物理內(nèi)存地址和內(nèi)存段編號計算物理內(nèi)存頁結(jié)構(gòu)體,該函數(shù)后文再分析。⑵處如果獲取的物理內(nèi)存頁結(jié)構(gòu)體不為空,則跳出循環(huán),返回物理內(nèi)存頁結(jié)構(gòu)體指針。

  1. LosVmPage *LOS_VmPageGet(PADDR_T paddr) 
  2.     INT32 segID; 
  3.     LosVmPage *page = NULL
  4.  
  5.     for (segID = 0; segID < g_vmPhysSegNum; segID++) { 
  6. ⑴      page = OsVmPhysToPage(paddr, segID); 
  7. ⑵      if (page != NULL) { 
  8.             break; 
  9.         } 
  10.     } 
  11.  
  12.     return page; 

 繼續(xù)看下函數(shù)OsVmPhysToPage的代碼。⑴處如果參數(shù)傳入的物理內(nèi)存地址不在指定的物理內(nèi)存段的地址范圍之內(nèi)則返回NULL。⑵處計算物理內(nèi)存地址相對內(nèi)存段開始地址的偏移值。⑶處根據(jù)偏移值計算出偏移的內(nèi)存頁的數(shù)目,然后返回物理內(nèi)存地址對應(yīng)的物理頁結(jié)構(gòu)體的地址。

  1. LosVmPage *OsVmPhysToPage(paddr_t pa, UINT8 segID) 
  2.     struct VmPhysSeg *seg = NULL
  3.     paddr_t offset; 
  4.  
  5.     if (segID >= VM_PHYS_SEG_MAX) { 
  6.         LOS_Panic("The page segment id(%d) is invalid\n", segID); 
  7.     } 
  8.     seg = &g_vmPhysSeg[segID]; 
  9. ⑴  if ((pa < seg->start) || (pa >= (seg->start + seg->size))) { 
  10.         return NULL
  11.     } 
  12.  
  13. ⑵  offset = pa - seg->start; 
  14. ⑶  return (seg->pageBase + (offset >> PAGE_SHIFT)); 

3.3.2 函數(shù)LOS_PaddrToKVaddr

函數(shù)LOS_PaddrToKVaddr根據(jù)物理地址獲取其對應(yīng)的內(nèi)核虛擬地址。⑴處遍歷物理內(nèi)存段數(shù)組,然后在⑵處判斷如果物理地址處于遍歷到的物理內(nèi)存段的地址范圍內(nèi),則執(zhí)行⑶,傳入的物理內(nèi)存地址相對物理內(nèi)存開始地址的偏移加上內(nèi)核態(tài)虛擬地址空間的開始地址就是物理地址對應(yīng)的內(nèi)核虛擬地址。

  1. VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr) 
  2.     struct VmPhysSeg *seg = NULL
  3.     UINT32 segID; 
  4.  
  5.     for (segID = 0; segID < g_vmPhysSegNum; segID++) { 
  6.  ⑴     seg = &g_vmPhysSeg[segID]; 
  7.  ⑵     if ((paddr >= seg->start) && (paddr < (seg->start + seg->size))) { 
  8.  ⑶          return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE); 
  9.         } 
  10.     } 
  11.  
  12.     return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE); 

3.4 其他函數(shù)

3.4.1 函數(shù)OsPhysSharePageCopy

函數(shù)OsPhysSharePageCopy用于復(fù)制共享內(nèi)存頁。 ⑴處進行參數(shù)校驗, ⑵處獲取老內(nèi)存頁, ⑶處獲取內(nèi)存段。⑷處如果老內(nèi)存頁引用計數(shù)為1,則把老物理內(nèi)存地址直接賦值給新物理內(nèi)存地址。⑸處如果內(nèi)存頁有多個引用,則先轉(zhuǎn)化為虛擬內(nèi)存地址,然后執(zhí)行⑹進行內(nèi)存頁的內(nèi)容復(fù)制。⑺刷新新老內(nèi)存頁的引用計數(shù)。

  1. VOID OsPhysSharePageCopy(PADDR_T oldPaddr, PADDR_T *newPaddr, LosVmPage *newPage) 
  2.     UINT32 intSave; 
  3.     LosVmPage *oldPage = NULL
  4.     VOID *newMem = NULL
  5.     VOID *oldMem = NULL
  6.     LosVmPhysSeg *seg = NULL
  7.  
  8.  ⑴  if ((newPage == NULL) || (newPaddr == NULL)) { 
  9.         VM_ERR("new Page invalid"); 
  10.         return
  11.     } 
  12.  
  13.  ⑵  oldPage = LOS_VmPageGet(oldPaddr); 
  14.     if (oldPage == NULL) { 
  15.         VM_ERR("invalid oldPaddr %p", oldPaddr); 
  16.         return
  17.     } 
  18.  
  19.  ⑶  seg = &g_vmPhysSeg[oldPage->segID]; 
  20.     LOS_SpinLockSave(&seg->freeListLock, &intSave); 
  21. ⑷  if (LOS_AtomicRead(&oldPage->refCounts) == 1) { 
  22.         *newPaddr = oldPaddr; 
  23.     } else { 
  24. ⑸      newMem = LOS_PaddrToKVaddr(*newPaddr); 
  25.         oldMem = LOS_PaddrToKVaddr(oldPaddr); 
  26.         if ((newMem == NULL) || (oldMem == NULL)) { 
  27.             LOS_SpinUnlockRestore(&seg->freeListLock, intSave); 
  28.             return
  29.         } 
  30. ⑹      if (memcpy_s(newMem, PAGE_SIZE, oldMem, PAGE_SIZE) != EOK) { 
  31.             VM_ERR("memcpy_s failed"); 
  32.         } 
  33.  
  34. ⑺      LOS_AtomicInc(&newPage->refCounts); 
  35.         LOS_AtomicDec(&oldPage->refCounts); 
  36.     } 
  37.     LOS_SpinUnlockRestore(&seg->freeListLock, intSave); 
  38.     return

總結(jié)

本文首先了解了物理內(nèi)存管理的結(jié)構(gòu)體,接著閱讀了物理內(nèi)存如何初始化,然后分析了物理內(nèi)存的申請、釋放和查詢等操作接口的源代碼。

想了解更多內(nèi)容,請訪問:

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com

 

 

責任編輯:jianghua 來源: 鴻蒙社區(qū)
相關(guān)推薦

2021-11-05 15:00:33

鴻蒙HarmonyOS應(yīng)用

2021-12-03 16:20:26

鴻蒙HarmonyOS應(yīng)用

2021-05-17 09:28:59

鴻蒙HarmonyOS應(yīng)用

2022-03-11 20:23:14

鴻蒙源碼分析進程管理

2022-03-03 18:28:28

Harmony進程任務(wù)管理模塊

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2021-06-17 09:36:07

鴻蒙HarmonyOS應(yīng)用

2022-03-31 16:26:49

鴻蒙源碼分析進程管理

2021-05-21 09:25:11

鴻蒙HarmonyOS應(yīng)用

2022-01-10 15:31:44

鴻蒙HarmonyOS應(yīng)用

2022-01-12 10:50:23

鴻蒙HarmonyOS應(yīng)用

2021-06-04 09:57:49

鴻蒙HarmonyOS應(yīng)用

2021-06-04 14:15:10

鴻蒙HarmonyOS應(yīng)用

2021-05-08 15:14:50

鴻蒙HarmonyOS應(yīng)用

2021-05-25 09:28:34

鴻蒙HarmonyOS應(yīng)用

2021-10-20 16:08:57

鴻蒙HarmonyOS應(yīng)用

2022-04-13 11:12:43

鴻蒙輕內(nèi)核信號量模塊操作系統(tǒng)

2021-05-12 09:45:20

鴻蒙HarmonyOS應(yīng)用

2021-05-10 15:05:56

鴻蒙HarmonyOS應(yīng)用

2021-12-01 15:59:22

鴻蒙HarmonyOS應(yīng)用
點贊
收藏

51CTO技術(shù)棧公眾號