操作系统实验
Lab3
目录
1.思考题解答
2.难点分析
3.思考体会
思考题解答
Thinking 3.1
e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_V;
大小为4MB(0x7fc000000 - 0x80000000)是保存该进程页表项的区域,其中 UVPT = 0x7fc00000。
采用页表自映射的方式:页目录的 4KB 空间在这 4MB 空间之中,该页目录中有一项指向的空间是页目录的头地址,该项即为第PDX(UVPT) 项,将页目录本身的物理地址映射给这一页目录项实现自映射。
Thinking 3.2
在 env.c 文件的 load_icode 函数中,调用了 elf_load_seg 函数,形参 map_page 和 data 对应的实参分别是 load_icode_mapper函数和 e(进程控制块)。
不可以没有该参数,因为该参数的作用是作为回调函数的参数传入,函数会对其进行分配物理页面建立映射的操作。
Thinking 3.3
va 和 va + bin_size 的关系可能有:
va + bin_size 和 va + sig_size 的关系可能有:
Thinking 3.4
env_tf.cp0_epc 存储的是程序入口,而各个进程的程序入口相同,所以这是虚拟地址。
Thinking 3.5
handle_int (kern/genex.S)
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
j schedule
END(handle_int)
handle_mod、handle_tlb、handle_sys通过genex.S文件中的宏函数BUILD_HANDLER实现:
BUILD_HANDLER tlb do_tlb_refill
#if !defined(LAB) || LAB >= 4
BUILD_HANDLER mod do_tlb_mod
BUILD_HANDLER sys do_syscall
#endif
Thinking 3.6
LEAF(enable_irq)
li t0, (STATUS_CU0 | STATUS_IM4 | STATUS_IEc)
//赋值 t0 = 0x10001001
mtc0 t0, CP0_STATUS
//#将 CP0 的 SR 寄存器中第1、12、28位 置为1,作用是开启全局中断使能和始终中断使能,并允许用户态使用CP0
jr ra
//返回
END(enable_irq)
timer_irq:
sw zero, (KSEG1 | DEV_RTC_ADDRESS | DEV_RTC_INTERRUPT_ACK)
//写入0,响应时钟中断
li a0, 0
//向 schedule 中传入 0
j schedule
//跳转到 schedule 函数
Thinking 3.7
- 当线程被创建并置为 RUNNABLE 时,将其插入到 env_sched_list 的头部。
- 每次运行前检查正需要运行的进程时间片是否用完。
- 用完若状态仍为 RUNNABLE 则将其插入到 env_sched_list 的尾部,否则直接移出可执行线程队列。继续运行队列头部的线程。
- 若未用完则继续执行。
难点分析
- 页表自映射的机制较为抽象,在 lab2 的扩展部分,第一次接触到了页表自映射的概念,由于对二级页表的处理较为生疏,理解该映射机制存在一定难度;该机制实际上是将页目录、页表、其他虚拟页一视同仁,都采用相同的映射机制进行访问,唯一需要注意的是为了实现该机制,各个页表占用的总 4MB 空间要求连续存储。
- 对中断处理函数的理解有一定难度,主要操作位,结合中断允许控制位和中断标志位对是否中断及中断类型进行判断,通过进程调度的方式来处理中断。
- 调度函数的编写容易出错,由于进程是可以创建进程的,故一个进程需要执行时,需先将其从可执行线程链表中立即取出,若执行后再取出,可能会导致其他进程获取到相同的子进程。
思考体会
本次作业要求填补的函数难度不高,但透彻理解线程的创建过程和中断的处理机制还是有一定挑战的;经历 lab2 对内存管理的熟悉后,完成 lab3 实验的压力降低了很多;后续需要加强对进程在内存中执行的细节的了解和理解。