鸿蒙轻内核A核源码分析系列五 虚实映射(7)虚实映射Flag属性 原创 精华

zhushangyuan_
发布于 2021-12-7 21:48
浏览
2收藏

7、Flag标签属性

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

在学习函数LOS_ArchMmuMap()代码时,我们已经了解了虚拟内存如何映射到物理内存,在映射的时候,可以通过UINT 32 flags参数定一些标签属性信息。本节,我们具体了解下内存标签属性信息。先了解下MMU标签属性,然后看看映射内存区间时的映射虚实信息,最后了解下属性信息转换函数。

7.1 MMU标签属性

在映射的时候,对于内存页可以指定一些内存属性,比如权限、内存类型、缓存策略等等。更多信息参考ARM官网资料《ARM® Cortex™-A Series Version: 4.0 Programmer’s Guide》,我们只快速摘录些关键信息。L1页表项的格式如下图所示,其中Type extension (TEX), Shareable (S), Access Permission (AP, APX)Cacheable (C)Bufferable (B)位表示内存属性信息。在arch\arm\arm\include\los_mmu_descriptor_v6.h文件中定义了MMU L1页表内存属性相关的宏,如下。

鸿蒙轻内核A核源码分析系列五 虚实映射(7)虚实映射Flag属性-鸿蒙开发者社区

/* TEX CB */
#define MMU_DESCRIPTOR_L1_TEX_SHIFT                             12 /* type extension field shift */
#define MMU_DESCRIPTOR_L1_TEX(x)                                \
    ((x) << MMU_DESCRIPTOR_L1_TEX_SHIFT) /* type extension */
#define MMU_DESCRIPTOR_L1_TYPE_STRONGLY_ORDERED                 \
    (MMU_DESCRIPTOR_L1_TEX(MMU_DESCRIPTOR_TEX_0) | MMU_DESCRIPTOR_NON_CACHEABLE)
#define MMU_DESCRIPTOR_L1_TYPE_NORMAL_NOCACHE                   \
    (MMU_DESCRIPTOR_L1_TEX(MMU_DESCRIPTOR_TEX_1) | MMU_DESCRIPTOR_NON_CACHEABLE)
#define MMU_DESCRIPTOR_L1_TYPE_DEVICE_SHARED                    \
    (MMU_DESCRIPTOR_L1_TEX(MMU_DESCRIPTOR_TEX_0) | MMU_DESCRIPTOR_WRITE_BACK_ALLOCATE)
#define MMU_DESCRIPTOR_L1_TYPE_DEVICE_NON_SHARED                \
    (MMU_DESCRIPTOR_L1_TEX(MMU_DESCRIPTOR_TEX_2) | MMU_DESCRIPTOR_NON_CACHEABLE)
#define MMU_DESCRIPTOR_L1_TYPE_NORMAL_WRITE_BACK_ALLOCATE       \
    (MMU_DESCRIPTOR_L1_TEX(MMU_DESCRIPTOR_TEX_1) | MMU_DESCRIPTOR_WRITE_BACK_NO_ALLOCATE)
#define MMU_DESCRIPTOR_L1_TEX_TYPE_MASK                         \
    (MMU_DESCRIPTOR_L1_TEX(MMU_DESCRIPTOR_TEX_MASK) | MMU_DESCRIPTOR_WRITE_BACK_NO_ALLOCATE)

#define MMU_DESCRIPTOR_L1_AP2_SHIFT                             15
#define MMU_DESCRIPTOR_L1_AP2(x)                                ((x) << MMU_DESCRIPTOR_L1_AP2_SHIFT)
#define MMU_DESCRIPTOR_L1_AP2_0                                 (MMU_DESCRIPTOR_L1_AP2(0))
#define MMU_DESCRIPTOR_L1_AP2_1                                 (MMU_DESCRIPTOR_L1_AP2(1))
#define MMU_DESCRIPTOR_L1_AP01_SHIFT                            10
#define MMU_DESCRIPTOR_L1_AP01(x)                               ((x) << MMU_DESCRIPTOR_L1_AP01_SHIFT)
#define MMU_DESCRIPTOR_L1_AP01_0                                (MMU_DESCRIPTOR_L1_AP01(0))
#define MMU_DESCRIPTOR_L1_AP01_1                                (MMU_DESCRIPTOR_L1_AP01(1))
#define MMU_DESCRIPTOR_L1_AP01_3                                (MMU_DESCRIPTOR_L1_AP01(3))
#define MMU_DESCRIPTOR_L1_AP_P_NA_U_NA                          (MMU_DESCRIPTOR_L1_AP2_0 | MMU_DESCRIPTOR_L1_AP01_0)
#define MMU_DESCRIPTOR_L1_AP_P_RW_U_RW                          (MMU_DESCRIPTOR_L1_AP2_0 | MMU_DESCRIPTOR_L1_AP01_3)
#define MMU_DESCRIPTOR_L1_AP_P_RW_U_NA                          (MMU_DESCRIPTOR_L1_AP2_0 | MMU_DESCRIPTOR_L1_AP01_1)
#define MMU_DESCRIPTOR_L1_AP_P_RO_U_RO                          (MMU_DESCRIPTOR_L1_AP2_1 | MMU_DESCRIPTOR_L1_AP01_3)
#define MMU_DESCRIPTOR_L1_AP_P_RO_U_NA                          (MMU_DESCRIPTOR_L1_AP2_1 | MMU_DESCRIPTOR_L1_AP01_1)
#define MMU_DESCRIPTOR_L1_AP_MASK                               (MMU_DESCRIPTOR_L1_AP2_1 | MMU_DESCRIPTOR_L1_AP01_3)

  • 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.

