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_id、env_status = ENV_RUNNABLE、env_parent_id、env_runs - 设置
env_tf.cp0_status = 0x10001004、env_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_tf至TIMESTACK中 - 设置
curenv -> env_tf.pc = curenv->env_tf.cp0_epc
- 保存当前进程的
- 切换进程:
curenv = e、curenv -> 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指令,后六位
000100变000001,正是期望得到的状态
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.

浙公网安备 33010602011771号