简介
文档链接:Lab2: 内存管理 - IPADS OS Course Lab Manual
本实验主要目的在于让同学们熟悉内核启动过程中对内存的初始化和内核启动后对物理内存和页表的管理,包括三个部分。
- 物理内存管理: 理解并完成伙伴系统以及SLAB系统
- 虚拟页表管理: 深入理解页表分配机制以及页表项权限机制,并完成页表分配函数。
- 缺页异常处理: 理解aarch64架构下的异常处理机制,并按照页表项的配置完成按需分配以及写时拷贝的缺页管理设置。
!本次实验由于时间紧任务重,只完成代码部分
代码导读(list_head, 页表原理并不在此列,自行了解)
从main
函数讲起,在初始化完cpu信息之后,就开始初始化页表(mm_init
)

mm_init
函数
|
|
init_buddy_for_one_physmem_map
函数
|
|
- 页表相关结构体
|
|
- 初始化伙伴系统
|
|
- 获取伙伴块以及地址转换函数
|
|
练习题1
完成 kernel/mm/buddy.c
中的 split_chunk
、merge_chunk
、buddy_get_pages
、 和 buddy_free_pages
函数中的 LAB 2 TODO 1
部分,其中 buddy_get_pages
用于分配指定阶大小的连续物理页,buddy_free_pages
用于释放已分配的连续物理页。
根据
init_buddy
中对buddy_free_pages
的使用,我们知道这个函数主要是将page->allocated
设置回0,再结合伙伴系统的知识,我们知道在释放完内存之后还要尽可能地合并伙伴,即调用merge_chunk
函数
|
|
参照
merge_chunk
和buddy_free_pages
,实现split_chunk
和buddy_get_pages
|
|
练习题2
完成 kernel/mm/slab.c
中的 choose_new_current_slab
、alloc_in_slab_impl
和 free_in_slab
函数中的 LAB 2 TODO 2
部分,其中 alloc_in_slab_impl
用于在 slab 分配器中分配指定阶大小的内存,而 free_in_slab
则用于释放上述已分配的内存。
前置代码:
在初始化完伙伴分配器之后,开始初始化slab分配器
|
|
slab_pool
的定义

|
|
题解:
choose_new_current_slab
函数,从slab_list
中将下一个slab
放到current_slab
上
|
|
alloc_in_slab_impl
函数,在slab中获取一个空闲空间
|
|
free_in_slab
函数,释放已分配的slot
|
|
练习题 3
完成
kernel/mm/kmalloc.c
中的_kmalloc
函数中的LAB 2 TODO 3
部分,在适当位置调用对应的函数,实现kmalloc
功能
|
|
练习题4
完成 kernel/arch/aarch64/mm/page_table.c
中的 query_in_pgtbl
、map_range_in_pgtbl_common
、unmap_range_in_pgtbl
和 mprotect_in_pgtbl
函数中的 LAB 2 TODO 4
部分,分别实现页表查询、映射、取消映射和修改页表权限的操作,以 4KB 页为粒度。
前置代码:
|
|
|
|
题解:
query_in_pgtbl
函数, 将虚拟地址翻译成物理地址,并返回存储该物理地址的页表项
|
|
map_range_in_pgtbl_common
函数,建立页表映射
|
|
unmap_range_in_pgtbl
函数,取消内存映射,是map_range_in_pgtbl_common
的相反操作,我们只需要复制之后进行修改就好了
|
|
mprotect_in_pgtbl
函数,跟上面一样,只需要改一两句代码,没什么好讲的
|
|
挑战题7
使用前面实现的 page_table.c
中的函数,在内核启动后的 main
函数中重新配置内核页表,进行细粒度的映射。
这题的意思应该是将所有的内核地址都映射到内核页表内,这需要根据lab1中的介绍来获取内核地址范围。但由于笔者实力不够,还不太明白这题的意思,并且没有多少时间来钻研这个,所以并没有进行实现
练习题 8, 9, 10
- 完成
kernel/arch/aarch64/irq/pgfault.c
中的do_page_fault
函数中的LAB 2 TODO 5
部分,将缺页异常转发给handle_trans_fault
函数。 - 完成
kernel/mm/vmspace.c
中的find_vmr_for_va
函数中的LAB 2 TODO 6
部分,找到一个虚拟地址找在其虚拟地址空间中的 VMR。 - 完成
kernel/mm/pgfault_handler.c
中的handle_trans_fault
函数中的LAB 2 TODO 7
部分(函数内共有 3 处填空,不要遗漏),实现PMO_SHM
和PMO_ANONYM
的按需物理页分配。你可以阅读代码注释,调用你之前见到过的相关函数来实现功能。
以上三题基本等于一题,所以放一起看
do_page_fault
函数
|
|
find_vmr_for_va
函数,在vmspace中查找相应vmr
前置代码:
- 对应的结构体定义
|
|
- 红黑树的查询函数
|
|
题解:
我们其实不需要了解太多相关信息,只需要知道怎么查找就好了,这里使用的是红黑树来查找,根据内核实现的红黑树查找函数,以及已经实现了的比较函数
cmp_vmr_and_va
和rb_entry
,即可完成题目
|
|
handle_trans_fault
函数
|
|
挑战题 11
我们在map_range_in_pgtbl_common
、unmap_range_in_pgtbl
函数中预留了没有被使用过的参数rss
用来来统计map映射中实际的物理内存使用量1, 你需要修改相关的代码来通过Compute physical memory
测试,不实现该挑战题并不影响其他部分功能的实现及测试。如果你想检测是否通过此部分测试,需要修改kernel/config.cmake
中CHCORE_KERNEL_PM_USAGE_TEST
为ON
题解:在上面的实现中笔者已经实现了大部分的内存记录,此时只需要稍作修改
get_next_ptp
函数
|
|
try_release_ptp
函数
|
|
unmap_range_in_pgtbl
函数
|
|