6.S081 lab5 lazy
Eliminate allocation from sbrk()
这次实验的第一关非常简单,就是从sbrk
调用中取消内存分配,为之后的lay allocation
做准备。
|
|
hints 提示我们,修改完代码后,尝试运行echo hi
,会产生类似下面的结果:
|
|
其实并不一定是echo
才会导致 crash,其他的执行任意的命令或者输入无意义字符都会导致 crash。在user/umalloc.c
中,morecore
调用了sbrk
,malloc
调用了morecore
。在user/sh.c
中,shell 运行过程中不断地调用malloc
为 command 申请分配空间,然后运行 command。这个过程中,malloc 并未真正分配空间,运行时访问到对应虚拟地址就会产生 page fault,导致 panic;
Lazy allocation
这一关需要我们实现lazy allocation
,在usertrap()
中处理page fault
,为产生page fault
的虚拟地址分配一个真实的物理页面,并 map 到对应虚拟地址。
r_scause()
用于获取 trap 产生的原因,为 13/15 时为page fault
。
r_stval()
获取stval
寄存器值,它是导致page fault
的虚拟地址值。
uvmunmap()
会 panic,因为进程地址空间有些虚拟地址并未被 map,所要加以修改。
参照uvmalloc()
,完成如下函数,为虚拟地址va
分配一个真实物理页:
|
|
在usertrap()
中加入对于page fault
的处理:
|
|
添加以上代码之后,在uvmunmap()
中添加如下修改,取消panic
:
|
|
完成如上代码后,echo hi
可以正常运行。
Lazytests and Usertests
第三关需要处理第二关的一些遗留细节问题,完善lazy allocation
,使之通过全部测试。
- Handle negative sbrk() arguments.
对于负数参数,需要unmap
对应页面:
|
|
Kill a process if it page-faults on a virtual memory address higher than any allocated with sbrk().
Handle faults on the invalid page below the user stack.
这里需要判断产生page fault
的 va 是否在当前进程拥有的地址范围之外。
|
|
- Handle the parent-to-child memory copy in fork() correctly.
在fork()
中,使用如下代码将内存从父进程复制到子进程:
|
|
进入uvmcopy()
,做出如下修改:
|
|
- Handle the case in which a process passes a valid address from sbrk() to a system call such as read or write, but the memory for that address has not yet been allocated.
当进程进行syscall
时,会陷入 kernel,此时stap
切换为内核页表,RISC-V
硬件无法再为用户地址空间产生page fault
,所以当用户执行read()
和write()
,将用户地址空间的有效虚拟地址传递给内核时,如果该虚拟地址没有 map 到有效物理内存,将会导致程序 panic。kernel 运行时,使用walkaddr
进行虚实地址转换,所以我们需要修改其中的代码,当虚拟地址有效而页表中未 map 时,尝试为其分配物理内存:
|
|
- Handle out-of-memory correctly: if kalloc() fails in the page fault handler, kill the current process.
在关卡 2 中,已经做到了这一点,当lazy_uvmalloc()
调用kalloc()
失败时,返回非 0,杀掉进程:
|
|
做完如上修改,便能通过所有测试。