鴻蒙輕內核A核源碼分析系列之虛實映射(4)虛實映射查詢
4、虛實映射查詢函數LOS_ArchMmuQuery
給定一個虛擬內存地址,可以查詢其映射到的物理內存地址,還可以查詢映射標簽屬性信息,函數LOS_ArchMmuQuery負責完成這些信息的查詢。
4.1 函數LOS_ArchMmuQuery
函數LOS_ArchMmuQuery用于獲取進程空間虛擬地址對應的物理地址以及映射標簽屬性,其中輸入參數為虛擬內存地址vaddr,輸出參數為物理內存地址*paddr和標簽屬性*flags。⑴處獲取虛擬地址對應的頁表項。⑵處如果虛擬地址對應的頁表項描述符類型無效,返回錯誤碼。⑶處如果頁表項描述符類型為L1頁表Section類型映射,則執行⑷獲取映射的物理地址,其中MMU_DESCRIPTOR_L1_SECTION_ADDR(l1Entry)為L1頁表項的高12位,(vaddr & (MMU_DESCRIPTOR_L1_SMALL_SIZE - 1))為虛擬地址的低20位,即頁內偏移值。可以和上文了解到的知識相對應,物理內存地址的計算方式為頁表項的高12位加上虛擬內存地址的低20位,如下圖所示。⑸處獲取映射的標簽屬性,把MMU標簽轉換為內存區域標簽。

如果虛擬地址對應的頁表項描述符類型為頁表Page Table,則執行⑹調用內聯函數OsGetPte2BasePtr()計算L2頁表項基地址,計算方法為:取L1頁表項的高22位,低10位置0,得到L2頁表項物理內存基地址,然后轉化為L2頁表項虛擬內存基地址。⑺處計算虛擬地址對應的L2頁表項數值,從上文可知,L2頁表項的指針地址在頁表項基地址加上虛擬內存地址的高20位,取該地址的數據即為L2頁表項數據。如果L2頁表項描述符類型為小頁,則執行⑻計算物理內存地址,其中MMU_DESCRIPTOR_L2_SMALL_PAGE_ADDR(l2Entry)為L2頁表項的高20位;vaddr & (MMU_DESCRIPTOR_L2_SMALL_SIZE - 1)為虛擬地址的低12位,如下圖所示。然后計算相應的標簽值。⑼處表示當前輕內核還不支持大頁類型。

- STATUS_T LOS_ArchMmuQuery(const LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T *paddr, UINT32 *flags)
- {
- ⑴ PTE_T l1Entry = OsGetPte1(archMmu->virtTtb, vaddr);
- PTE_T l2Entry;
- PTE_T* l2Base = NULL;
- ⑵ if (OsIsPte1Invalid(l1Entry)) {
- return LOS_ERRNO_VM_NOT_FOUND;
- ⑶ } else if (OsIsPte1Section(l1Entry)) {
- if (paddr != NULL) {
- ⑷ *paddr = MMU_DESCRIPTOR_L1_SECTION_ADDR(l1Entry) + (vaddr & (MMU_DESCRIPTOR_L1_SMALL_SIZE - 1));
- }
- if (flags != NULL) {
- ⑸ OsCvtSecAttsToFlags(l1Entry, flags);
- }
- } else if (OsIsPte1PageTable(l1Entry)) {
- ⑹ l2Base = OsGetPte2BasePtr(l1Entry);
- if (l2Base == NULL) {
- return LOS_ERRNO_VM_NOT_FOUND;
- }
- ⑺ l2Entry = OsGetPte2(l2Base, vaddr);
- if (OsIsPte2SmallPage(l2Entry) || OsIsPte2SmallPageXN(l2Entry)) {
- if (paddr != NULL) {
- ⑻ *paddr = MMU_DESCRIPTOR_L2_SMALL_PAGE_ADDR(l2Entry) + (vaddr & (MMU_DESCRIPTOR_L2_SMALL_SIZE - 1));
- }
- if (flags != NULL) {
- OsCvtPte2AttsToFlags(l1Entry, l2Entry, flags);
- }
- ⑼ } else if (OsIsPte2LargePage(l2Entry)) {
- LOS_Panic("%s %d, large page unimplemented\n", __FUNCTION__, __LINE__);
- } else {
- return LOS_ERRNO_VM_NOT_FOUND;
- }
- }
- return LOS_OK;
- }