日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

optee内存管理和页表建立

發布時間:2025/3/21 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 optee内存管理和页表建立 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

        • 1、armv8的頁表定義
        • 2、rodata section指向內存的結構體
        • 3、內存的分類和注冊
        • 3、內存的屬性(type)
        • 4、頁表的構建

1、armv8的頁表定義

透過事務看本質,頁表里都有什么? 如下圖描述了頁表中的一個entry信息,而我們軟件做的工作,其實就是針對每一個頁面的管理,去填充一個entry, 一個entry對應一個頁面, entry中包含頁面地址和內存的一些屬性。把所有的entry放到一起,就構成了頁表www

2、rodata section指向內存的結構體

rodata section的地址段

*(.rodata .rodata.*)/** 8 to avoid unwanted padding between __start_ta_head_section* and the first structure in ta_head_section, in 64-bit* builds*/. = ALIGN(8);__start_ta_head_section = . ;KEEP(*(ta_head_section))__stop_ta_head_section = . ;. = ALIGN(8);__start_phys_mem_map_section = . ;KEEP(*(phys_mem_map_section))__end_phys_mem_map_section = . ;. = ALIGN(8);__start_phys_sdp_mem_section = . ;KEEP(*(phys_sdp_mem_section))__end_phys_sdp_mem_section = . ;. = ALIGN(8);__start_phys_nsec_ddr_section = . ;KEEP(*(phys_nsec_ddr_section))__end_phys_nsec_ddr_section = . ;. = ALIGN(8);__start_phys_ddr_overall_section = . ;KEEP(*(phys_ddr_overall_section))__end_phys_ddr_overall_section = . ;

可以看出在rodata中定義了如下section:

  • ta_head_section
  • phys_mem_map_section
  • phys_sdp_mem_section
  • phys_nsec_ddr_section
  • phys_ddr_overall_section

指向內存的結構體:

struct core_mmu_phys_mem {const char *name;enum teecore_memtypes type;__extension__ union {paddr_t addr;};__extension__ union {paddr_size_t size;}; };

注:在section段落中的,每一個core_mmu_phys_mem數據類型,都代表這一塊region.

3、內存的分類和注冊

在optee中注冊內存的宏有:

  • register_phys_mem 將注冊的內存地址添加到phys_mem_map_section段
  • register_sdp_mem 將注冊的內存地址添加到phys_sdp_mem_section段, 注意:sdp 應該是 secure device peripheral的意思
  • register_dynamic_shm 將注冊的內存地址添加到phys_nsec_ddr_section段
  • register_ddr 將注冊的內存地址添加到phys_ddr_overall_section段

以為register_phys_mem為例,該宏就是在.rodata的__start_phys_mem_map_section的section段定義一個struct core_mmu_phys_mem結構體類型的數據中,指向注冊的這塊mem的物理地址.

#define __register_memory2(_name, _type, _addr, _size, _section, _id) \static const struct core_mmu_phys_mem __phys_mem_ ## _id \__used __section(_section) = \{ .name = _name, .type = _type, .addr = _addr, .size = _size }#define __register_memory2_ul(_name, _type, _addr, _size, _section, _id) \__register_memory2(_name, _type, _addr, _size, _section, _id) #endif#define __register_memory1(name, type, addr, size, section, id) \__register_memory2(name, type, addr, size, #section, id)#define __register_memory1_ul(name, type, addr, size, section, id) \__register_memory2_ul(name, type, addr, size, #section, id)#define register_phys_mem(type, addr, size) \__register_memory1(#addr, (type), (addr), (size), \phys_mem_map_section, __COUNTER__)

在core/arch/arm/plat_xxx/main.c中,注冊這些內存:
可以注冊多塊物理內存:

register_phys_mem(xxx0_TYPE, xxx0_PA_BASE, xxx_SIZE); register_phys_mem(xxx1_TYPE, xxx1_PA_BASE, xxx1_SIZE);

可以注冊多個IO設備:

register_sdp_mem(DRM_VPU1_BASE, DRM_VPU1_BASE); register_sdp_mem(DRM_VPU2_BASE, DRM_VPU2_BASE);

3、內存的屬性(type)

在注冊內存的時候,其實就是將包含name、type、addr、size四個元素的結構體,填寫到了section段落,而type對應的就是內存的屬性,對應著teecore_memtypes類型:

在optee中,有如下十幾種type

enum teecore_memtypes {MEM_AREA_END = 0,MEM_AREA_TEE_RAM,MEM_AREA_TEE_RAM_RX,MEM_AREA_TEE_RAM_RO,MEM_AREA_TEE_RAM_RW,MEM_AREA_TEE_COHERENT,MEM_AREA_TEE_ASAN,MEM_AREA_TA_RAM,MEM_AREA_NSEC_SHM,MEM_AREA_RAM_NSEC,MEM_AREA_RAM_SEC,MEM_AREA_IO_NSEC,MEM_AREA_IO_SEC,MEM_AREA_RES_VASPACE,MEM_AREA_SHM_VASPACE,MEM_AREA_TA_VASPACE,MEM_AREA_PAGER_VASPACE,MEM_AREA_SDP_MEM,MEM_AREA_DDR_OVERALL,MEM_AREA_MAXTYPE };

4、頁表的構建

在optee中,定義一個region的靜態數組,CFG_MMAP_REGIONS=127, 可以存放127塊region

static struct tee_mmap_regionstatic_memory_map[CFG_MMAP_REGIONS + 1];struct tee_mmap_region {unsigned int type; /* enum teecore_memtypes */unsigned int region_size;paddr_t pa;vaddr_t va;size_t size;uint32_t attr; /* TEE_MATTR_* above */ };

