思考题
Thinking 4.1
- 内核在保存现场时会使用 SAVE_ALL 宏将所有通用寄存器的值保存在 KSTACKTOP 向下一个 Trapframe 的区域。
- 刚刚陷入内核后可以,这时会使用 SAVE_ALL 宏保存现场,随后跳转到各个异常处理函数中,异常处理函数会根据后续调用的 C 函数需要的传参更改 $a0-$a3 的值,因此在这之后应当从保存的 Trapframe 中取参数。
- 我们首先由异常处理函数将 Trapframe 传给 do_syscall 函数,在这个函数中,我们将 Trapframe 中和栈中用户传给 msyscall 的参数取出,作为参数调用对应的系统调用函数。
- 调用过对应系统调用函数后,内核将返回值赋值给了 Trapframe 上的 $v0,用来向用户态模拟 ”函数返回值“,同时将 EPC += 4,使得返回后用户能运行下一条指令。
Thinking 4.2
为了验证变换是否正确,检查出可能存在的内核其他函数误操作修改了进程的 envid 的情况,或是 alloc 时进程赋值的 envid 不正确的情况,作为一种验证手段,类似其他内核函数内有 “不会被运行到的地方” 放一句 panic 的效果。
Thinking 4.3
mkenvid 函数对 (1 << LOG2NENV) 取或,因此返回值一定非零,这是代码上的解释。
应用中,所有 env 相关函数调用时都认为 envid=0 时代表取 curenv (因为 envid2env 是这么处理的),因此不能使其他 envid 是 0。
Thinking 4.4
C,在父进程返回子进程的 pid,在子进程返回 0。
Thinking 4.5
对于所有用户空间,应该映射的部分包括虚拟地址从 0 到 USTACKTOP 的部分,这些用户空间包括了用户自己的各种全局变量和栈中局部变量等内存数据。
不应映射的部分包括 UXSTACKTOP(处理写入异常使用),UENVS 和 UPAGES (只读,所有进程相同,映射内核空间的进程和页表数组),UVPT(页目录,每个进程独立)等 USTACKTOP 上的,一般情况下不应被用户进程所操作的页。
Thinking 4.6
- vpd 用于给用户访问页目录项,vpt 用于给用户访问各个页表。访问一个虚拟地址 va 对应的页目录用 vpd[PDX(va)],页表用 vpt[VPN(va)]。
- 因为所有页表占据了一段连续的内存。
- 页目录占据的恰好是页表内存中能映射到页表这一段内存的对应页表的地址。(UVPT + (PDX(UVPT) << PGSHIFT))
- 不能,页表项对用户态只读。
Thinking 4.7
- 缺页异常处理时响应时钟中断或其他中断,比如在缺页中断时修改有 PTE_COW 标记的页。
- 因为可能出现异常重入,不保证 KSTACKTOP 处一直是当前异常处理的现场。
Thinking 4.8
得不到许多权限,即使处理有误也不至于产生使操作系统崩溃的错误,不会改变内核所需的重要内存空间。
Thinking 4.9
- 保证子进程如果在 exofork 之后被创建的过程中如果出现写入异常能够得到正确的处理
- 会无法处理缺页中断错误,导致写时保护机制不能执行。
难点分析
-
需要充分理解内核态和用户态的区别,用户态只能访问对应的函数和内存空间等,才能进一步理解系统调用。
-
理解系统调用的过程:从 syscall 的函数到 msyscall 到 do_syscall 到 sys 函数的整个过程是如何进行的,参数传递是怎么完成的等。
-
Lab2 的内存映射如果没有理解依然会导致一部分题目出现问题,应当理解虚拟地址通过页表的映射方式,才能理解用户态的 mem_map。
-
IPC的流程应当是先 recv 再 send
-
需要搞清楚写时复制机制和 tlb_mod 异常的联系和 fork 时的处理顺序
-
对 trapframe 的保存和访问需要清楚
实验体会
从 lab4 开始就没有实验讲解,需要认真在课下学习研究,并参加两次课上实验了,压力开始变大,需要更加努力更加专注,对 OS 课程需要投入更大精力,更加用心。