BUAA_OS_lab3-1 学习笔记

BUAA_OS_lab3-1 学习笔记

Author: Lingo

〇.mmu_map

一.变量

1. struct Env - 进程控制块

struct Env {
     struct Trapframe env_tf;       // Saved registers 
     LIST_ENTRY(Env) env_link;      // Free LIST_ENTRY 
     u_int env_id;                  // Unique environment identifier 
     u_int env_parent_id;           // env_id of this env's parent 
     u_int env_status;              // Status of the environment 
     Pde *env_pgdir;                // Kernel virtual address of page dir 
     u_int env_cr3; 
     LIST_ENTRY(Env) env_sched_link; 
     u_int env_pri;
};
  • env_tf : 保存进程的上下文环境

  • env_link : env_link 的机制类似于lab2中的pp_link, 使用它和env_free_list来构造空闲进程链表

  • env_sched_link : 构造调度队列

  • env_status : 三种取值:

    • ENV_FREE : 表明该进程是不活动的,即该进程控制块处于进程空闲链表中。

    • ENV_NOT_RUNNABLE : 进程处于阻塞状态

    • ENV_RUNNABLE : 进程处于执行状态或就绪状态

  • env_pgdir : 进程页目录的内核虚拟地址

  • env_cr3 : 进程页目录的物理地址

  • env_pri : 进程的优先级。

2.struct Trapframe - 保存上下文环境

struct Trapframe {
	/* Saved main processor registers. */
	unsigned long regs[32];

	/* Saved special registers. */
	unsigned long cp0_status;
	unsigned long hi;
	unsigned long lo;
	unsigned long cp0_badvaddr;
	unsigned long cp0_cause;
	unsigned long cp0_epc;
	unsigned long pc;
};

二.函数

1.void mips_vm_init()

为进程控制块分配物理页面,并映射至UENVS段虚存

2.void env_init()

初始化空闲队列与两个调度队列,并将所有进程控制块逆序LIST_INSERT_HRAD到空闲队列中

3.int envid2env(u_int envid, struct Env **penv, int checkperm)

  • 输入envid,将*penv赋为对应进程控制块。由于此进程控制块已有envid,因此必不在空闲状态。找到返回0
  • 特别地,当checkperm != 0时,若envid对应的进程控制块不是当前进程且不是当前进程的子进程,*penv赋为0,返回负数

4.int env_alloc(struct Env **new, u_int parent_id)

  • 给*new赋为分配的进程控制块,正常分配返回0
  • 过程:
    • 从空闲队列取头元素作为待分配的进程控制块
    • 初始化该进程的地址空间
    • 设置env_idenv_status = ENV_RUNNABLEenv_parent_idenv_runs
    • 设置env_tf.cp0_status = 0x10001004env_tf.regs[29] = USTACKTOP
    • 空闲队列中删除分配的进程控制块

5.void env_free(struct Env *e)

  • 将进程页目录中的所有页面移除(取消映射).

  • 将页目录占用的物理页面回收.

  • 将进程控制块放回到 env_free_list 中.

6.static int env_setup_vm(struct Env *e)

  • 功能:上述函数过程2
  • 效果:
    • 为该进程的页目录分配了对应的物理页
    • UTOP以下的虚存对应的页目录项置为0
    • UTOP及以上(更严谨:UTOP到UVPT之间的PAGES与ENVS区)的虚存对应的页目录项复制boot_pgdir对应页目录项
    • 设置自映射:e->env_pgdir[PDX(UVPT)] = e->env_cr3 | PTE_V;
  • 0x80000000以下的区域才需要构建页表机制,以上的直接映射

7.static int load_icode_mapper(u_long va, u_int32_t sgsize, u_char *bin, u_int32_t bin_size, void *user_data)

  • 功能:拷贝程序段信息

  • 过程:

    • u_char *bin完全拷贝到va所在虚拟“空间”中。要求两者的“页面对齐情况”完全一致
    • 将上述虚拟空间后sgsize - bin_size的虚拟“空间”置为0.要求两者的“页面对齐情况”完全一致
    • 拷贝/置0时,先检查待装入的虚拟空间是否有映射的物理页面,若无则使用page_alloc()page_insert()申请物理页面并构建映射关系

