Changchun Master Li

[RPi bring up] 树莓派实现简单的内存管理

2023-06-02

受到xv6的启发,我也想给我襁褓之中的“操作系统”赋予内存管理功能。一个完善的内存管理需要考虑很多failover,缓存、tlb、page replacement等诸多功能,导致实际中使用的内存管理系统非常复杂。我决定我的内存管理从设计开始就极度简化,只实现最基础的功能。

设计

把所有内存组织成一个链表kmem,用kalloc和kfree管理物理内存分配,粒度为1MB。128MB内存被分成128块

1
2
kalloc 分配连续1MB的物理内存
kfree 释放空间

虚拟内存布局

在内核启动后,打开mmu,进入虚拟内存布局。

  • 整个128MB物理内存被映射到0xC000 0000的高地址,作为内核空间
  • 0x2000 0000的外设IO地址仍然被映射到原来的位置,这样在启动mmu后,mmio操作不需要改变base address
  • 低1MB的虚拟地址控制作为用户空间,为了简化,不打开缓存、tlb功能,不实现内存页置换算法。

这里用三个内核函数实现

1
2
3
setupkvm     在初始化的时候,建立虚拟内存映射
createuvm 建立用户空间内存描述符
loaduvm 载入用户空间内存描述符

实现

首先,需要修改kernel.ld 链接文件,把text首地址改成

1
. = 0xC0008000;

保证跳转指令中的地址匹配虚拟地址。

也可以用linker script的at指令来改变实际load address。我们在一开始entry.S中设置好栈就开启mmu,因此整个image可以都load到0xC0008000,而不需要具体控制某一个section的 load address。

接下来,通过setupkvm函数,修改位于0x0000-0x4000的一级页表,映射虚拟内存布局。最后通过操作cp15协处理器打开mmu

1
mcr p15, 0, 1, c3, 0

设置domain 0位client模式(user空间页描述符为domain 0)

1
mcr p15, 0, 0, c2, c0

设置ttbr为0,一级页表位于0x0000-0x4000,共4GB/1MB = 4096个页描述符,16KB

1
mcr p15, 0, 1, c1, c0, 0

启动mmu

最后我们来验证一下,mmu是否开启成功了

1
2
3
4
5
6
7
8
9
10
// 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

1
git clone -b memory https://github.com/996refuse/emperorOS.git
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章