enclave_mm.c 基于PMP(Physical Memory Protection,物理内存保护) 和伙伴系统(Buddy System) 的内存区域(region)管理逻辑,主要用于安全监控器(SM,Security Monitor)中对enclave(安全区)内存的隔离、分配和释放。核心逻辑围绕“内存区域的初始化、分配、释放”以及“PMP权限控制”展开,以下是详细分析:
一、核心数据结构
内存区域管理依赖以下关键数据结构,用于跟踪内存状态和PMP配置:
-
mm_regions数组
类型:struct mm_region_t mm_regions[N_PMP_REGIONS]
作用:存储所有可用的内存区域信息,每个元素对应一个由PMP保护的物理内存块。
关键成员:valid:标记区域是否有效(已初始化)。paddr/size:区域的物理起始地址和大小(必须是2的幂,且不小于一页)。mm_list_head:指向伙伴系统的链表头,用于管理该区域内的空闲内存块(基于伙伴系统)。
-
pmp_bitmap位图
类型:unsigned long pmp_bitmap
作用:跟踪PMP寄存器的使用状态,每一位对应一个PMP索引(如bit 0对应PMP 0,bit 1对应PMP 1),置位表示该PMP已被占用。 -
伙伴系统相关结构
struct mm_list_head_t:伙伴系统中相同“阶(order)”的内存块链表头,用于快速查找可用块。order:内存块的阶(大小为2^order字节)。prev_list_head/next_list_head:链表指针,连接不同阶的链表头。mm_list:指向当前阶的空闲内存块链表。
struct mm_list_t:单个内存块的元数据。order:块的阶。prev_mm/next_mm:链表指针,连接同阶的其他空闲块。
二、核心流程分析
1. 内存区域初始化(mm_init)
作用:将一块物理内存初始化为受PMP保护的enclave内存区域,并初始化伙伴系统用于后续分配。
流程:
- 参数检查:验证内存大小是否为2的幂、地址是否按大小对齐、不小于一页(
check_mem_size)。 - 冲突检查:确保新区域不与安全监控器(SM)内存或现有区域重叠(
check_mem_overlap)。 - PMP分配:通过
pmp_bitmap找到空闲的PMP索引,标记为占用,并配置PMP寄存器(set_pmp_and_sync),初始权限为“无访问权限(PMP_NO_PERM)”,防止未授权访问。 - 伙伴系统初始化:在区域起始地址创建伙伴系统的根节点(
mm_list_head和mm_list),将整个区域作为一个大内存块加入伙伴系统。
2. 内存分配(mm_alloc)
作用:从已初始化的区域中分配一块满足大小要求的内存(基于伙伴系统)。
流程:
- 计算阶数:根据请求大小计算所需的“阶(order)”(如8KB对应order=3,因为
2^3=8)。 - 遍历区域:对每个已初始化的区域,尝试从其伙伴系统中分配一块不小于所需阶的内存块(
alloc_one_region)。 - 块拆分:若找到的块阶数大于所需阶,将其拆分为 smaller 块(每次拆分阶数减1),剩余部分插回伙伴系统(
insert_mm_region)。 - 返回地址:返回分配的物理地址,并清零内存(
sbi_memset)。
3. 内存释放(mm_free)
作用:将内存块归还给伙伴系统,并尝试合并相邻块以减少碎片(伙伴系统核心特性)。
流程:
- 参数检查:验证释放的内存大小是否为2的幂、地址对齐。
- 查找区域:确定释放的内存属于哪个已初始化的区域。
- 插入伙伴系统:将内存块插入对应阶的链表,并尝试合并相邻的同阶块(
merge_regions),合并后阶数加1,直到无法合并或达到区域最大阶。
4. PMP权限管理
为了在enclave初始化、运行等阶段灵活控制内存访问权限,提供了以下函数:
grant_kernel_access:临时允许内核访问enclave内存(如初始化enclave或配置页表),通过PMP 0配置权限为“读写执行(PMP_R|W|X)”。retrieve_kernel_access:撤销内核对enclave内存的访问权限(目前未实现,仅返回0)。grant_enclave_access:允许enclave访问自身内存,配置PMP和SPMP(Supervisor PMP)权限为“读写执行”(目前部分实现)。retrieve_enclave_access:撤销enclave对内存的访问权限(目前部分实现)。
三、核心逻辑总结
- 基于PMP的内存隔离:通过PMP寄存器将enclave内存与其他区域隔离,初始权限为“无访问”,仅在需要时(如内核初始化enclave)临时开放权限。
- 伙伴系统的内存管理:采用伙伴系统实现高效的内存分配与释放,支持块的拆分与合并,减少碎片。
- 线程安全:通过自旋锁(
pmp_bitmap_lock)保证多线程环境下对pmp_bitmap和伙伴系统链表的操作原子性。
四、关键细节与限制
- 区域数量限制:最多支持
N_PMP_REGIONS个区域(由PMP寄存器数量决定)。 - 大小限制:内存块大小必须是2的幂,且不小于一页(
RISCV_PGSIZE)。 - PMP配置:目前部分PMP操作被注释(
#if 0),可能处于开发阶段,实际权限控制需依赖完整实现。
整体而言,这段代码是安全监控器中enclave内存管理的核心,通过PMP实现硬件级隔离,通过伙伴系统实现高效的内存分配,为enclave提供安全且灵活的内存环境。
五、系统内核 飞地虚拟地址映射逻辑 penglai-enclave-page
这段代码实现了基于页表的内存管理系统,主要用于安全监控器(Security Monitor)中管理enclave(安全区)的内存映射。核心逻辑围绕“页表遍历”、“虚拟地址到物理地址映射”以及“内存分配释放”展开,以下是详细分析:
5.1、核心数据结构与设计思想
-
内存页管理
- 使用链表(
struct list_head free_mem)管理空闲页,每个节点为struct free_mem_t,包含虚拟地址vaddr。 - 通过
init_free_mem初始化链表,将连续物理内存按页分割并加入链表。
- 使用链表(
-
页表结构
- 基于RISC-V架构的多级页表(
RISCV_PT_LEVEL级,通常为3级)。 - 每个页表项(PTE)包含物理页号(PPN)和权限位(如
PTE_V表示有效)。
- 基于RISC-V架构的多级页表(
-
地址转换
va2ppn:虚拟地址→物理页号(右移页大小位数)。pte2pa:页表项→物理地址(提取PPN并左移页大小位数)。
5.2、关键函数与流程分析
5.2.1. 页表操作核心函数
static pt_entry_t * walk_enclave_pt(struct list_head* free_mem,
pt_entry_t* enclave_root_pt,
vaddr_t vaddr, bool create);
- 作用:遍历页表,查找或创建虚拟地址对应的页表项。
- 流程:
- 从根页表(
enclave_root_pt)开始,逐级解析虚拟地址中的索引。 - 若中间页表项不存在且
create=true,则分配新页表页(create_ptd_page)。 - 返回最终页表项的指针。
- 从根页表(
- 应用:为内存映射和分配提供底层支持。
5.2.2. 内存分配与映射
vaddr_t enclave_alloc_page(enclave_mem_t* enclave_mem, vaddr_t vaddr, unsigned long flags);
vaddr_t map_va2pa(enclave_mem_t* enclave_mem, vaddr_t vaddr, paddr_t paddr, unsigned long flags);
enclave_alloc_page- 分配一个空闲页(从
free_mem链表获取),并将其映射到指定虚拟地址vaddr。 - 设置页表项权限(
flags),如读写执行权限。
- 分配一个空闲页(从
map_va2pa- 将物理地址
paddr映射到虚拟地址vaddr,用于已有物理内存的映射(如设备内存)。 - 同样设置页表项权限。
- 将物理地址
5.2.3. 初始化与销毁
void enclave_mem_int(enclave_mem_t* enclave_mem, vaddr_t vaddr, int size, paddr_t paddr);
int enclave_mem_destroy(enclave_mem_t * enclave_mem);
enclave_mem_int- 初始化enclave内存管理器:
- 将
vaddr开始的size字节内存按页分割,加入free_mem链表。 - 分配根页表,并设置
enclave_root_pt。 - 预留两个特殊页(注释中提到用于动态分配记录)。
- 将
- 初始化enclave内存管理器:
enclave_mem_destroy- 清理空闲页链表,但未完全实现(注释中标记为
FIXME)。 - 需补充释放页表内存和enclave占用的物理页。
- 清理空闲页链表,但未完全实现(注释中标记为
5.3、核心逻辑总结
-
空闲页管理
- 使用链表实现简单的页分配器,支持初始化、分配和回收。
- 适用于enclave内部的小内存块分配(如栈、堆)。
-
页表操作
- 实现多级页表的递归遍历和动态创建。
- 通过
walk_enclave_pt实现“按需创建”页表,节省内存。
-
映射策略
enclave_alloc_page:分配新页并映射,用于动态内存(如堆)。map_va2pa:将已有物理内存映射到虚拟地址,用于静态内存(如代码段、设备内存)。
5.4、关键细节与限制
-
权限控制
- 通过
flags参数设置页表项权限(如PTE_R、PTE_W、PTE_X)。 - 需配合硬件PMP/SPMP进一步隔离enclave与外部内存。
- 通过
-
性能优化
- 页表遍历涉及多次内存访问,可通过TLB(Translation Lookaside Buffer)缓存加速。
-
未完成的功能
enclave_mem_destroy未完全实现页表回收,可能导致内存泄漏。- 预留的两个特殊页(用于动态分配记录)未实现具体逻辑。
5.5、安全考量
-
地址验证
- 代码未显式检查
vaddr是否在enclave合法范围内,需上层调用者保证。 - 若传入非法地址,可能导致页表污染或越界访问。
- 代码未显式检查
-
权限隔离
- 页表权限与PMP/SPMP需协同工作,确保enclave内存不被外部非法访问。
- 例如,enclave代码段应设置为“只读+可执行”,数据段为“读写”。
5.6、总结
这段代码实现了一个轻量级的enclave内存管理系统,核心是基于多级页表的虚拟内存映射和简单的空闲页链表分配器。它为enclave提供了内存隔离的基础,但需与硬件保护机制(如PMP)结合,才能实现完整的安全隔离。
339

被折叠的 条评论
为什么被折叠?



