思考题
-
Thinking 3.1 请结合 MOS 中的页目录自映射应用解释代码中
e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_V
的含义。UVPT 是该用户进程 e 的页表虚拟基地址,采用自映射方法,(进程 e 的)页表的第
PDX(UVPT)
个页目录项映射到进程 e 自身页目录的物理地址,并且对应的页目录项应当是有效的 PTE_V。 -
Thinking 3.2 elf_load_seg 以函数指针的形式,接受外部自定义的回调函数 map_page。请你找到与之相关的 data 这一参数在此处的来源,并思考它的作用。没有这个参数可不可以?为什么?
1 2 3
int elf_load_seg(Elf32_Phdr *ph, const void *bin, elf_mapper_t map_page, void *data); struct Env* env = (struct Env*)data; //load_icode_mapper中
map_page (调用 load_icode_mapper)中,data 是指定的一个进程空间, load_icode_mapper 为 data 对应的进程空间分配一个物理页面,并在页表建立映射。
必须要有data,否则无法为指定进程分配物理页面 -
Thinking 3.3 结合 elf_load_seg 的参数和实现,考虑该函数需要处理哪些页面加载的情况。
1
u_long offset = va - ROUNDDOWN(va, BY2PG);
offset 为 va 的距离对齐页面的偏移量。
- 若页面不对齐,则需要先将不对齐的页加载到指定进程。
- 将二进制文件的对齐部分加载到内存。
- 当 段内存大小 大于 二进制文件的大小 时,为多于的部分(如.bss)填充0。
-
Thinking 3.4 思考上面这一段话,并根据自己在 Lab2 中的理解,回答:
• 你认为这里的 env_tf.cp0_epc 存储的是物理地址还是虚拟地址?是虚拟地址,CPU在会使用MMU将虚拟地址转化为相应的物理地址。此外PC计数器顺序执行指令,物理地址是不连续的,虚拟地址是连续的。
-
Thinking 3.5 试找出 0、1、2、3 号异常处理函数的具体实现位置。8 号异常(系统调用)涉及的 do_syscall() 函数将在 Lab4 中实现。
kern/genex.S 0号异常处理函数 handle_int 表示中断,由时钟中断、控制台中断等中断造成 1 2 3号找不到
-
Thinking 3.6 阅读 init.c、kclock.S、env_asm.S 和 genex.S 这几个文件,并尝试说出enable_irq 和 timer_irq 中每行汇编代码的作用。
// enable_irq LEAF(enable_irq) //定义叶函数 li t0, (STATUS_CU0 | STATUS_IM4 | STATUS_IEc) // IM4 表示 4 号中断可否被响应 // IEc IE 代表CPU 中断是否开启,c代表SR寄存器的二重栈底部 // CU0 SR寄存器的第 28 位,代表可以在用户态使用一些特权指令 mtc0 t0, CP0_STATUS //CP0寄存器赋值 jr ra //返回调用位置 END(enable_irq) //定义结束 NESTED(handle_int, TF_SIZE, zero) mfc0 t0, CP0_CAUSE mfc0 t2, CP0_STATUS and t0, t2 andi t1, t0, STATUS_IM4 bnez t1, timer_irq // TODO: handle other irqs timer_irq: sw zero, (KSEG1 | DEV_RTC_ADDRESS | DEV_RTC_INTERRUPT_ACK) //写此地址响应时钟中断 li a0, 0 //调度schedule的yield参数为0,也就是正常调度,不强制切换当前进程 j schedule //度过了一个时间片,重新进行进程调度 END(handle_int)
-
阅读相关代码,思考操作系统是怎么根据时钟中断切换进程的。
env_sched_list 是需要调度的进程队列(全部是ENV_RUNNABLE),每个进程都有自己的优先级 env_pri(执行的时间片长度)。
我们设定的时钟频率为 200HZ ,每个时间片为 5ms。若启用时钟中断,则每 5ms 产生一次时钟中断。每次时钟中断时,调用 handle_int 异常处理函数,其中调用 schedule(0) 调度当前进程运行1次。若当前进程的 count(剩余时间片数量) 为 0 或当前进程不为 ENV_RUNNABLE, 则从 env_sched_list 选取一个新进程调度运行。
难点分析
本次实验的难点在于 env_setup_vm
初始化进程虚拟地址空间,要结合 mmu.h 理解用户进程页表分布于 UVPT~ULIM,所有进程共享 UTOP~UVPT 内核只读空间 pages envs(现在env_init内赋模板初值,再在env_setup_vm多次使用)。
我在 exercise 3.4 env_alloc
出错,尽管通过课下测试,但是 exam 失败
1
2
3
4
//正确写法
panic_on(asid_alloc(&(e->env_asid)));
//原错误如下,不清楚 int r 有何作用
e->env_asid = asid_alloc(&r);
env_create 进程在创建时,需要为其加载二进制任务程序,设定优先级,并放入带调度进程队列。
进程加载二进制内存程序 load_icode 步骤:
- 在 load_icode 中,分别对程序的每个段进行 elf_load_seg,再设置该进程的入口 env_tf.cp0_epc 为程序的入口。
- 在 elf_load_seg 中,将段使用 load_icode_mapper 加载到进程中,考虑段是否对齐、段内存大小多于程序部分填充0。
- load_icode_mapper 调用 memcpy 加载程序,调用 page_insert 分配页面映射。
env_run 进程运行时需要保存上下文环境,再切换 curenv 运行进程,并切换 cur_pgdir 页表,最后恢复上下文环境。
后续在链接器部分添加了异常处理程序段和 TLB 缺失处理程序段。
并开启 GXemul-RTC 时钟中断 200HZ。
实验体会
本次实验完成了进程的初始化,并模拟了中断和异常处理,其中着重实现了时钟中断引起的时间片进程切换调度。
由于课下测试强度较弱,未能发现 bug,导致课上测试失败。
在之后的学习中,课下部分需要精心考虑,保证正确性。
指导书&测评网站纠错
1
2
3
# 指导书p88和测评网站 结果显示不对(测评结果是对的)
# 个人猜测指导书和测评网站显示的是旧版本,但是实际测试的是新版本
make test lab=3_2 && make run