Exercise 1.Modify mem_init()
in
kern/pmap.cto allocate and map the envs
array.This array consists o fexactly
NENV
instances of the Env
structure allocated much like how you allocated the pages
array.Also like the
pages
array, the memory backing envs
should also be mapped user read-only at UENVS
(defined in
inc/memlayout.h) so user processes can read from this array.
You should run your code and make sure check_kern_pgdir()
succeeds.
Answer:
// LAB 3: Your code here.
-
+ envs = (struct Env *)boot_alloc(NENV * sizeof(struct Env));
+ memset(pages, 0, NENV * sizeof(struct Env));
//////////////////////////////////////////////////////////////////////
// Now that we've allocated the initial kernel data structures, we set
// up the list of free physical pages. Once we've done so, all further
@@ -203,7 +204,9 @@ mem_init(void)
// - the new image at UENVS -- kernel R, user R
// - envs itself -- kernel RW, user NONE
// LAB 3: Your code here.
-
+ boot_map_region(kern_pgdir, UENVS,
+ ROUNDUP(NENV*sizeof(struct Env), PGSIZE),
+ PADDR(envs), PTE_U);
Exercise 2.In the file env.c,finish coding the following functions:
- Initialize all of the
Env
structures in theenvs
array and add them to theenv_free_list
.Also callsenv_init_percpu
, which configures the segmentation hardware with separate segments for privilege level 0 (kernel) and privilege level 3 (user). 122 env_free_list = envs;
- Allocate a page directory for a new environmentand initialize the kernel portionof the new environment's address space.
env_init()
123 struct Env *iter = env_free_list;
124 while (i < NENV) {
125 envs[i].env_id = 0;
126 envs[i].env_status = ENV_FREE;
127 i++;
128 iter->env_link = envs + i;
129 }Q: envs在mem_init()里用boot_map_region()已经申请过空间了,就物理空间上应该是紧挨着pages?
env_setup_vm()
198 p->pp_ref++;
199 e->env_pgdir = page2kva(p);
200 memmove(e->env_pgdir,kern_pgdir,PGSIZE);
201 memset(e->env_pgdir,0,PDX(UTOP)*sizeof(pde_t));
原来以为是做映射,其实这边每个enviroment都需要有一个pgdir,让每个用户环境都能映射到4GB的空间。kern_pgdir已经映射到4GB空间,而对于UTOP以上的空间,所有的user enviroment都是和kernel一样的映射,因此可以直接copy过来用。
- Allocates and maps physical memory for an environment
region_alloc()
284 uint32_t ua,la;
285 ua = (uint32_t)ROUNDUP(va+len, PGSIZE);
286 la = (uint32_t)ROUNDDOWN(va, PGSIZE);
287 uint32_t size = 0;
288 struct Page *p = NULL;
289 for(size = 0;size < (ua - la);size += PGSIZE) {
290 if (!(p = page_alloc(ALLOC_ZERO)))
291 panic("page allocation failed!\n");
292 // Jacky: Original I thought should use boot_map_region to map, but actually it's only a static mapping, should use page_insert
293 // boot_map_region(e->env_pgdir, va+size, PGSIZE,
294 // page2pa(p), PTE_W|PTE_U);
295 page_insert(e->env_pgdir, p, va+size, PTE_W|PTE_U);
296 }
- You will need to parse an ELF binary image,much like the boot loader already does,and load its contents into the user address spaceof a new environment. 358 // LAB 3: Jacky 14020.
- Allocate an environment with
env_alloc
and callload_icode
load an ELF binary into it. 395 { - Start a given environment running in user mode. 521 if (curenv) {
load_icode()
359 struct Elf *elf = (struct Elf *)binary;
360 struct Proghdr *ph, *eph;
361 if(elf->e_magic != ELF_MAGIC) {
362 cprintf("%s() It's not an ELF file!\n",__func__);
363 return;
364 }
365 // Mistake 1: Almost miss this one, it's changing the address space from k ernel to e enviroment;
366 lcr3((uint32_t)e->env_pgdir);
367 ph = (struct Proghdr *) ((uint8_t *)elf + elf->e_phoff);
368 eph = ph + elf->e_phnum;
369 for (;ph<eph;ph++) {
370 if (ph->p_type != ELF_PROG_LOAD)
371 continue;
372 region_alloc(e,(void *)ph->p_va,ph->p_memsz);
373 memmove((void *)ph->p_va, (uint8_t *)elf + ph->p_offset, ph->p_fil esz);
374 memset((void *)(ph->p_va + ph->p_filesz), 0, ph->p_memsz - ph->p_f ilesz);
375 }
376 // Mistake 2: set the enviroment's entry point
377 e->env_tf.tf_eip = elf->e_entry;
378
379 // Now map one page for the program's initial stack
380 // at virtual address USTACKTOP - PGSIZE.
381
382 // LAB 3: Jacky 140120
383 region_alloc(e, (void *)(USTACKTOP-PGSIZE), PGSIZE);
env_create()
396 // LAB 3: Jacky140120
397 struct Env* e;
398 int failno = env_alloc(&e, 0);
399 if (failno < 0) {
400 cprintf("%s(0x%x, %d, %d) failed, fail code = %d!\n",__func__, bin ary, size, type);
401 return;
402 }
403 load_icode(*e, binary, size)
404 e->env_type = type;
405 }
env_run()
522 if(curenv->env_status == ENV_RUNNING)
523 curenv->env_status = ENV_RUNNABLE;
524 }
525 curenv = e;
526 curenv->env_status = ENV_RUNNING;
527 curenv->env_runs++;
528 lcr3(PADDR(curenv->env_pgdir));
529
530 env_pop_tf(&curenv->env_tf);
531 panic("env_run not yet implemented");
As you write these functions,you might find the new cprintf verb %e
useful -- it prints a description corresponding to an error code.For example,
r = -E_NO_MEM; panic("env_alloc: %e", r);
will panic with the message "env_alloc: out of memory".