optee記憶體管理和頁表建立
1、armv8的頁表定義
透過事務看本質,頁表裡都有什麼? 如下圖描述了頁表中的一個entry資訊,而我們軟體做的工作,其實就是針對每一個頁面的管理,去填充一個entry, 一個entry對應一個頁面, entry中包含頁面地址和記憶體的一些屬性。把所有的entry放到一起,就構成了頁表
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_region
static_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;
else
desc = 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;
}
相關文章
- 作業系統記憶體管理:頁、頁表項和頁框之間的關係作業系統記憶體
- Windows記憶體管理-分頁Windows記憶體
- [轉帖]關於記憶體管理:計算頁表大小記憶體
- Linux 的記憶體分頁管理Linux記憶體
- Linux的記憶體分頁管理Linux記憶體
- 記憶體管理 記憶體管理概述記憶體
- 段頁式記憶體管理(轉載)記憶體
- 【記憶體管理】頁面分配機制記憶體
- linux記憶體管理(一)實體記憶體的組織和記憶體分配Linux記憶體
- linux記憶體管理(十)- 頁面回收(二)Linux記憶體
- linux記憶體管理(十一)- 頁面遷移Linux記憶體
- 記憶體管理篇——實體記憶體的管理記憶體
- Linux記憶體洩露案例分析和記憶體管理分享Linux記憶體洩露
- 【記憶體管理】記憶體佈局記憶體
- JVM記憶體管理和垃圾回收JVM記憶體
- Node - 記憶體管理和垃圾回收記憶體
- Linux-記憶體和磁碟管理Linux記憶體
- 【大頁記憶體】Oracle資料庫配置大頁記憶體記憶體Oracle資料庫
- 記憶體管理兩部曲之實體記憶體管理記憶體
- Java的記憶體 -JVM 記憶體管理Java記憶體JVM
- Go:記憶體管理與記憶體清理Go記憶體
- MySQL記憶體管理,記憶體分配器和作業系統MySql記憶體作業系統
- 理解 iOS 和 macOS 的記憶體管理iOSMac記憶體
- 【記憶體管理】Oracle AMM自動記憶體管理詳解記憶體Oracle
- 記憶體管理兩部曲之虛擬記憶體管理記憶體
- delphi記憶體表記憶體
- 記憶體表(FDMEMTABLE)記憶體
- JavaScript 記憶體管理JavaScript記憶體
- iOS 記憶體管理iOS記憶體
- Android記憶體管理Android記憶體
- OC記憶體管理記憶體
- 記憶體管理-swMemoryGlobal記憶體
- Flink記憶體管理記憶體
- MySQL記憶體管理MySql記憶體
- 【記憶體管理】Oracle如何使用ASMM自動共享記憶體管理記憶體OracleASM
- 記憶體管理Release和Retain實現原理記憶體AI
- C++記憶體管理:new / delete 和 cookieC++記憶體deleteCookie
- Linux實體記憶體管理Linux記憶體