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

鴻蒙輕內(nèi)核A核源碼分析系列之虛實(shí)映射(3)虛擬物理內(nèi)存映射

開(kāi)發(fā) 前端
虛實(shí)映射其實(shí)就是一個(gè)建立頁(yè)表的過(guò)程。MMU支持多級(jí)頁(yè)表,LiteOS-A內(nèi)核采用二級(jí)頁(yè)表描述進(jìn)程空間。首先介紹下一級(jí)頁(yè)表和二級(jí)頁(yè)表。

[[438476]]

想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):

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

https://harmonyos.51cto.com

3、虛實(shí)映射函數(shù)LOS_ArchMmuMap

從上文可知,用戶程序加載啟動(dòng)時(shí),會(huì)將代碼段、數(shù)據(jù)段映射進(jìn)虛擬內(nèi)存空間,此時(shí)并沒(méi)有物理頁(yè)做實(shí)際的映射;程序執(zhí)行時(shí),如下圖(圖片來(lái)自O(shè)penHarmony docs開(kāi)源站點(diǎn))粗箭頭所示,CPU訪問(wèn)虛擬地址,通過(guò)MMU查找是否有對(duì)應(yīng)的物理內(nèi)存,若該虛擬地址無(wú)對(duì)應(yīng)的物理地址則觸發(fā)缺頁(yè)異常,內(nèi)核申請(qǐng)物理內(nèi)存并將虛實(shí)映射關(guān)系及對(duì)應(yīng)的屬性配置信息寫(xiě)進(jìn)頁(yè)表,并把頁(yè)表?xiàng)l目緩存至TLB,接著CPU可直接通過(guò)轉(zhuǎn)換關(guān)系訪問(wèn)實(shí)際的物理內(nèi)存;若CPU訪問(wèn)已緩存至TLB的頁(yè)表?xiàng)l目,無(wú)需再訪問(wèn)保存在內(nèi)存中的頁(yè)表,可加快查找速度。本小節(jié)我們就詳細(xì)分析下虛實(shí)映射函數(shù)的實(shí)現(xiàn)代碼。

鴻蒙輕內(nèi)核A核源碼分析系列五 虛實(shí)映射(3)虛擬物理內(nèi)存映射-鴻蒙HarmonyOS技術(shù)社區(qū)

3.1 函數(shù)LOS_ArchMmuMap

函數(shù)LOS_ArchMmuMap用于映射進(jìn)程空間虛擬地址區(qū)間與物理地址區(qū)間,其中輸入?yún)?shù)archMmu為MMU結(jié)構(gòu)體,vaddr和paddr分別是虛擬內(nèi)存和物理內(nèi)存的開(kāi)始地址;count為虛擬地址和物理地址映射的內(nèi)存頁(yè)數(shù)量;flags為映射標(biāo)簽。⑴處進(jìn)行函數(shù)參數(shù)校驗(yàn),不支持NON-SECURE的標(biāo)記,虛擬地址和物理地址需要內(nèi)存頁(yè)4KiB對(duì)齊,參數(shù)檢查函數(shù)代碼簡(jiǎn)單,自行查看即可。⑵處當(dāng)虛擬地址、物理地址基于1MiB對(duì)齊,并且數(shù)量count大于256時(shí),使用Section頁(yè)表項(xiàng)格式。⑶處生成L1 section類型頁(yè)表項(xiàng)并保存,下文詳細(xì)分析該函數(shù)OsMapSection()。如果不滿足⑵處條件,需要使用L2映射。首先執(zhí)行⑷處獲取虛擬地址vaddr對(duì)應(yīng)的L1頁(yè)表項(xiàng),接著執(zhí)行⑸處判斷是否映射,如果沒(méi)有對(duì)應(yīng)的映射,則執(zhí)行⑹處的函數(shù)OsMapL1PTE生成L1 page table類型頁(yè)表項(xiàng)并保存,然后執(zhí)行函數(shù)OsMapL2PageContinous生成L2 頁(yè)表項(xiàng)并保存。如果已經(jīng)映射為L(zhǎng)1 page table頁(yè)表項(xiàng)類型,則執(zhí)行函數(shù)OsMapL2PageContinous生成L2 頁(yè)表項(xiàng)并保存。如果不是支持的頁(yè)表項(xiàng)類型,則執(zhí)行LOS_Panic()觸發(fā)異常。⑺處統(tǒng)計(jì)生成映射的調(diào)試,最終會(huì)返回映射成功的數(shù)量。

