思考题

Thinking 3.1

  • UVPTkuseg保存用户当前进程页表信息的虚拟地址区,e->env_pgdir是进程页目录对应的物理地址。PADDR(e->env_pgdir) | PTE_V将对应页目录物理地址转换为页表项物理地址并赋予页表有效性信息,存入当前进程对应的pgdir中。

Thinking 3.2

  • void *data主要在函数load_icode_mapperload_icodeload_elf中直接使用或间接涉及。这个参数不可以去除,在产生mapper的时候,可能需要多种额外数据辅助映射,因此需要添加。

Thinking 3.3

  • binary无法获得ehdr
  • binary + ph_off无法获得ph或获得的ph->p_typePT_LOAD

Thinking 3.4

  • 虚拟地址

Thinking 3.5

  • 0,1,2,3号异常函数均在/kern/genex.S文件中实现
  • 0号异常使用汇编程序,1,2,3号异常函数均使用宏定义进行描述

Thinking 3.6

  • 时钟达到每个时钟间断间隔,触发时钟中断。
  • 当时钟周期达到预期执行周期时发生时钟中断。具体实现为Count 寄存器的值与Compare 寄存器的值相等且非0时触发中断(Count每周期递增,代表当前已进行周期数)
  • 时钟周期达到预期执行周期进行更换进程之后发生时钟中断。RESET_KCLOCK宏将 Count 寄存器清零并将 Compare寄存器配置期望的计时器周期数, 完成对Timer配置。在设定时钟周期后,时钟中断将被触发。

Thinking 3.7

  • 系统切换运行进程代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    void schedule(int yield) 
    {
    static int count = 0; //静态全局变量,储存当前剩余待执行的周期数
    struct Env *e = curenv; //当前的环境变量,当前进程

    //当发生以下四种情况时更换进程,进行时钟中断
    //当前进程已经被执行过(yield != 0),除非只有一个进程,否则更换进程
    //当前进程执行轮数已达到预期轮数(count == 0),更换线程
    //当前进程不存在(e == NULL)
    //当前进程状态不处于可以运行的状态(e->env_status != ENV_RUNNABLE)
    if (yield != 0 || count == 0 || e == NULL || e->env_status != ENV_RUNNABLE)
    {
    //如果e存在,将该进程移出规划列表
    if (e != NULL)
    {
    TAILQ_REMOVE(&env_sched_list, e, env_sched_link);
    //如果该进程仍处于需要运行的状态,就将其仍放入规划列表尾端
    if (e->env_status == ENV_RUNNABLE)
    {
    TAILQ_INSERT_TAIL(&env_sched_list, e, env_sched_link);
    }
    }
    //规划列表中不存在需要运行的列表
    if (TAILQ_EMPTY(&env_sched_list))
    {
    panic("schedule: no runnable envs");
    }
    e = TAILQ_FIRST(&env_sched_list); //更换进程时,选择位于列表头的进程
    count = e->env_pri; //将待执行周期数设置为预期周期数
    }
    count--; //每个周期进行,待执行周期数减少
    env_run(e); //执行进程e一个周期

    //每个周期执行之后,均会产生一次时钟中断
    }
  • 每一次时钟中断均会触发一轮判断(是否切换当前执行进程)。

难点分析

本次实验中,我遇到的难点主要有以下几点:

  • 页表地址映射:实验中主要使用二级页表的结构,一级页表作为页框映射获得二级页表序号,二级页表作为页号映射获得页内容的真实物理地址。映射过程中的数据提取(该部分数据提取哪几位)及数据对应(这些数据又对应下一级数据地址的哪几位)难度较大,对于当前地址含义的判断也有一定难度。
  • 进程环境的构建:在实验中,设立了多个函数用于构建env并对构建的env进行多项属性设置。如初始化,为环境分配空余页表,数据拷贝等多项操作,整体理解难度较大,实现难度正常。

实验体会

Lab3主要让我们学习有关进程与时钟中断的问题,了解MIPS系统中虚拟地址与物理地址的对应关系、建立并初始化新进程、通过时钟中断实现进程的运行与更换。整体而言,受益于Lab3优秀的指导书和清晰明白的代码注释,其难度应该是小于Lab2的。本次实验涉及到的知识点很多很新,同时也有大量未知的需要自己阅读的宏定义和函数(在不知道使用目的与形参函数的含义情况下上手难度极大),对于小白来说还是比较不友好,也花费了我很长一段时间来完成,但各函数与Lab2中宏定义与自定义函数基本一致,有了Lab2长时间的学习就会很好解决,也会很明白。同时,也十分感谢那些写博客的学长,看了他们的博客后真的是茅塞顿开。实验越往后走,陌生的东西越多,还是要摆正心态,世上无难事,只要肯攀登。