全部学习汇总: GreyZhang/g_unix: some basic learning about unix operating system. (github.com)
在计划表中看到了这样一份作业,做一个简单的翻译整理。原来的页面:Homework: xv6 lazy page allocation (mit.edu)
家庭作业:xv6延迟页面分配
在下一堂课开始前,将您的解决方案提交到提交网站。
O/S在使用页表硬件时可以使用的许多巧妙技巧之一是延迟分配堆内存。Xv6应用程序使用sbrk()系统调用向内核请求堆内存。在我们给您的内核中,sbrk()分配物理内存并将其映射到进程的虚拟地址空间。有些程序分配内存,但从不使用内存,例如用于实现大型稀疏阵列。复杂的内核会延迟每一页内存的分配,直到应用程序尝试使用该页——这是由页面错误发出的信号。在本练习中,您将把这个延迟分配功能添加到xv6中。
第一部分:消除sbrk()中的分配
您的第一个任务是从sbrk(n)系统调用实现中删除页面分配,这是sysproc.c中的函数sys_sbrk()。sbrk(n)系统调用将进程的内存大小增加n个字节,然后返回新分配区域的起始位置(即旧大小)。新的sbrk(n)应该只将进程的大小(myproc()->sz)增加n,然后返回旧的大小。它不应该分配内存,所以应该删除对growtproc()的调用(但仍然需要增加进程的大小!)。
试着猜测这次修改的结果是什么:什么会坏?
进行此修改,启动xv6,并在shell中键入echo-hi。你应该看到这样的东西:
“pid 3 sh:trap…”消息来自trap.c中的内核陷阱处理程序;它发现了一个页面错误(陷阱14,或T_PGFLT),xv6内核不知道如何处理。请确保您理解出现此页面错误的原因。“addr 0x4004”表示导致页面错误的虚拟地址是0x4004。
第二部分: 延迟分配
修改trap.c中的代码以响应来自用户空间的页面错误,方法是在错误地址映射新分配的物理内存页面,然后返回到用户空间,让进程继续执行。您应该在生成“pid 3 sh:trap 14”消息的cprintf调用之前添加代码。您的代码不需要涵盖所有角落情况和错误情况;它只需要足够好,就可以让sh运行echo和ls之类的简单命令。
提示:查看cprintf参数,了解如何查找导致页面错误的虚拟地址。
提示:从vm.c中的allocuvm()中找到参考代码,这是sbrk()调用的(通过growtproc())。
提示:使用PGROUNDDOWN(va)将出现错误的虚拟地址向下舍入到页面边界。
提示:中断或返回以避免printf和myproc()->killed=1。
提示:您需要调用mappages()。为了做到这一点,您需要删除vm.c中mappages()声明中的static,并且需要在trap.c中声明mappages:
提示:您可以通过检查trap()中的tf->trapno是否等于T_PGFLT来检查故障是否为页面故障。
如果一切顺利,您的延迟分配代码应该会导致echo-hi工作。您应该在shell中至少得到一个页面错误(从而得到延迟分配),也许还有两个。
顺便说一句,这不是一个完全正确的实现。请参阅下面的挑战,以获取我们意识到的问题列表。
可选挑战:处理负的sbrk()参数。处理错误情况,如sbrk()参数过大。
验证fork()和exit()是否工作,即使某些sbrk()地址没有为它们分配内存。正确处理堆栈下方无效页面上的错误。确保内核对尚未分配的用户地址的使用有效——例如,如果程序将sbrk()分配的地址传递给read()。