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 的参数和实现,考虑该函数需要处理哪些页面加载的情况。

image-20230416212810408

Thinking 3.4

思考上面这一段话,并根据自己在 Lab2 中的理解,回答:

• 你认为这里的 env_tf.cp0_epc 存储的是物理地址还是虚拟地址?

我认为存储的虚拟地址,因为epc存储的是发生错误时CPU所处的指令地址,那么对于CPU来说,所见的都是虚拟地址,因此env_tf.cp0_epc存储的是虚拟地址。

Thinking 3.5

试找出上述 5 个异常处理函数的具体实现位置。

handle_intgenex.S文件中

handle_modhandle_tlbhandle_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。

  • 在实验中,我们要抛弃局部性的理念,不能只在实验需要完成代码附近寻找答案,我们应该查阅各种文件宏定义,这样才能去真正理解这一个空的目的。

Search by:GoogleBingBaidu