在構建頁表之前,先調用init_mem_map函數,將內存中已注冊了的region讀取到static_memory_map這個靜態數組中

init_mem_map(static_memory_map, ARRAY_SIZE(static_memory_map));

init_mem_map()函數原型

在init_mem_map讀取section region到static_memory_map的過程中,還會調用core_mmu_type_to_attr函數,將注冊時寫入的內存屬性(type)轉換位memory attribute
這里返回的memory attribute是一個32bit的值,而armv8要求的是64bit的。

uint32_t core_mmu_type_to_attr(enum teecore_memtypes t) {const uint32_t attr = TEE_MATTR_VALID_BLOCK;const uint32_t cached = TEE_MATTR_CACHE_CACHED << TEE_MATTR_CACHE_SHIFT;const uint32_t noncache = TEE_MATTR_CACHE_NONCACHE <<TEE_MATTR_CACHE_SHIFT;switch (t) {case MEM_AREA_TEE_RAM:return attr | TEE_MATTR_SECURE | TEE_MATTR_PRWX | cached;case MEM_AREA_TEE_RAM_RX:return attr | TEE_MATTR_SECURE | TEE_MATTR_PRX | cached;case MEM_AREA_TEE_RAM_RO:return attr | TEE_MATTR_SECURE | TEE_MATTR_PR | cached;case MEM_AREA_TEE_RAM_RW:case MEM_AREA_TEE_ASAN:return attr | TEE_MATTR_SECURE | TEE_MATTR_PRW | cached;case MEM_AREA_TEE_COHERENT:return attr | TEE_MATTR_SECURE | TEE_MATTR_PRWX | noncache;case MEM_AREA_TA_RAM:return attr | TEE_MATTR_SECURE | TEE_MATTR_PRW | cached;case MEM_AREA_NSEC_SHM:return attr | TEE_MATTR_PRW | cached;case MEM_AREA_IO_NSEC:return attr | TEE_MATTR_PRW | noncache;case MEM_AREA_IO_SEC:return attr | TEE_MATTR_SECURE | TEE_MATTR_PRW | noncache;case MEM_AREA_RAM_NSEC:return attr | TEE_MATTR_PRW | cached;case MEM_AREA_RAM_SEC:return attr | TEE_MATTR_SECURE | TEE_MATTR_PRW | cached;case MEM_AREA_RES_VASPACE:case MEM_AREA_SHM_VASPACE:return 0;case MEM_AREA_PAGER_VASPACE:return TEE_MATTR_SECURE;default:panic("invalid type");} }

在創建頁表的時候會將32位的內存屬性,轉換成64的內存屬性之后,再填充到頁表的entry中
core_init_mmu_tables()—>core_mmu_map_region()—>core_mmu_set_entry()—>core_mmu_set_entry_primitive()

void core_mmu_set_entry_primitive(void *table, size_t level, size_t idx,paddr_t pa, uint32_t attr) {uint64_t *tbl = table;uint64_t desc = mattr_to_desc(level, attr);tbl[idx] = desc | pa; }static uint64_t mattr_to_desc(unsigned level, uint32_t attr) {uint64_t desc;uint32_t a = attr;if (a & TEE_MATTR_HIDDEN_BLOCK)return INVALID_DESC | HIDDEN_DESC;if (a & TEE_MATTR_HIDDEN_DIRTY_BLOCK)return INVALID_DESC | HIDDEN_DIRTY_DESC;if (a & TEE_MATTR_TABLE)return TABLE_DESC;if (!(a & TEE_MATTR_VALID_BLOCK))return 0;if (a & (TEE_MATTR_PX | TEE_MATTR_PW))a |= TEE_MATTR_PR;if (a & (TEE_MATTR_UX | TEE_MATTR_UW))a |= TEE_MATTR_UR;if (a & TEE_MATTR_UR)a |= TEE_MATTR_PR;if (a & TEE_MATTR_UW)a |= TEE_MATTR_PW;if (level == 3)desc = L3_BLOCK_DESC;elsedesc = BLOCK_DESC;if (!(a & (TEE_MATTR_PX | TEE_MATTR_UX)))desc |= UPPER_ATTRS(XN);if (!(a & TEE_MATTR_PX))desc |= UPPER_ATTRS(PXN);if (a & TEE_MATTR_UR)desc |= LOWER_ATTRS(AP_UNPRIV);if (!(a & TEE_MATTR_PW))desc |= LOWER_ATTRS(AP_RO);/* Keep in sync with core_mmu.c:core_mmu_mattr_is_ok */switch ((a >> TEE_MATTR_CACHE_SHIFT) & TEE_MATTR_CACHE_MASK) {case TEE_MATTR_CACHE_NONCACHE:desc |= LOWER_ATTRS(ATTR_DEVICE_INDEX | OSH);break;case TEE_MATTR_CACHE_CACHED:desc |= LOWER_ATTRS(ATTR_IWBWA_OWBWA_NTR_INDEX | ISH);break;default:/** "Can't happen" the attribute is supposed to be checked* with core_mmu_mattr_is_ok() before.*/panic();}if (a & (TEE_MATTR_UR | TEE_MATTR_PR))desc |= LOWER_ATTRS(ACCESS_FLAG);if (!(a & TEE_MATTR_GLOBAL))desc |= LOWER_ATTRS(NON_GLOBAL);desc |= a & TEE_MATTR_SECURE ? 0 : LOWER_ATTRS(NS);return desc; }

下圖是一個頁表創建的過程:

總結

以上是生活随笔為你收集整理的optee内存管理和页表建立的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。