Lab3实验报告
BUAA 2023 Operating System Lab3
(一)思考题
Thinking 3.1
请结合 MOS 中的页目录自映射应用解释代码中 e->env_pgdir[PDX(UVPT)]= PADDR(e->env_pgdir) | PTE_V 的含义
PDX(UVPT)是得出UVPT所处的页目录号,即UVPT处于第PDX(UVPT)个页目录项所映射的4MB空间,因此页目录也被第PDX(UVPT)映射,然后将该页目录号所对应的的页目录项映射为页目录的物理基地址,并且加上权限位。
页目录基地址:
UVPT+UVPT>>10
映射到页目录的页目录项的基地址:
UVPT+UVPT>>10+UVPT>>20
该页表项处于第几个页目录项:
(UVPT>>20) >> 2 = UVPT>>22 = PDX(UVPT)
Thinking 3.2
elf_load_seg 以函数指针的形式,接受外部自定义的回调函数 map_page。请你找到与之相关的 data 这一参数在此处的来源,并思考它的作用。没有这个参数可不可以?为什么?
data是传入的进程控制块指针,在load_icode_mapper和load_icode函数中被调用,在load_icode函数中data被赋予进程控制块的指针e
static int load_icode_mapper(void *data, u_long va, size_t offset, u_int perm,const void *src, size_t len){……}
static void load_icode(struct Env *e, const void *binary, size_t size) {
……
panic_on(elf_load_seg(ph, binary + ph->p_offset, load_icode_mapper, e));
……
}
不能没有这个参数,因为需要根据这个进程去实现它的内存管理,为这个进程分配相应的物理页。
Thinking 3.3
结合 elf_load_seg 的参数和实现,考虑该函数需要处理哪些页面加载的情况。
Thinking 3.4
思考上面这一段话,并根据自己在 Lab2 中的理解,回答:
• 你认为这里的 env_tf.cp0_epc 存储的是物理地址还是虚拟地址?
我认为存储的虚拟地址,因为epc存储的是发生错误时CPU所处的指令地址,那么对于CPU来说,所见的都是虚拟地址,因此env_tf.cp0_epc存储的是虚拟地址。
Thinking 3.5
试找出上述 5 个异常处理函数的具体实现位置。
handle_int在genex.S文件中
handle_mod和handle_tlb,handle_sys藏得比较深,三者都是通过genex.S文件中的宏函数BUILD_HANDLER实现的
Thinking 3.6
阅读 init.c、kclock.S、env_asm.S 和 genex.S 这几个文件,并尝试说出enable_irq 和 timer_irq 中每行汇编代码的作用。
//enable_irq
li t0, (STATUS_CU0 | STATUS_IM4 | STATUS_IEc)
//将t0赋为打开时钟中断的值
mtc0 t0, CP0_STATUS
//将t0的值赋给SR寄存器,使之可以相应时钟中断
jr ra
//返回
//timer_irq
sw zero, (KSEG1 | DEV_RTC_ADDRESS | DEV_RTC_INTERRUPT_ACK)
//写 KSEG1 | DEV_RTC_ADDRESS | DEV_RTC_INTERRUPT_ACK 地址响应时钟中断
li a0, 0
j schedule
//走到调度函数,进行进程调度
Thinking 3.7
阅读相关代码,思考操作系统是怎么根据时钟中断切换进程的。
当内核创建新进程时,将其插入调度链表的头部;在其不再就绪(被阻塞)或退出时,将其从调度链表中移除。当时间片使用完了,我们将当前的进程控制块插入到调度链表的尾部。接下来从调度链表的头部取出一个就绪的进程进行切换。
(二)难点分析
Exercise 3.1
要注意对于链表的插入顺序。
Exercise 3.3
在env结构体中的env_pgdir的地址应该是虚拟地址,我们开辟新的一页时需要将虚拟地址传给env_pgdir。只要是程序处理的地址都应该是虚拟地址。
Exercise 3.4
难点在于要对于其中调用的函数的异常返回值进行处理。
Exercise 3.5
memcpy的两个参数地址都是虚拟地址。
Exercise 3.8
难点在于我们要理解进程运行的过程,首先我们要把当前的页目录切换为待切换进程的页目录,接下来使用env_pop_tf恢复待切换进程的上下文,使之回到该进程中断前的状态,以便于切换后进程的正确运行。
Exercise 3.11
要理解200写入的地址KSEG1 | DEV_RTC_ADDRESS | DEV_RTC_HZ,其中 KSEG1 | DEV_RTC_ADDRESS 是模拟器(GXemul)映射时时钟的位置。偏移量为 DEV_RTC_HZ 表示设置实时钟中断的频率。
Exercise 3.12
难点在于对于scheule函数的编写。首先,我们要确定调度的逻辑,要设置好进入进程调度的条件,在进程调度时,我们还需要注意各种调用的异常返回值,对于这些特殊值要进行异常处理。接下来,在于我们要理解对于不同状态的进程调度的处理如何进行,如果切换时进程不再是就绪状态,就将进程控制块从调度链表中移除,如果仍旧是就绪状态,将该进程控制块插入到调度链表的尾部。
(三)实验体会
Lab3和Lab2相比,实验进行更容易,但是对于代码的理解难度有了一定程度的增加,也就是说做完实验容易,但是深入理解实验有着不小的困难。
理解实验的逻辑应该从功能逻辑开始理解,首先掌握宏观逻辑,接下来对于具体函数的理解就能容易些。
要学会使用Gxemul的debug功能,有时候bug单看代码是难以发现的,我们应该学习debug功能,运用单步调试,设置断点等方法进行bug的de。
在实验中,我们要抛弃局部性的理念,不能只在实验需要完成代码附近寻找答案,我们应该查阅各种文件宏定义,这样才能去真正理解这一个空的目的。