鸿蒙轻内核A核源码分析系列五 虚实映射(4)虚实映射查询 原创 精华

zhushangyuan_
发布于 2021-12-1 17:45
浏览
3收藏

鸿蒙轻内核A核源码分析系列五 虚实映射

【#本文正在参与优质创作者激励#】

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标签转换为内存区域标签。

鸿蒙轻内核A核源码分析系列五 虚实映射(4)虚实映射查询-鸿蒙开发者社区

如果虚拟地址对应的页表项描述符类型为页表Page Table,则执行⑹调用内联函数OsGetPte2BasePtr()计算L2页表项基地址,计算方法为:取L1页表项的高22位,低10位置0,得到L2页表项物理内存基地址,然后转化为L2页表项虚拟内存基地址。⑺处计算虚拟地址对应的L2页表项数值,从上文可知,L2页表项的指针地址在页表项基地址加上虚拟内存地址的12-19位上的索引值,取该地址的数据即为L2页表项数据。如果L2页表项描述符类型为小页,则执行⑻计算物理内存地址,其中MMU_DESCRIPTOR_L2_SMALL_PAGE_ADDR(l2Entry)为L2页表项的高20位;vaddr & (MMU_DESCRIPTOR_L2_SMALL_SIZE - 1)为虚拟地址的低12位,如下图所示。然后计算相应的标签值。⑼处表示当前轻内核还不支持大页类型。

鸿蒙轻内核A核源码分析系列五 虚实映射(4)虚实映射查询-鸿蒙开发者社区

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;
}

【#本文正在参与优质创作者激励#】

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-1-4 19:09:02修改
2
收藏 3
回复
举报
1条回复
按时间正序
/
按时间倒序
zhushangyuan_
zhushangyuan_
。⑺处计算虚拟地址对应的L2页表项数值,从上文可知,L2页表项的指针地址在页表项基地址加上虚拟内存地址的高20位,取该地址的数据即为L2页表项数据。

 

文中此处描述错误。 % MMU_DESCRIPTOR_L1_SMALL_SIZE 表示取后20位,>> MMU_DESCRIPTOR_L2_SMALL_SHIFT然后右移12位。所以L2页表项的索引值保存在虚拟地址的第12-19位上,而不是高20位。

 

#define MMU_DESCRIPTOR_L1_SMALL_SIZE                            0x100000
#define MMU_DESCRIPTOR_L2_SMALL_SHIFT                           12
......
STATIC INLINE UINT32 OsGetPte2Index(vaddr_t va)
{
    return (va % MMU_DESCRIPTOR_L1_SMALL_SIZE) >> MMU_DESCRIPTOR_L2_SMALL_SHIFT;
}

STATIC INLINE PTE_T *OsGetPte2Ptr(PTE_T *pte2BasePtr, vaddr_t va)
{
     return (pte2BasePtr + OsGetPte2Index(va));
}

 

1
回复
2022-1-4 11:55:09
回复
    相关推荐