Lab3 实验报告
Exercise 1
- Modify mem_init() in kern/pmap.c to allocate and map the envs array.
// mem_int()
// 第一处
envs = (struct Env *) boot_alloc(NENV * sizeof(struct Env));
memset(pages, 0, NENV * sizeof(struct Env));
// 第二处
boot_map_region(kern_pgdir, UENVS, PTSIZE, PADDR(envs), PTE_U | PTE_P);
这里仿照上一个实验可以比较轻松的写出来,注意,由于内核已用内存多出了 NENV
这一段,所以还需要修改 page_init
函数内的上限,参照 LAB 2
实验报告的代码,修改如下
// page_init()
size_t right_i = PGNUM(PADDR(envs + NENV));
Exercise 2
- In the file env.c, finish coding the following functions.
// env_init()
env_free_list = envs;
struct Env *pre = envs;
for (int i = 1; i != NENV; ++i) {
pre -> env_link = envs + i;
pre = envs + i;
}
这里是初始化 envs
数组,然后插入到空闲链表中,由注释可知,需要确保分配 env
的时候是从 env[0]
开始分配的,也就是使用尾接法建链表,这和之前的 pages
不同
// env_setup_vm()
p->pp_ref++;
e->env_pgdir = page2kva(p);
memcpy(e->env_pgdir, kern_pgdir, PGSIZE);
初始化用户地址空间中内核部分的虚拟内存并设置一级页表,可以将之前的 kern_pgdir
复制过去
// region_alloc()
uintptr_t low = ROUNDDOWN((uintptr_t) va, PGSIZE);
uintptr_t high = ROUNDUP((uintptr_t) va + len, PGSIZE);
if (high > UTOP) {
panic("allocation fails");
}
while (low < high) {
struct PageInfo *pp = page_alloc(ALLOC_ZERO);
if (pp == NULL) {
panic("allocation falis");
}
pp->pp_ref++;
int r = page_insert(e->env_pgdir, pp, (void *) low, PTE_P | PTE_U | PTE_W);
if (r != 0) {
panic("region_alloc: %e", r);
}
low += PGSIZE;
}
为 env
分配物理内存,接着映射到虚拟内存,注意需要对齐以及考虑边界情况
// load_icode()
// 第一处
struct Elf *elf = (struct Elf *) binary;
struct Proghdr *ph = (struct Proghdr *) (binary + elf->e_phoff);
struct Proghdr *eph = ph + elf->e_phnum;
lcr3(PADDR(e->env_pgdir));
while (ph < eph) {
if (ph->p_type == ELF_PROG_LOAD) {
region_alloc(e, (void *) ph->p_va, ph->p_memsz);
memcpy((void *) ph->p_va, binary + ph->p_offset, ph->p_filesz);
}
ph++;
}
lcr3(PADDR(kern_pgdir));
e->env_tf.tf_eip = elf->e_entry;
// 第二处
region_alloc(e, (void *) (USTACKTOP - PGSIZE), PGSIZE);
把 elf
二进制文件读入用户地址空间中,仿照 bootloader
中 main.c
的做法,需要了解 elf
文件的结构,这个之前学习过,需要注意的是,为了读入用户地址空间,需要切换到用户的页表,还有记得设置 eip
指向入口处
// env_create()
struct Env *e;
int r = env_alloc(&e, 0);
if (r < 0) {
panic("env_alloc: %e", r);
}
load_icode(e, binary);
e->env_type = type;
利用之前的函数创建 env
,对于 parent_id
由于分配页面的时候,把页面都清 0
了,所以这里不显式设置也