Part A: User Environments and Exception Handling

Exercise 1

修改 kern/pmap.c 中的 mem_init(),分配存放 env 数组的内存,并且完成内存空间映射 代码实现: image

image

Exercise 2

实现下列函数 env_init(): 初始胡 env 数组,将数组中的结构体加到 env_free_list 中,调用 env_init_percpu,用来区分 cpu 执行的权限级别,0-内核,3-用户 env_setup_vm(): 为新环境分配页目录并初始化 region_alloc():分配并映射物理内存 load_icode():解析 elf 格式的二进制文件,把其内容加载到用户地址空间 env_create:调用 region_alloc() 和 load_icode() env_run(): 在用户模式运行 env

实现 env_init(), 将数组中的所有 env 标记为 ENV_FREE, 将 env_id 置为 0,并将它们添加到 env_free_list, 确保在 env_free_list 中的位置和 envs 数组中的位置一样 代码实现: image

实现 env_setup_vm(), 已 kern_pgdir 为模板来初始化 env_pgdir, env_pgdir 的 pp_ref 需要修改 代码实现 image

实现 region_alloc(), 使用 lab2 的 page_alloc() 和 page_insert() 来实现 image image

实现 load_icode(), 根据 elf header 中的信息,将代码段部分加载到对应的虚拟内存,只需要加载 ph->p_type == ELF_PROG_LOAD 的代码段,每个代码段要加载到的虚地址可以通过 ph->p_va 获取,段大小可以通过 ph->p_memsz 获取,从 binary + ph->p_offset 开始,大小为 ph->p_filesz 部分需要复制到虚地址 ph->p_va,其他剩余的部分需要置为 0.

image

实现 env_create(), 使用 env_alloc() 分配一个环境,然后用 load_icode() 加载二进制 elf, 设置 env_type image 实现 env_run(), 如果此时 env 的状态是 running 的话,将其设为 runnable。 将 curenv 设置为当前的新的 env, 将其设为 running 状态,更新 env_runs 计数器,使用 lcr3() 转换到新环境的地址空间,使用 env_pop_tf() 回复其寄存器信息。

image

Exercise 3

阅读 80386 Programmer’s Manual 中的 Chapter 9, Exceptions and Interrupts,了解异常和中断

Exercise 4

编辑 trapentry.S 和 trap.c, 使得每一个异常或中断都有其 handler, trap_init() 应该根据这次 handler 的地址来初始化 IDT,每一个 handler 都要在栈中构建 Trapframe 结构体并通过指向 trapframe 的指针调用 trap(),trap() 处理异常或中断或者把它分发给对应的 handler, trapentry.S 中的 TRAPHANDLER 和 TRAPHANDLER_NOEC 宏以及 inc/trap.h 中的 T_*定义会对你有帮助,你需要为定义在 inc/trap.h 中的每一个 trap 在 trapentry.S 中添加入口,你还要提供_alltraps, 需满足一下几点

  • 需要将 trapframe 需要的值入栈
  • 将 GD_KD 加载到%ds 和%es
  • pushl %esp
  • call trap

首先使用 TRAPHANDLER 和 TRAPHANDLER_NOEC 绑定中断号和中断处理函数的关系 image 然后实现_alltraps: image 最后设置中断 image

Question 1

为什么要为每一个中断单独设置一个 handler? 如果所有的异常或中断都由同一个 handler 来处理,那会不现在的实现少哪些特性? 首先单独设置中断能够根据 err_code 进行分别处理,然后就是可以区分每个中断的权限,区分出用户和内核权限。

Question 2

你需要做什么来使得用户产生的软中断能够正确执行吗?评分的脚本期望发生 trap13,但是用户的软中断为 14,为什么软中断 14 使得 13 号中断发生了,如果用户软中断可以和内核一样 14 软中断就是 14 号中断会发生什么? 因为中断的执行区分不同权限的,如果用户中断和内核中断一样的话,用户就有可能恶意使用中断,造成内核安全问题

Part B: Page Faults, Breakpoints Exceptions, and System Calls

Exercise 5

修改 trap_dispatch(),将缺页中断分发给 page_fault_handler() image

Exercise 6

实现断点异常处理,要求用户代码能够产生断点异常 image

image

Question 3

断点测试会产出断点异常和 general protection fault 中其中一个,这取决于你如何初始化断点的中断向量,为什么是这样?什么样错误的设定会导致产生 general protection fault? 就是 SETGATE 这里设置错误会导致 general protection fault,GD_KT 这个段地址指向了错误的地址,权限设置错误也会导致这个错误

Question 4

你怎样看待这个机制? 这是用户和内核的权限分离,使得内核更加安全

Exercise 7

实现系统调用

首先需要增加系统调用的中断 image image image 在 trap_dispatch() 中处理 syscall 中断 image 在 kern/syscall.c 中实现 syscall 函数 image

Exercise 8

补充相应的用户代码,在 lib/libmain.c 中,修改 libmain() image

Exercise 9

修改 kern/trap.c 使得如果内核产生缺页中断产生 panic 根据 tf_cs 的低位来区分中断是发生在内核还是用户 实现 user_mem_check() 修改 kern/syscall.c 来检查传入的参数 修复 debuginfo_eip 用 user_mem_check 来检查 usd, stabs, and stabstr image

image

image

image

结束

image