8.int load_elf(u_char *binary, int size, u_long *entry_point, void *user_data, int (*map)(u_long va, u_int32_t sgsize, u_char *bin, u_int32_t bin_size, void *user_data))

  • 功能:

    • 解析elf文件,传参给load_icode_mapper函数
    • 将程序入口传给*entry_point
  • 传参:map(phdr->p_vaddr, phdr->p_memsz, binary + phdr->p_offset, phdr->p_filesz, user_data)

    格外关注memsz为sgsize,filesz为bin_size

9.static void load_icode(struct Env **e, u_char **binary, u_int size)

  • 功能:
    • 为该进程的用户栈分配一页物理页面并建立映射
    • 调用load_elf,加载程序
    • 设置e->env_tf.pc = entry_point
  • 注意:为栈分配页面——USTACKTOP - BY2PG

10.void env_create_priority(u_char *binary, int size, int priority)

  • 过程:
    • 调用env_alloc(),得到已分配好地址空间、只差程序段未加载的进程控制块
    • 调用load_icode,加载程序段
    • 设置优先数
    • 加入队列env_sched_list[0]

11.void env_create(u_char *binary, int size)

创建优先数为1的进程

12.void env_run(struct Env *e)

  • 过程:
    • 若当前有活动进程:
      • 保存当前进程的env_tfTIMESTACK
      • 设置curenv -> env_tf.pc = curenv->env_tf.cp0_epc
    • 切换进程:curenv = ecurenv -> env_runs ++
    • 切换当前地址空间:lcontext(e -> env_pgdir)
    • 恢复上下文环境:env_pop_tf(&(e->env_tf), GET_ENV_ASID(e -> env_id))

三.调用过程

四.理解

1.asid_alloc()函数拆分高一位与低五位

由于整型变量只有32位,若用位图表示需要两个asid_bitmap。于是直接建立asid_bitmap数组,asid的高一位作为数组下标,低五位通过位运算反映在asid_bitmap的对应位中。

2.cp0_status

  • 第28bit 设置为1,表示允许在用户模式下使用 CP0 寄存器。

  • 第12bit 设置为1,表示4号中断(时钟中断)可以被响应。

  • KUc 为1, 意味CPU目前在内核态下运行; KUc 为0, 意味CPU目前在用户态下运行.

  • IEc 为1, 意味着CPU会响应中断; IEc 为0, 意味着CPU不会响应中断.

  • 每个进程在每一次调度都会执行rfe指令,后六位000100000001,正是期望得到的状态

3.所有进程都具有4GB的虚拟空间

图中, 所有进程的蓝色区域都是一样的(共享内核空间). 另外, 紫色区域:

  • UVPT 用于映射进程页表, 每个进程的这部分都不一样.
  • UPAGES 用于映射内存管理中的 pages 数组, 每个进程的这部分都一样.
  • UENVS 用于映射进程管理中的 envs 数组, 每个进程的这部分都一样.

4.为栈分配页面

由于栈的延伸方向自顶向下,因此为栈分配一个页面时应映射到栈顶减去一页的地址处

e.g. USTACKTOP - BY2PG

5.切换进程时步骤curenv -> env_tf.pc = curenv->env_tf.cp0_epc

这是由于: 当时钟中断到来后, CP0 的 EPC 寄存器存储了当前进程的被中断指令的虚地址, env_pop_tf 的恢复现场过程中, 将会通过 jr 指令跳转到 env_tf 中的 pc 值, 从而回滚进程. 因此这里必须要将 pc 设置为被中断指令的虚地址, 即 cp0_epc.

posted @ 2022-04-27 23:37  Lingo30  阅读(288)  评论(0)    收藏  举报