lab3实验报告一、思考题Thinking 3.1请结合MOS中的页目录自映射应用解释代码中e-env_pgdir[PDX(UVPT)] PADDR(e-env_pgdir) | PTE_V 的含义。e-env_pgdir[PDX(UVPT)] PADDR(e-env_pgdir) | PTE_VUVPT意为User Virtual Page Table是用户新建进程页表虚拟地址的起始地址PDX(UVPT)获得的是该虚拟地址的页目录号该页目录项就是指向页目录本身的页目录项通过PADDR(e-env_pgdir)获得其物理地址而其权限通过PTE_V设置为只读页表基地址UVPT页目录基地址UVPTUVPT10映射到该页目录项的页表项的基地址UVPTUVPT10UVPT20该页表项是第几个页目录项UVPT202UVPT22PDX(UVPT)Thinking 3.2elf_load_seg 以函数指针的形式接受外部自定义的回调函数 map_page。 请你找到与之相关的data这一参数在此处的来源并思考它的作用。没有这个参数可不可以为什么?data是传入的进程控制块指针在load_icode中将进程控制块e通过参数data传入elf_load_seg在elf_load_seg中将data传入回调函数map_page中回调函数mape_page即为load_icode_mapper在该函数中将data解析为进程控制块以获得进程页目录和asid作用在增加虚拟地址到物理地址的映射时提供env_pgdir和env_asid没有这个参数不可以因为如果没有data参数那么在load_icode_mapper中就无法获得进程的页目录和asid同时该参数的存在也提高了程序的可拓展性使得其他结构体也可以使用该函数Thinking 3.3结合 elf_load_seg 的参数和实现考虑该函数需要处理哪些页面加载的情况。段首地址不对齐将不对齐的地方从offset开始先映射到内存中intr;size_ti;u_long offsetva-ROUNDDOWN(va,PAGE_SIZE);if(offset!0){if((rmap_page(data,va,offset,perm,bin,MIN(bin_size,PAGE_SIZE-offset)))!0){returnr;}}循环将与完整页大小相等数据完整的部分映射到内存中/* Step 1: load all content of bin into memory. */for(ioffset?MIN(bin_size,PAGE_SIZE-offset):0;ibin_size;iPAGE_SIZE){if((rmap_page(data,vai,0,perm,bini,MIN(bin_size-i,PAGE_SIZE)))!0){returnr;}}bin_sizesgsize循环创建新页但不向其中写入内容/* Step 2: alloc pages to reach sgsize when bin_size sgsize. */while(isgsize){if((rmap_page(data,vai,0,perm,NULL,MIN(sgsize-i,PAGE_SIZE)))!0){returnr;}iPAGE_SIZE;}Thinking 3.4思考上面这一段话并根据自己在Lab2中的理解回答你认为这里的env_tf.cp0_epc存储的是物理地址还是虚拟地址?虚拟地址epc存储的是发生错误时的CPU所指的指令地址对于CPU来说指令和数据都存储在内存中读取指令和内存所需要的都是虚拟地址。因此env_tf.cp0_epc所存储的是虚拟地址Thinking 3.5试找出0、1、2、3号异常处理函数的具体实现位置。8号异常系统调用 涉及的do_syscall()函数将在Lab4中实现。0号异常位于kern/genex.S中NESTED(handle_int, TF_SIZE, zero) mfc0 t0, CP0_CAUSE mfc0 t2, CP0_STATUS and t0, t2 andi t1, t0, STATUS_IM7 bnez t1, timer_irq timer_irq: li a0, 0 j schedule END(handle_int)1、2、3号异常位于kern/genex.S中使用BUILD_HANDLER宏定义实现.macro BUILD_HANDLER exception handler NESTED(handle_\exception, TF_SIZE 8, zero) move a0, sp addiu sp, sp, -8 jal \handler addiu sp, sp, 8 j ret_from_exception END(handle_\exception) .endm BUILD_HANDLER tlb do_tlb_refill #if !defined(LAB) || LAB 4 BUILD_HANDLER mod do_tlb_mod BUILD_HANDLER sys do_syscall #endif BUILD_HANDLER reserved do_reservedThinking 3.6阅读entry.S、genex.S和env_asm.S这几个文件并尝试说出时钟中断在哪些时候开启在哪些时候关闭。开启在异常处理handle_int中通过调用timer_irq跳转到schedule函数该函数调用env_run最终调用env_pop_tf来设置新进程的上下文环境且最后跳转到ret_from_exception此时eret将EXL设置为0且Status中UM、IE均为1表示用户模式且开启了中断FEXPORT(ret_from_exception) RESTORE_ALL eret关闭entry.S中在异常分发时关闭时钟中断mfc0 t0, CP0_STATUS and t0, t0, ~(STATUS_UM | STATUS_EXL | STATUS_IE) mtc0 t0, CP0_STATUS # 清除Status寄存器中的UM、EXL、IE位以保持处理器处于内核态UM0、关闭中断且允许嵌套异常Thinking 3.7阅读相关代码思考操作系统是怎么根据时钟中断切换进程的。每次触发时钟中断操作系统都会跳转到异常处理程序handle_int该函数通过调用timer_irq跳转到schedule函数在该函数中当count减为0时分给该进程的时间片用完或者未调度过任何进程或者当前进程不再就绪或者yield参数指定必须发生切换首先判断当前进程是否仍再就绪如果是就将其从链表头部移除加入就绪链表的尾端取出链表头部的一个进程将优先级设置为时间片数运行该取出的线程二、难点分析进程进程控制块(lab3中所使用的部分)structEnv{structTrapframeenv_tf;// saved context (registers) before switching// 在发生进程调度,或当陷入内核时,会将当时的进程上下文环境保存在 env_tf 变量中.LIST_ENTRY(Env)env_link;// intrusive entry in env_free_list// 类似于pp_link,用来创建空闲链表env_free_listu_int env_id;// unique environment identifier// 进程独一无二的标识符u_int env_asid;// ASID of this envu_int env_parent_id;// env_id of this envs parent// 记录父进程的进程idu_int env_status;// status of this env// 记录进程的状态,空闲状态,阻塞状态,执行状态或者就绪状态Pde*env_pgdir;// page directory// 保存了该进程页目录的内核虚拟地址TAILQ_ENTRY(Env)env_sched_link;// intrusive entry in env_sched_list// 用于构造调度队列env_sched_listu_int env_pri;// schedule priority// 进程的优先级}TAILQ开头的宏定义TAILQ_INIT初始化一个双端队列TAILQ_INSERT_HEAD插入到双端队列的头部TAILQ_INSERT_TAIL插入到双端队列的尾部TAILQ_INSERT_AFTER插入到双端队列某个元素之后TAILQ_INSERT_BEFORE插入到双端队列某个元素之前TAILQ_REMOVE从双端队列中删除某个元素TAILQ_FOREACH遍历双端队列模板页表创建模板页表时首先分配一页物理内存作为模板页表的页目录并将一些物理页面映射到该页表对应的虚拟地址空间中的特定虚拟页面上。在此过程中还会分配物理页面用于二级页表。当创建新进程时我们只需将模板页表的页目录项注 意仅复制相关的目录项添加到新进程的页目录中。这使得 所有用户进程能够共享相同的二级页表。页目录自映射e-env_pgdir[PDX(UVPT)] PADDR(e-env_pgdir) | PTE_V;UVPTUser Virtual Page Table是用户程序读取自己页表的入口意为将进程页目录中虚拟地址 UVPT 对应的页目录项置为存放该进程的页目录的物理页面的物理页号并将权限置为只读创建进程分配一个新的Env结构体设置进程控制块加载二进制镜像将程序载入到目标进程的地址空间宏拼接#defineENV_CREATE(x)\({\externu_char binary_##x##_start[];\externu_int binary_##x##_size;\env_create(binary_##x##_start,(u_int)binary_##x##_size,1);\})如果ENV_CREATE(program)进行宏拼接惠普将产生数组名binary_program_start进程运行与切换进程切换的条件count减为0时当前进程的时间片用完当前进程为null操作系统内核刚完成初始化暂无进程正在执行参数yield为1时当前进程需要让出当前进程被阻塞时不能继续执行让给其他进程切换的步骤如果当前进程需要切换进入if分支如果当前进程不为null且认为就绪态将其从就绪队列的头部删除加入到就绪队列的尾部取出当前就绪队列的头部元素判断该元素是否为null将时间片设置为该元素的优先级时间片自减运行该取出的进程中断与异常异常重入若UM位已经为0则代表待处理异常是在内核态被触发的对于异常重入的情况此时sp寄存器储存的栈指针已经指向内核异常栈使其继续增长这样就可以再异常中处理新的异常而不破坏原本的异常处理过程在使sp寄存器继续增长后执行正常的异常处理流程即可完成对异常重入的处理新增异常处理注册handle函数在genex.S中添加xx、do_xx添加如下代码BUILD_HANDLER xx do_xx在traps.c中更新异常向量组例如该异常为y号异常[y]handle_xx在kern/traps.c中编写异常处理函数voidhandle_xx(void)三、实验体会课下实验较lab2来说整个过程较为完整逻辑结构较为清晰在有了lab使用链表宏的经验上使得lab3对于链表宏的使用也较为熟练同时计组P7的知识也为lab3打下了良好的基础总得来说lab3的课下较lab2来说较为简单课上实验来说exam较为繁琐但跟着题目的提示也能很快、很有逻辑地找到解决的方法同时在受迫环境以及vim中下对于单词的拼写等最基本的步骤也需要谨慎extra其实较为清晰但对于立即数的符号拓展一直未能找到合理的方法实现~~不过这应该是对c语言的不熟练~~因此对c语言的熟练程度也需要不断提高