阅读本文您不需要掌握的知识有[RPi bring up] [RPi bring up] 树莓派实现简单的内存管理阅读本文您不需要掌握的知识有
高深的操作系统理论
高深的计算机体系结构理论
阅读本文您需要具备
全日制小学生学历及其同等学历 ★★★★★
内存控制和管理 ★★☆☆☆
受到xv6的启发,我也想给我襁褓之中的“操作系统”赋予内存管理功能。一个完善的内存管理需要考虑很多failover,缓存、tlb、page replacement等诸多功能,导致实际中使用的内存管理系统非常复杂。
为此,我决定我的内存管理从设计开始就极度简化,只实现最基础的功能。
设计
把所有内存组织成一个链表kmem,用kalloc和kfree管理物理内存分配,粒度为1MB。128MB内存被分成128块
kalloc 分配连续1MB的物理内存
kfree 释放空间
虚拟内存布局
在内核启动后,打开mmu,进入虚拟内存布局。
- 整个128MB物理内存被映射到0xC000 0000的高地址,作为内核空间
- 0x2000 0000的外设IO地址仍然被映射到原来的位置,这样在启动mmu后,mmio操作不需要改变base address
- 低1MB的虚拟地址控制作为用户空间,为了简化,不打开缓存、tlb功能,不实现内存页置换算法。
这里用三个内核函数实现
setupkvm 在初始化的时候,建立虚拟内存映射
createuvm 建立用户空间内存描述符
loaduvm 载入用户空间内存描述符
实现
首先,需要修改kernel.ld 链接文件,把text首地址改成
. = 0xC0008000;
保证跳转指令中的地址不出错。
也可以用linker script的at指令来改变实际load address。我们在一开始entry.S中设置好栈就开启mmu,因此整个image可以都load到0xC0008000,而不需要具体控制某一个section的 load address。
接下来,通过setupkvm函数,修改位于0x0000-0x4000的一级页表,映射虚拟内存布局。最后通过操作cp15协处理器打开mmu
mcr p15, 0, 1, c3, 0
设置domain 0位client模式(user空间页描述符为domain 0)
mcr p15, 0, 0, c2, c0
设置ttbr为0,一级页表位于0x0000-0x4000,共4GB/1MB = 4096个页描述符,16KB
mcr p15, 0, 1, c1, c0, 0
启动mmu
最后我们来验证一下,mmu是否开启成功了
// mmu test, cp should be high address
unsigned int pc_value;
__asm (
"mov %[result], pc\n\t"
: [result]"=r" (pc_value)
:
:
);
uart_puts("pc_value is :\n\r");
uart_hex(pc_value);
把pc寄存器的值打印出来,如果大于0xC000 0000,则证明mmu开启成功
source code
git clone -b memory https://github.com/996refuse/emperorOS.git
http://blog.74ls74.org/2023/06/02/20230602_rpi_memory_management/