OS LAB3 进程与异常
思考题
Thinking 3.1 请结合 MOS 中的页目录自映射应用解释代码中 e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_V 的含义。
一个页目录项映射一个含有 1K 个页表项的 4KB 页表,每一个页表映射一个
4MB 大小的虚拟地址空间。由于页目录映射的 4MB 空间就是二级页表结构所在的
4MB 空间,而用户二级页表结构存储在虚拟地址空间中的 UVPT 至 ULIM 处的 4MB
空间 ,因此页目录相当于第 PDX(UVPT)
(取高 10
位)个页表,也就位于第 PDX(UVPT)
个页目录项,其物理地址
PADDR(e->env_pgdir)
存储在这个页目录项中。
Thinking 3.2 elf_load_seg 以函数指针的形式,接受外部自定义的回调函数 map_page。请你找到与之相关的 data 这一参数在此处的来源,并思考它的作用。没有这个参数可不可以?为什么?
int elf_load_seg(Elf32_Phdr *ph, const void *bin, elf_mapper_t map_page, void *data);
在 load_icode
函数中被调用,调用语句为
1 | // kern/env.c |
可见此处 data
来源就是进程控制块
struct Env *e
。回调函数 load_icode_mapper
中将
void *data
重新转换为 struct Env *
类型并作为进程控制块使用。
作用:用于将进程控制块指针传递给回调
load_icode_mapper
,使得回调函数能够将程序的某一页映射到该进程的虚拟地址空间中。
不可以没有,否则无法找到该进程的页表。
Thinking 3.3 结合 elf_load_seg 的参数和实现,考虑该函数需要处理哪些页面加载的情况。
首先是段的初始地址
va
按是否页对齐分为两种情况:其次是段的实际大小
bin_size
与其在内存中占用的大小sgsize
分为两种情况:若
bin_size = sgsize
,则将程序段加载到va
至va + bin_size
即可;若
bin_size < sgsize
,则将程序段加载到va
至va + bin_size
后,还要加载空内容NULL
到va + bin_size
至va + sgsize
。
Thinking 3.4 思考上面这一段话,并根据自己在 Lab2 中的理解,回答: 你认为这里的 env_tf.cp0_epc 存储的是物理地址还是虚拟地址?
虚拟地址。
Thinking 3.5 试找出 0、1、2、3 号异常处理函数的具体实现位置。8 号异常(系统调用) 涉及的 do_syscall()函数将在 Lab4 中实现。
0 号异常处理函数 handle_int
在 kern/genex.S
中:
1 | NESTED(handle_int, TF_SIZE, zero) |
1 号异常处理函数 handle_mod
、2 和 3 号异常处理函数
handle_tlb
也在 kern/genex.S
中,不过用了宏进行了包装:
1 | .macro BUILD_HANDLER exception handler |
Thinking 3.6 阅读 entry.S、genex.S 和 env_asm.S 这几个文件,并尝试说出时钟中断在哪些时候开启,在哪些时候关闭。
时钟中断在进入异常、中断处理时关闭,在退出异常、中断处理后开启。
Thinking 3.7 阅读相关代码,思考操作系统是怎么根据时钟中断切换进程的。
操作系统给每个进程分配一定大小的时间片,其大小依据时钟中断来衡量。每次时钟中断发生时,内核检测是否满足进程切换条件,若满足则切换进程,否则在下个时钟周期继续执行该进程。循环往复,直到进程切换。
难点分析
进程创建流程
时钟中断流程
UVPT
处的用户进程页表,以及位于kseg0
中的e->env_pgdir
页目录,理解它们的关系。
实验体会
本次实验主要涉及进程管理的初始化、进程的创建与切换,以及异常中断处理。
体会创建进程的流程,理解创建进程时对进程页目录的操作。