L2页表项的格式如下图所示。在arch\arm\arm\include\los_mmu_descriptor_v6.h文件中定义了MMU L2页表内存属性相关的宏,如下。

鸿蒙轻内核A核源码分析系列五 虚实映射(7)虚实映射Flag属性-鸿蒙开发者社区

#define MMU_DESCRIPTOR_L2_TEX_SHIFT                             6 /* type extension field shift */
#define MMU_DESCRIPTOR_L2_TEX(x)                                \
    ((x) << MMU_DESCRIPTOR_L2_TEX_SHIFT) /* type extension */
#define MMU_DESCRIPTOR_L2_TYPE_STRONGLY_ORDERED                 \
    (MMU_DESCRIPTOR_L2_TEX(MMU_DESCRIPTOR_TEX_0) | MMU_DESCRIPTOR_NON_CACHEABLE)
#define MMU_DESCRIPTOR_L2_TYPE_NORMAL_NOCACHE                   \
    (MMU_DESCRIPTOR_L2_TEX(MMU_DESCRIPTOR_TEX_1) | MMU_DESCRIPTOR_NON_CACHEABLE)
#define MMU_DESCRIPTOR_L2_TYPE_DEVICE_SHARED                    \
    (MMU_DESCRIPTOR_L2_TEX(MMU_DESCRIPTOR_TEX_0) | MMU_DESCRIPTOR_WRITE_BACK_ALLOCATE)
#define MMU_DESCRIPTOR_L2_TYPE_DEVICE_NON_SHARED                \
    (MMU_DESCRIPTOR_L2_TEX(MMU_DESCRIPTOR_TEX_2) | MMU_DESCRIPTOR_NON_CACHEABLE)
#define MMU_DESCRIPTOR_L2_TYPE_NORMAL_WRITE_BACK_ALLOCATE       \
    (MMU_DESCRIPTOR_L2_TEX(MMU_DESCRIPTOR_TEX_1) | MMU_DESCRIPTOR_WRITE_BACK_NO_ALLOCATE)
#define MMU_DESCRIPTOR_L2_TEX_TYPE_MASK                         \
    (MMU_DESCRIPTOR_L2_TEX(MMU_DESCRIPTOR_TEX_MASK) | MMU_DESCRIPTOR_WRITE_BACK_NO_ALLOCATE)
#define MMU_DESCRIPTOR_L2_AP2_SHIFT                             9
#define MMU_DESCRIPTOR_L2_AP2(x)                                ((x) << MMU_DESCRIPTOR_L2_AP2_SHIFT)
#define MMU_DESCRIPTOR_L2_AP2_0                                 (MMU_DESCRIPTOR_L2_AP2(0))
#define MMU_DESCRIPTOR_L2_AP2_1                                 (MMU_DESCRIPTOR_L2_AP2(1))
#define MMU_DESCRIPTOR_L2_AP01_SHIFT                            4
#define MMU_DESCRIPTOR_L2_AP01(x)                               ((x) << MMU_DESCRIPTOR_L2_AP01_SHIFT)
#define MMU_DESCRIPTOR_L2_AP01_0                                (MMU_DESCRIPTOR_L2_AP01(0))
#define MMU_DESCRIPTOR_L2_AP01_1                                (MMU_DESCRIPTOR_L2_AP01(1))
#define MMU_DESCRIPTOR_L2_AP01_3                                (MMU_DESCRIPTOR_L2_AP01(3))
#define MMU_DESCRIPTOR_L2_AP_P_NA_U_NA                          (MMU_DESCRIPTOR_L2_AP2_0 | MMU_DESCRIPTOR_L2_AP01_0)
#define MMU_DESCRIPTOR_L2_AP_P_RW_U_RW                          (MMU_DESCRIPTOR_L2_AP2_0 | MMU_DESCRIPTOR_L2_AP01_3)
#define MMU_DESCRIPTOR_L2_AP_P_RW_U_NA                          (MMU_DESCRIPTOR_L2_AP2_0 | MMU_DESCRIPTOR_L2_AP01_1)
#define MMU_DESCRIPTOR_L2_AP_P_RO_U_RO                          (MMU_DESCRIPTOR_L2_AP2_1 | MMU_DESCRIPTOR_L2_AP01_3)
#define MMU_DESCRIPTOR_L2_AP_P_RO_U_NA                          (MMU_DESCRIPTOR_L2_AP2_1 | MMU_DESCRIPTOR_L2_AP01_1)
#define MMU_DESCRIPTOR_L2_AP_MASK                               (MMU_DESCRIPTOR_L2_AP2_1 | MMU_DESCRIPTOR_L2_AP01_3)
  • 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.