可以看出,在給定虛實(shí)內(nèi)存地址和映射的內(nèi)存頁(yè)數(shù)后,使用L1頁(yè)表映射還是L2頁(yè)表映射的判斷條件是:虛實(shí)內(nèi)存地址是否1MiB內(nèi)存對(duì)齊,并且映射數(shù)量是否大于256。當(dāng)使用L1映射時(shí),映射為Section頁(yè)表項(xiàng)類型。當(dāng)使用L2映射時(shí),根據(jù)L1頁(yè)表項(xiàng)類型,分布處理無(wú)效頁(yè)表項(xiàng)和Page Table頁(yè)表項(xiàng)類型這2種情況。具體的映射方式見(jiàn)下文。

  1. status_t LOS_ArchMmuMap(LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T paddr, size_t count, UINT32 flags) 
  2.     PTE_T l1Entry; 
  3.     UINT32 saveCounts = 0; 
  4.     INT32 mapped = 0; 
  5.     INT32 checkRst; 
  6.  
  7. ⑴  checkRst = OsMapParamCheck(flags, vaddr, paddr); 
  8.     if (checkRst < 0) { 
  9.         return checkRst; 
  10.     } 
  11.  
  12.     /* see what kind of mapping we can use */ 
  13.     while (count > 0) { 
  14. ⑵      if (MMU_DESCRIPTOR_IS_L1_SIZE_ALIGNED(vaddr) && 
  15.             MMU_DESCRIPTOR_IS_L1_SIZE_ALIGNED(paddr) && 
  16.             count >= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1) { 
  17.             /* compute the arch flags for L1 sections cache, r ,w ,x, domain and type */ 
  18. ⑶          saveCounts = OsMapSection(archMmu, flags, &vaddr, &paddr, &count); 
  19.         } else { 
  20.             /* have to use a L2 mapping, we only allocate 4KB for L1, support 0 ~ 1GB */ 
  21. ⑷          l1Entry = OsGetPte1(archMmu->virtTtb, vaddr); 
  22. ⑸          if (OsIsPte1Invalid(l1Entry)) { 
  23. ⑹              OsMapL1PTE(archMmu, &l1Entry, vaddr, flags); 
  24.                 saveCounts = OsMapL2PageContinous(l1Entry, flags, &vaddr, &paddr, &count); 
  25.             } else if (OsIsPte1PageTable(l1Entry)) { 
  26.                 saveCounts = OsMapL2PageContinous(l1Entry, flags, &vaddr, &paddr, &count); 
  27.             } else { 
  28.                 LOS_Panic("%s %d, unimplemented tt_entry %x/n", __FUNCTION__, __LINE__, l1Entry); 
  29.             } 
  30.         } 
  31. ⑺      mapped += saveCounts; 
  32.     } 
  33.  
  34.     return mapped; 

3.2 OsMapSectionL1 Section類型頁(yè)表項(xiàng)映射函數(shù)

函數(shù)OsMapSection生成L1 Section類型頁(yè)表項(xiàng)并保存。⑴處把內(nèi)存區(qū)間標(biāo)簽(這些標(biāo)簽定義在文件kernel\base\include\los_vm_map.h中,標(biāo)簽名稱一般為VM_MAP_REGION_FLAG_XXXX)轉(zhuǎn)換為MMU標(biāo)簽(定義在arch\arm\arm\include\los_mmu_descriptor_v6.h中,標(biāo)簽名稱一般為MMU_DESCRIPTOR_L1_TYPE_XXXX)。 ⑵處的函數(shù)OsGetPte1Ptr(archMmu->virtTtb, *vaddr)用于獲取虛擬地址對(duì)應(yīng)的頁(yè)表項(xiàng)索引地址,等于頁(yè)表項(xiàng)基地址加上虛擬地址的高20位;OsTruncPte1(*paddr) | mmuFlags | MMU_DESCRIPTOR_L1_TYPE_SECTION)為物理內(nèi)存地址的高12位+MMU標(biāo)簽+頁(yè)表項(xiàng)Section類型值。該行語(yǔ)句的作用是把虛擬地址和物理地理進(jìn)行映射,映射關(guān)系維護(hù)在頁(yè)表項(xiàng)。這行代碼比較關(guān)鍵,我們繪制下圖形來(lái)表示,見(jiàn)下圖。⑶處把虛擬地址和物理地址增加1MiB的大小,映射數(shù)量減去256(1MiB有256個(gè)4KiB大小的內(nèi)存頁(yè))。

 鴻蒙輕內(nèi)核A核源碼分析系列五 虛實(shí)映射(3)虛擬物理內(nèi)存映射-鴻蒙HarmonyOS技術(shù)社區(qū)

  1. STATIC UINT32 OsMapSection(const LosArchMmu *archMmu, UINT32 flags, VADDR_T *vaddr, 
  2.                            PADDR_T *paddr, UINT32 *count
  3.     UINT32 mmuFlags = 0; 
  4.  
  5. ⑴  mmuFlags |= OsCvtSecFlagsToAttrs(flags); 
  6. ⑵  OsSavePte1(OsGetPte1Ptr(archMmu->virtTtb, *vaddr), 
  7.         OsTruncPte1(*paddr) | mmuFlags | MMU_DESCRIPTOR_L1_TYPE_SECTION); 
  8. ⑶  *count -= MMU_DESCRIPTOR_L2_NUMBERS_PER_L1; 
  9.     *vaddr += MMU_DESCRIPTOR_L1_SMALL_SIZE; 
  10.     *paddr += MMU_DESCRIPTOR_L1_SMALL_SIZE; 
  11.  
  12.     return MMU_DESCRIPTOR_L2_NUMBERS_PER_L1; 

3.3 函數(shù)OsGetL2Table生成L2頁(yè)表項(xiàng)基地址

函數(shù)OsGetL2Table用于生成L2頁(yè)表,函數(shù)參數(shù)中archMmu是MMU結(jié)構(gòu)體,l1Index是L1頁(yè)表項(xiàng)索引(頁(yè)號(hào)),ppa屬于輸出參數(shù),保存L2頁(yè)表項(xiàng)基地址。⑴處計(jì)算L2頁(yè)表項(xiàng)偏移值(為啥這么計(jì)算? 看不懂 TODO),其中(MMU_DESCRIPTOR_L2_SMALL_SIZE / MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE)的大小等于1024;l1Index & (MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE - 1)為虛擬地址的第20-21位。⑵處通過(guò)循環(huán)遍歷查詢是否存在L2頁(yè)表(為啥查詢4次?TODO),⑶處獲取頁(yè)表項(xiàng)基地址,然后判斷是否頁(yè)表類型,如果是,則返回L2頁(yè)表項(xiàng)基地址。

如果沒(méi)有存在的頁(yè)表,則為L(zhǎng)2頁(yè)表申請(qǐng)內(nèi)存,如果支持虛擬地址LOSCFG_KERNEL_VM,執(zhí)行⑷使用LOS_PhysPageAlloc申請(qǐng)內(nèi)存頁(yè),把申請(qǐng)的內(nèi)存頁(yè)掛載頁(yè)表鏈表上,并根據(jù)內(nèi)存頁(yè)計(jì)算虛擬內(nèi)存地址kvaddr;如果不支持虛擬地址,執(zhí)行⑸使用LOS_MemAlloc申請(qǐng)內(nèi)存。⑹處轉(zhuǎn)換為物理地址,然后加上頁(yè)表偏移值l2Offset返回L2頁(yè)表項(xiàng)基地址。

  1. STATIC STATUS_T OsGetL2Table(LosArchMmu *archMmu, UINT32 l1Index, paddr_t *ppa) 
  2.     UINT32 index
  3.     PTE_T ttEntry; 
  4.     VADDR_T *kvaddr = NULL
  5. ⑴  UINT32 l2Offset = (MMU_DESCRIPTOR_L2_SMALL_SIZE / MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE) * 
  6.         (l1Index & (MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE - 1)); 
  7.     /* lookup an existing l2 page table */ 
  8. ⑵   for (index = 0; index < MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE; index++) { 
  9. ⑶      ttEntry = archMmu->virtTtb[ROUNDDOWN(l1Index, MMU_DESCRIPTOR_L1_SMALL_L2_TABLES_PER_PAGE) + index]; 
  10.         if ((ttEntry & MMU_DESCRIPTOR_L1_TYPE_MASK) == MMU_DESCRIPTOR_L1_TYPE_PAGE_TABLE) { 
  11.             *ppa = (PADDR_T)ROUNDDOWN(MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(ttEntry), MMU_DESCRIPTOR_L2_SMALL_SIZE) + 
  12.                 l2Offset; 
  13.             return LOS_OK; 
  14.         } 
  15.     } 
  16.  
  17. #ifdef LOSCFG_KERNEL_VM 
  18.     /* not found: allocate one (paddr) */ 
  19. ⑷  LosVmPage *vmPage = LOS_PhysPageAlloc(); 
  20.     if (vmPage == NULL) { 
  21.         VM_ERR("have no memory to save l2 page"); 
  22.         return LOS_ERRNO_VM_NO_MEMORY; 
  23.     } 
  24.     LOS_ListAdd(&archMmu->ptList, &vmPage->node); 
  25.     kvaddr = OsVmPageToVaddr(vmPage); 
  26. #else 
  27. ⑸  kvaddr = LOS_MemAlloc(OS_SYS_MEM_ADDR, MMU_DESCRIPTOR_L2_SMALL_SIZE); 
  28.     if (kvaddr == NULL) { 
  29.         VM_ERR("have no memory to save l2 page"); 
  30.         return LOS_ERRNO_VM_NO_MEMORY; 
  31.     } 
  32. #endif 
  33.     (VOID)memset_s(kvaddr, MMU_DESCRIPTOR_L2_SMALL_SIZE, 0, MMU_DESCRIPTOR_L2_SMALL_SIZE); 
  34.  
  35.     /* get physical address */ 
  36. ⑹  *ppa = LOS_PaddrQuery(kvaddr) + l2Offset; 
  37.     return LOS_OK; 

3.4 OsMapL1PTEL1 Page Table類型頁(yè)表項(xiàng)映射函數(shù)

和函數(shù)OsMapSection對(duì)應(yīng),函數(shù)OsMapL1PTE用于生成L1 Page Table類型頁(yè)表項(xiàng)并保存,其中函數(shù)參數(shù)pte1Ptr是L1頁(yè)表項(xiàng)地址。⑴處調(diào)用函數(shù)OsGetL2Table()獲取L2頁(yè)表項(xiàng)基地址TTB,⑵處把L2頁(yè)表項(xiàng)基地址加上描述符類型作為L(zhǎng)1頁(yè)表項(xiàng)數(shù)據(jù)。⑶處開(kāi)始的3行代碼為頁(yè)表項(xiàng)設(shè)置標(biāo)簽,⑷處為虛擬內(nèi)存地址vaddr保存頁(yè)表項(xiàng)數(shù)據(jù)。

  1. STATIC VOID OsMapL1PTE(LosArchMmu *archMmu, PTE_T *pte1Ptr, vaddr_t vaddr, UINT32 flags) 
  2.     paddr_t pte2Base = 0; 
  3.  
  4. ⑴  if (OsGetL2Table(archMmu, OsGetPte1Index(vaddr), &pte2Base) != LOS_OK) { 
  5.         LOS_Panic("%s %d, failed to allocate pagetable\n", __FUNCTION__, __LINE__); 
  6.     } 
  7.  
  8. ⑵  *pte1Ptr = pte2Base | MMU_DESCRIPTOR_L1_TYPE_PAGE_TABLE; 
  9. ⑶  if (flags & VM_MAP_REGION_FLAG_NS) { 
  10.         *pte1Ptr |= MMU_DESCRIPTOR_L1_PAGETABLE_NON_SECURE; 
  11.     } 
  12.     *pte1Ptr &= MMU_DESCRIPTOR_L1_SMALL_DOMAIN_MASK; 
  13.     *pte1Ptr |= MMU_DESCRIPTOR_L1_SMALL_DOMAIN_CLIENT; // use client AP 
  14. ⑷   OsSavePte1(OsGetPte1Ptr(archMmu->virtTtb, vaddr), *pte1Ptr); 

3.5 OsMapL2PageContinuous映射L2頁(yè)表函數(shù)

函數(shù)OsMapL2PageContinuous用于映射L2頁(yè)表項(xiàng),其中函數(shù)參數(shù)pte1為L(zhǎng)1頁(yè)表項(xiàng)數(shù)據(jù),flags為虛實(shí)映射標(biāo)簽,vaddr為虛擬內(nèi)存,paddr為物理內(nèi)存,count為需要映射的內(nèi)存頁(yè)數(shù)量。

⑴處根據(jù)L1頁(yè)表項(xiàng)數(shù)據(jù)獲取L2頁(yè)表項(xiàng)虛擬內(nèi)存基地址。頁(yè)表項(xiàng)的高22位為L(zhǎng)2頁(yè)表項(xiàng)的物理內(nèi)存基地址,然后轉(zhuǎn)換為虛擬內(nèi)存基地址即可。⑵處把地址區(qū)間標(biāo)簽轉(zhuǎn)換為L(zhǎng)2頁(yè)表標(biāo)簽,⑶處連續(xù)設(shè)置L2頁(yè)表項(xiàng)數(shù)據(jù),saveCounts表示映射了多少個(gè)L2頁(yè)表項(xiàng)。⑷處映射L2頁(yè)表項(xiàng)數(shù)據(jù)后,更新虛擬、物理內(nèi)存地址,更新映射后的內(nèi)存頁(yè)數(shù)量count。由于一個(gè)L2頁(yè)表項(xiàng)占用4KiB大小,saveCounts個(gè)頁(yè)表項(xiàng),需要把saveCounts左移12位來(lái)增長(zhǎng)內(nèi)存地址。

  1. STATIC UINT32 OsMapL2PageContinuous(PTE_T pte1, UINT32 flags, VADDR_T *vaddr, PADDR_T *paddr, UINT32 *count
  2.     PTE_T *pte2BasePtr = NULL
  3.     UINT32 archFlags; 
  4.     UINT32 saveCounts; 
  5.  
  6. ⑴  pte2BasePtr = OsGetPte2BasePtr(pte1); 
  7.     if (pte2BasePtr == NULL) { 
  8.         LOS_Panic("%s %d, pte1 %#x error\n", __FUNCTION__, __LINE__, pte1); 
  9.     } 
  10.  
  11.     /* compute the arch flags for L2 4K pages */ 
  12. ⑵  archFlags = OsCvtPte2FlagsToAttrs(flags); 
  13. ⑶  saveCounts = OsSavePte2Continuous(pte2BasePtr, OsGetPte2Index(*vaddr), *paddr | archFlags, *count); 
  14. ⑷  *paddr += (saveCounts << MMU_DESCRIPTOR_L2_SMALL_SHIFT); 
  15.     *vaddr += (saveCounts << MMU_DESCRIPTOR_L2_SMALL_SHIFT); 
  16.     *count -= saveCounts; 
  17.     return saveCounts; 

想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):

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

https://harmonyos.51cto.com

 

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

2021-12-03 16:22:05

鴻蒙HarmonyOS應(yīng)用

2021-12-02 15:08:23

鴻蒙HarmonyOS應(yīng)用

2021-12-01 15:59:22

鴻蒙HarmonyOS應(yīng)用

2021-11-05 15:00:33

鴻蒙HarmonyOS應(yīng)用

2021-11-08 15:06:15

鴻蒙HarmonyOS應(yīng)用

2022-03-11 20:23:14

鴻蒙源碼分析進(jìn)程管理

2022-01-10 15:31:44

鴻蒙HarmonyOS應(yīng)用

2022-01-12 10:50:23

鴻蒙HarmonyOS應(yīng)用

2021-05-17 09:28:59

鴻蒙HarmonyOS應(yīng)用

2022-01-14 08:39:47

鴻蒙HarmonyOS應(yīng)用

2022-03-03 18:28:28

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

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2021-05-21 09:25:11

鴻蒙HarmonyOS應(yīng)用

2021-06-04 09:57:49

鴻蒙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)核信號(hào)量模塊操作系統(tǒng)

2021-06-04 14:15:10

鴻蒙HarmonyOS應(yīng)用

2021-05-08 15:14:50

鴻蒙HarmonyOS應(yīng)用

2021-05-31 20:30:55

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

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