OS - Lab 2: Memory Management
Operating Systems (H) @ Fudan University, fall 2020.
实验简介
实验报告
1 物理内存分配器
实验目标
完成物理内存分配器的分配函数 kalloc 以及回收函数 kfree。
由源代码可知,物理页表位于 kmem.free_list 这个链表里。
1 2 3 | |
对于函数 kalloc,我们需要做的就是从 free_list 链表中取出头节点返回。因此不难得到函数 kalloc 的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
函数 kfree 则是函数 kalloc 的逆过程,也就是将释放的物理页插回 free_list 链表头部。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
2 页表管理
实验目标
完成物理地址的映射函数 map_region 以及回收页表物理空间函数 vm_free。
本过程中,我们需要构建 ttbr0_el1 页表,并将其映射到虚拟地址(高地址)。
在实现映射函数 map_region 前,我们需要先按照要求完成函数 pgdir_walk。根据注释,函数 pgdir_walk 所做的事情是根据提供的虚拟地址 va 找到相应的页表,如果途径的页表项(Page Directory Entry, PDE)不存在,则分配一个新的页表项。
这里我将分配新页表项的逻辑单独封装成一个函数 pde_validate,以提高代码的可读性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
需要注意的是,PDE 中前半段保存的地址应当为物理地址(低地址)。
函数 pgdir_walk 中我们进行了 3 次循环。每次循环,我们根据当前所在层级的 PDE 所保存的物理地址,将其转换为虚拟地址后,再以 va 相应的片段为索引,找到下一级 PDE 所在的虚拟地址。过程中如果 PDE 不存在,则利用函数 pde_validate 分配一个新的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | |
为什么 4 级页表只进行了 3 次循环?这是因为最后一级我们只需要返回 PDE 中地址所指向的页表(Page Table Entry, PTE)地址即可。
对于回收页表物理空间函数 vm_free,我们需要遍历 4 级页表,并将其中的节点全部释放。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
这里我们使用了递归的写法。需要注意的是,pgdir 中 PDE 保存的地址为物理地址,在传给函数 kfree 前需要先转换为虚拟地址。代码中,ENTRYSZ 的值为 512,表示 4 KB 页表中的 PDE 项数(每项的大小为 64 bit = 8 B)。
测试环境
- Ubuntu 18.04.5 LTS (WSL2 4.4.0-19041-Microsoft)
- QEMU emulator 5.0.50
- GCC 8.4.0 (Target: aarch64-linux-gnu)
- GDB 8.2 (Target: aarch64-linux-gnu)
- GNU Make 4.1