7.2 映射地址区间标签属性

kernel\base\include\los_vm_map.h文件中定义地址区间映射标签属性信息。标签属性信息主要分为4类,如图所示。前2位用于标记释放缓存设备,2-5位用于标记权限信息,6-8位用于标记共享私有等信息,9-19位用于标记stack、heap、data、text、bss、vsdo、mmap、shm、fixed、fixed_noreplace等属性信息。20-23位暂未使用,高8位被共享内存SHM使用。

鸿蒙轻内核A核源码分析系列五 虚实映射(7)虚实映射Flag属性-鸿蒙开发者社区

/* the high 8 bits(24~31) should reserved, shm will use it */
#define     VM_MAP_REGION_FLAG_CACHED               (0<<0)
#define     VM_MAP_REGION_FLAG_UNCACHED             (1<<0)
#define     VM_MAP_REGION_FLAG_UNCACHED_DEVICE      (2<<0) /* only exists on some arches, otherwise UNCACHED */
#define     VM_MAP_REGION_FLAG_STRONGLY_ORDERED     (3<<0) /* only exists on some arches, otherwise UNCACHED */
#define     VM_MAP_REGION_FLAG_CACHE_MASK           (3<<0)
#define     VM_MAP_REGION_FLAG_PERM_USER            (1<<2)
#define     VM_MAP_REGION_FLAG_PERM_READ            (1<<3)
#define     VM_MAP_REGION_FLAG_PERM_WRITE           (1<<4)
#define     VM_MAP_REGION_FLAG_PERM_EXECUTE         (1<<5)
#define     VM_MAP_REGION_FLAG_PROT_MASK            (0xF<<2)
#define     VM_MAP_REGION_FLAG_NS                   (1<<6) /* NON-SECURE */
#define     VM_MAP_REGION_FLAG_SHARED               (1<<7)
#define     VM_MAP_REGION_FLAG_PRIVATE              (1<<8)
#define     VM_MAP_REGION_FLAG_FLAG_MASK            (3<<7)
#define     VM_MAP_REGION_FLAG_STACK                (1<<9)
#define     VM_MAP_REGION_FLAG_HEAP                 (1<<10)
#define     VM_MAP_REGION_FLAG_DATA                 (1<<11)
#define     VM_MAP_REGION_FLAG_TEXT                 (1<<12)
#define     VM_MAP_REGION_FLAG_BSS                  (1<<13)
#define     VM_MAP_REGION_FLAG_VDSO                 (1<<14)
#define     VM_MAP_REGION_FLAG_MMAP                 (1<<15)
#define     VM_MAP_REGION_FLAG_SHM                  (1<<16)
#define     VM_MAP_REGION_FLAG_FIXED                (1<<17)
#define     VM_MAP_REGION_FLAG_FIXED_NOREPLACE      (1<<18)
#define     VM_MAP_REGION_FLAG_INVALID              (1<<19) /* indicates that flags are not specified */
  • 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_READMAP_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;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

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

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;
        }
    }
  • 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虚实映射的基本概念,运行机制,分析了映射初始化、映射查询、映射虚拟内存和物理内存,解除虚实映射,更改映射属性,重新映射等常用接口的代码。由于水平有限,如果内容哪里有误,欢迎指正,不胜感激。感谢阅读,有什么问题,请留言。

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

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
ARM Cortex-A Series Programmer's Guide f.pdf 4.13M 48次下载
已于2021-12-7 23:13:42修改
3
收藏 2
回复
举报
3
2
2
2条回复
按时间正序
/
按时间倒序
wenfei6316
wenfei6316

very nice,特别是flag属性在哪个文件里,之前看了属性转换的函数,并没有明白这些函数还是有分类的

回复
2022-1-6 09:13:04
zhushangyuan_
zhushangyuan_ 回复了 wenfei6316
very nice,特别是flag属性在哪个文件里,之前看了属性转换的函数,并没有明白这些函数还是有分类的

对社区小伙伴有价值,就很开心了

回复
2022-1-6 09:19:53


回复
    相关推荐