class="hide-preCode-box">
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
7.3 标签转换操作
7.3.1 OsCvtProtFlagsToRegionFlags函数
函数OsCvtProtFlagsToRegionFlags()
把保护属性转换为虚拟内存区间标签属性,该函数在系统调用、共享内存等模块会使用。参数unsigned long prot
中的保护标签属性如PROT_READ
、MAP_SHARED
等等,定义在文件third_party/musl/porting/liteos_a/kernel/include/sys/mman.h
。
STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned long flags)
{
UINT32 regionFlags = 0;
regionFlags |= VM_MAP_REGION_FLAG_PERM_USER;
regionFlags |= (prot & PROT_READ) ? VM_MAP_REGION_FLAG_PERM_READ : 0;
regionFlags |= (prot & PROT_WRITE) ? (VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE) : 0;
regionFlags |= (prot & PROT_EXEC) ? (VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_EXECUTE) : 0;
regionFlags |= (flags & MAP_SHARED) ? VM_MAP_REGION_FLAG_SHARED : 0;
regionFlags |= (flags & MAP_PRIVATE) ? VM_MAP_REGION_FLAG_PRIVATE : 0;
regionFlags |= (flags & MAP_FIXED) ? VM_MAP_REGION_FLAG_FIXED : 0;
regionFlags |= (flags & MAP_FIXED_NOREPLACE) ? VM_MAP_REGION_FLAG_FIXED_NOREPLACE : 0;
return regionFlags;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
7.3.2 OsCvtSecFlagsToAttrs函数和OsCvtSecAttsToFlags函数
OsCvtSecFlagsToAttrs
函数用于把内存区域映射标签属性转换为L1 Section类型页表项的MMU标签属性。该函数又分为2个函数,分别是⑴处的OsCvtSecCacheFlagsToMMUFlags()
函数和⑵处的OsCvtSecAccessFlagsToMMUFlags()
函数。OsCvtSecCacheFlagsToMMUFlags()
函数主要判断内存映射区域的低2位缓存标签属性的转换。OsCvtSecAccessFlagsToMMUFlags()
函数用于映射标签属性的2-4位访问权限部分的转换。代码比较简单不再赘述。
⑶处的函数OsCvtSecAttsToFlags()
是上述函数OsCvtSecFlagsToAttrs
的逆过程,用于把L1 Section类型页表项的MMU标签属性转换为内存区域映射标签属性。自行阅读代码,不再逐行分析。
⑴ STATIC UINT32 OsCvtSecCacheFlagsToMMUFlags(UINT32 flags)
{
UINT32 mmuFlags = 0;
switch (flags & VM_MAP_REGION_FLAG_CACHE_MASK) {
case VM_MAP_REGION_FLAG_CACHED:
mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_NORMAL_WRITE_BACK_ALLOCATE;
#ifdef LOSCFG_KERNEL_SMP
mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_SHAREABLE;
#endif
break;
case VM_MAP_REGION_FLAG_STRONGLY_ORDERED:
mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_STRONGLY_ORDERED;
break;
case VM_MAP_REGION_FLAG_UNCACHED:
mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_NORMAL_NOCACHE;
break;
case VM_MAP_REGION_FLAG_UNCACHED_DEVICE:
mmuFlags |= MMU_DESCRIPTOR_L1_TYPE_DEVICE_SHARED;
break;
default:
return LOS_ERRNO_VM_INVALID_ARGS;
}
return mmuFlags;
}
⑵ STATIC UINT32 OsCvtSecAccessFlagsToMMUFlags(UINT32 flags)
{
UINT32 mmuFlags = 0;
switch (flags & (VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE)) {
case 0:
mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_NA_U_NA;
break;
case VM_MAP_REGION_FLAG_PERM_READ:
case VM_MAP_REGION_FLAG_PERM_USER:
mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RO_U_NA;
break;
case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ:
mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RO_U_RO;
break;
case VM_MAP_REGION_FLAG_PERM_WRITE:
case VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RW_U_NA;
break;
case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE:
case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_RW_U_RW;
break;
default:
break;
}
return mmuFlags;
}
/* convert user level mmu flags to L1 descriptors flags */
STATIC UINT32 OsCvtSecFlagsToAttrs(UINT32 flags)
{
UINT32 mmuFlags;
mmuFlags = OsCvtSecCacheFlagsToMMUFlags(flags);
if (mmuFlags == LOS_ERRNO_VM_INVALID_ARGS) {
return mmuFlags;
}
mmuFlags |= MMU_DESCRIPTOR_L1_SMALL_DOMAIN_CLIENT;
mmuFlags |= OsCvtSecAccessFlagsToMMUFlags(flags);
if (!(flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {
mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_XN;
}
if (flags & VM_MAP_REGION_FLAG_NS) {
mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_NON_SECURE;
}
if (flags & VM_MAP_REGION_FLAG_PERM_USER) {
mmuFlags |= MMU_DESCRIPTOR_L1_SECTION_NON_GLOBAL;
}
return mmuFlags;
}
⑶ STATIC VOID OsCvtSecAttsToFlags(PTE_T l1Entry, UINT32 *flags)
{
*flags = 0;
if (l1Entry & MMU_DESCRIPTOR_L1_SECTION_NON_SECURE) {
*flags |= VM_MAP_REGION_FLAG_NS;
}
switch (l1Entry & MMU_DESCRIPTOR_L1_TEX_TYPE_MASK) {
case MMU_DESCRIPTOR_L1_TYPE_STRONGLY_ORDERED:
*flags |= VM_MAP_REGION_FLAG_STRONGLY_ORDERED;
break;
case MMU_DESCRIPTOR_L1_TYPE_NORMAL_NOCACHE:
*flags |= VM_MAP_REGION_FLAG_UNCACHED;
break;
case MMU_DESCRIPTOR_L1_TYPE_DEVICE_SHARED:
case MMU_DESCRIPTOR_L1_TYPE_DEVICE_NON_SHARED:
*flags |= VM_MAP_REGION_FLAG_UNCACHED_DEVICE;
break;
default:
break;
}
*flags |= VM_MAP_REGION_FLAG_PERM_READ;
switch (l1Entry & MMU_DESCRIPTOR_L1_AP_MASK) {
case MMU_DESCRIPTOR_L1_AP_P_RO_U_NA:
break;
case MMU_DESCRIPTOR_L1_AP_P_RW_U_NA:
*flags |= VM_MAP_REGION_FLAG_PERM_WRITE;
break;
case MMU_DESCRIPTOR_L1_AP_P_RO_U_RO:
*flags |= VM_MAP_REGION_FLAG_PERM_USER;
break;
case MMU_DESCRIPTOR_L1_AP_P_RW_U_RW:
*flags |= VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE;
break;
default:
break;
}
if (!(l1Entry & MMU_DESCRIPTOR_L1_SECTION_XN)) {
*flags |= VM_MAP_REGION_FLAG_PERM_EXECUTE;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
7.3.3 OsCvtPte2FlagsToAttrs函数和OsCvtPte2AttsToFlags函数
和上一小节非常类似,上节是L1 Section类型页表项MMU属性和内存区域标签属性的相互转换,本节的2个函数是L2页表项MMU属性和内存区域标签属性的相互转换。函数OsCvtPte2FlagsToAttrs()
把内存区域映射标签属性转换为L2页表项MMU属性,又分为2个函数,分别是⑴处的函数OsCvtPte2CacheFlagsToMMUFlags()
和⑵处的OsCvtPte2AccessFlagsToMMUFlags()
。OsCvtPte2CacheFlagsToMMUFlags()
函数主要判断内存映射区域的低2位缓存标签属性的转换。OsCvtPte2AccessFlagsToMMUFlags()
函数用于映射标签属性的2-4位访问权限部分的转换。代码比较简单不再赘述。
⑶处的函数OsCvtPte2AttsToFlags()
是上述函数OsCvtPte2FlagsToAttrs
的逆过程,用于把L2页表项的MMU标签属性转换为内存区域映射标签属性。自行阅读代码,不再逐行分析。
⑴ STATIC UINT32 OsCvtPte2CacheFlagsToMMUFlags(UINT32 flags)
{
UINT32 mmuFlags = 0;
switch (flags & VM_MAP_REGION_FLAG_CACHE_MASK) {
case VM_MAP_REGION_FLAG_CACHED:
#ifdef LOSCFG_KERNEL_SMP
mmuFlags |= MMU_DESCRIPTOR_L2_SHAREABLE;
#endif
mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_NORMAL_WRITE_BACK_ALLOCATE;
break;
case VM_MAP_REGION_FLAG_STRONGLY_ORDERED:
mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_STRONGLY_ORDERED;
break;
case VM_MAP_REGION_FLAG_UNCACHED:
mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_NORMAL_NOCACHE;
break;
case VM_MAP_REGION_FLAG_UNCACHED_DEVICE:
mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_DEVICE_SHARED;
break;
default:
return LOS_ERRNO_VM_INVALID_ARGS;
}
return mmuFlags;
}
⑵ STATIC UINT32 OsCvtPte2AccessFlagsToMMUFlags(UINT32 flags)
{
UINT32 mmuFlags = 0;
switch (flags & (VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE)) {
case 0:
mmuFlags |= MMU_DESCRIPTOR_L1_AP_P_NA_U_NA;
break;
case VM_MAP_REGION_FLAG_PERM_READ:
case VM_MAP_REGION_FLAG_PERM_USER:
mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RO_U_NA;
break;
case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ:
mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RO_U_RO;
break;
case VM_MAP_REGION_FLAG_PERM_WRITE:
case VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RW_U_NA;
break;
case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE:
case VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE:
mmuFlags |= MMU_DESCRIPTOR_L2_AP_P_RW_U_RW;
break;
default:
break;
}
return mmuFlags;
}
/* convert user level mmu flags to L2 descriptors flags */
STATIC UINT32 OsCvtPte2FlagsToAttrs(UINT32 flags)
{
UINT32 mmuFlags;
mmuFlags = OsCvtPte2CacheFlagsToMMUFlags(flags);
if (mmuFlags == LOS_ERRNO_VM_INVALID_ARGS) {
return mmuFlags;
}
mmuFlags |= OsCvtPte2AccessFlagsToMMUFlags(flags);
if (!(flags & VM_MAP_REGION_FLAG_PERM_EXECUTE)) {
mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_SMALL_PAGE_XN;
} else {
mmuFlags |= MMU_DESCRIPTOR_L2_TYPE_SMALL_PAGE;
}
if (flags & VM_MAP_REGION_FLAG_PERM_USER) {
mmuFlags |= MMU_DESCRIPTOR_L2_NON_GLOBAL;
}
return mmuFlags;
}
⑶ STATIC VOID OsCvtPte2AttsToFlags(PTE_T l1Entry, PTE_T l2Entry, UINT32 *flags)
{
*flags = 0;
/* NS flag is only present on L1 entry */
if (l1Entry & MMU_DESCRIPTOR_L1_PAGETABLE_NON_SECURE) {
*flags |= VM_MAP_REGION_FLAG_NS;
}
switch (l2Entry & MMU_DESCRIPTOR_L2_TEX_TYPE_MASK) {
case MMU_DESCRIPTOR_L2_TYPE_STRONGLY_ORDERED:
*flags |= VM_MAP_REGION_FLAG_STRONGLY_ORDERED;
break;
case MMU_DESCRIPTOR_L2_TYPE_NORMAL_NOCACHE:
*flags |= VM_MAP_REGION_FLAG_UNCACHED;
break;
case MMU_DESCRIPTOR_L2_TYPE_DEVICE_SHARED:
case MMU_DESCRIPTOR_L2_TYPE_DEVICE_NON_SHARED:
*flags |= VM_MAP_REGION_FLAG_UNCACHED_DEVICE;
break;
default:
break;
}
*flags |= VM_MAP_REGION_FLAG_PERM_READ;
switch (l2Entry & MMU_DESCRIPTOR_L2_AP_MASK) {
case MMU_DESCRIPTOR_L2_AP_P_RO_U_NA:
break;
case MMU_DESCRIPTOR_L2_AP_P_RW_U_NA:
*flags |= VM_MAP_REGION_FLAG_PERM_WRITE;
break;
case MMU_DESCRIPTOR_L2_AP_P_RO_U_RO:
*flags |= VM_MAP_REGION_FLAG_PERM_USER;
break;
case MMU_DESCRIPTOR_L2_AP_P_RW_U_RW:
*flags |= VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_WRITE;
break;
default:
break;
}
if ((l2Entry & MMU_DESCRIPTOR_L2_TYPE_MASK) != MMU_DESCRIPTOR_L2_TYPE_SMALL_PAGE_XN) {
*flags |= VM_MAP_REGION_FLAG_PERM_EXECUTE;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
小结
本文介绍了MMU虚实映射的基本概念,运行机制,分析了映射初始化、映射查询、映射虚拟内存和物理内存,解除虚实映射,更改映射属性,重新映射等常用接口的代码。
如果大家想更加深入的学习 OpenHarmony 开发的内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:
搭建开发环境 Windows 开发环境的搭建 Ubuntu 开发环境搭建 Linux 与 Windows 之间的文件共享 ……
构建子系统 启动流程 子系统 分布式任务调度子系统 分布式通信子系统 驱动子系统 ……
写在最后
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙: 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://qr21.cn/FV7h05
data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/maniuT/article/details/139653578","extend1":"pc","ab":"new"}">>
id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"> class="blog_extension blog_extension_type2" id="blog_extension">
class="extension_official" data-report-click="{"spm":"1001.2101.3001.6471"}" data-report-view="{"spm":"1001.2101.3001.6471"}">
class="blog_extension_card_left">
class="blog_extension_card_cont">
鸿蒙开发学习资料领取!!!
class="blog_extension_card_cont_r">
微信名片
评论记录:
回复评论: