内存管理
上层俩接口
字节分配bytes alloc
平常string,vector类型走这里
实现rust的标准trait
基于page分配的
pages alloc
按page分配的接口,内核大量用,应用不用
比较简单,直接暴露了GLOBAL_ALLOCATOR的实例
实例本身能访问到页分配的分配器
驱动做文件管理的时候需要充buffer
页表本身需要申请页
俩图的意思有点重复
bytes alloc(balloc)和page alloc(palloc)的关系
最初page页分配器管理所有的物理内存页
b alloc会从page分配器里申请一部分初始内存
用于作为存储的一个池
分配不足后会要求page分配器给自己追加
一般按照翻倍方式来要求
间init和alloc
算法组件接口
只需要实现两个trait
base就是初始化要求的长度和追加
byte allocator就是分配释放和监控
见BaseAllocator和ByteAllocator
ReadPFlash
qemu会初始化一块存储设备
会加载到固定的内存区域,MMIO
读不需要驱动,写需要驱动
pflash#0不能用,kernel作为扩展的固件使用
#1给使用者来用,地址是0x2200_0000
arceos unikernel启动时包括mmu,但只有1g空间,boot阶段,恒等映射
不包含设备MMIO区间
axruntim在指定feature paging的时候能进行一次remap重映射
会映射更大的区间
unikernel地址空间
unikernel没有用户地址空间
如果没有启用mmu,直接看到的是物理地址空间
启用mmu后建立了一个虚拟地址空间
riscv64-qemu物理地址空间
对于riscv64的体系结构,入口地址都是0x8020_0000以上是内核各个段以连续地址存放
0x8000_0000会放SBI,这个就是riscv64的默认物理开始地址
启动的时候先从0x8000_0000进入SBI,SBI最后会跳转到0x8020_0000开始进入内核
上面是高端地址
下面是低端地址,跟设备相关
plic 是全局中断控制器
uart 串口设备
virtio 用于注册io的
pci设备
lds 指导如何布局这些各个segment
SBI需要配置FW_TEXT_START就是那个0x8000_0000
剩下的设备地址是qemu定义的,如果需要可以将ldt导出成人类可读模式
分页机制
首先一个寄存器组
包含根页表地址
和模式
riscv64就是satp最低12位是根页表地址,默认模式是三级页表
然后指向页表到物理地址
对应到架构如图
axhal 对应寄存器组
page_table 对应页表
page_table_entry 对应页表项pte
分页两个阶段
早期boot阶段,mmu,恒等映射
需要建立两个项,第一个与物理地址完全一样,在虚拟空间内
第二部分是希望物理空间存在的高地址区域
0xffff_ffc0_8000_0000是个固定的偏移
第一阶段直接映射,左右一样
第二阶段给指令指针寄存器pc和栈寄存器sp等,加offset偏移就是0xffff_ffc0_0000_0000
进入最终的空间
具体代码实现
在boot.rs里面
先用link_section定义根页表
使用init_boot_page_table初始化页表
init_mmu启用页表
在init_boot_page_table具体调用里映射俩区域
在init_mmu里设置模式,Sv39和根页表地址
第二阶段重映射
低端区域映射到虚拟空间
sbi的映射去掉,不应该被内核态访问
重映射上面的segment会重设置权限
重映射示例
pageing使得init_memory_management生效
里面创建一个内核的地址空间
通过axhal里面一个设置根页表操作(体系结构无关操作),将根页表写入刚才说的satp寄存器
new_kernel_aspace是先创建一个空的地址空间
new_empty最重要是通过PageTable来申请一个新的page
小结

Generated 2025-05-05 04:17:35 +0000
25bcfca-dirty 2025-05-04 14:47:56 +0000