码迷,mamicode.com
首页 > 其他好文 > 详细

Mit os Lab 3. User Environmen

时间:2016-07-10 16:35:06      阅读:259      评论:0      收藏:0      [点我收藏+]

标签:

Part A: User Environments and Exception Handling

As you can see in kern/env.c, the kernel maintains three main global variables pertaining to environments:

struct Env *envs = NULL;		// All environments
struct Env *curenv = NULL;		// The current env
static struct Env *env_free_list;	// Free environment list

Once JOS gets up and running, the envs pointer points to an array of Env structures representing all the environments in the system. In our design, the JOS kernel will support a maximum of NENV simultaneously active environments, although there will typically be far fewer running environments at any given time. (NENV is a constant #define‘d in inc/env.h.) Once it is allocated, the envs array will contain a single instance of the Env data structure for each of theNENV possible environments.

ENV结构体定义:

struct Env {
	struct Trapframe env_tf;	// Saved registers
	struct Env *env_link;		// Next free Env
	envid_t env_id;			// Unique environment identifier
	envid_t env_parent_id;		// env_id of this env‘s parent
	enum EnvType env_type;		// Indicates special system environments
	unsigned env_status;		// Status of the environment
	uint32_t env_runs;		// Number of times environment has run

	// Address space
	pde_t *env_pgdir;		// Kernel virtual address of page dir
};

Here‘s what the Env fields are for:

env_tf:
This structure, defined in inc/trap.h, holds the saved register values for the environment while that environment is not running: i.e., when the kernel or a different environment is running. The kernel saves these when switching from user to kernel mode, so that the environment can later be resumed where it left off.
env_link:
This is a link to the next Env on the env_free_listenv_free_list points to the first free environment on the list.
env_id:
The kernel stores here a value that uniquely identifiers the environment currently using this Env structure (i.e., using this particular slot in the envs array). After a user environment terminates, the kernel may re-allocate the same Env structure to a different environment - but the new environment will have a different env_id from the old one even though the new environment is re-using the same slot in the envs array.
env_parent_id:
The kernel stores here the env_id of the environment that created this environment. In this way the environments can form a “family tree,” which will be useful for making security decisions about which environments are allowed to do what to whom.
env_type:
This is used to distinguish special environments. For most environments, it will be ENV_TYPE_USER. We‘ll introduce a few more types for special system service environments in later labs.
env_status:
This variable holds one of the following values:
ENV_FREE:
Indicates that the Env structure is inactive, and therefore on the env_free_list.
ENV_RUNNABLE:
Indicates that the Env structure represents an environment that is waiting to run on the processor.
ENV_RUNNING:
Indicates that the Env structure represents the currently running environment.
ENV_NOT_RUNNABLE:
Indicates that the Env structure represents a currently active environment, but it is not currently ready to run: for example, because it is waiting for an interprocess communication (IPC) from another environment.
ENV_DYING:
Indicates that the Env structure represents a zombie environment. A zombie environment will be freed the next time it traps to the kernel. We will not use this flag until Lab 4.
env_pgdir:
This variable holds the kernel virtual address of this environment‘s page directory.

 

1 Exercise 1. Modify mem_init() in kern/pmap.c to allocate and map the envs array. This array consists of exactly 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.

1) 为env申请内存

1     // Make ‘envs‘ point to an array of size ‘NENV‘ of ‘struct Env‘.
2     // LAB 3: Your code here.
3     envs = (struct Env*)boot_alloc(ROUNDUP(NENV * sizeof(struct Env), PGSIZE));
4     memset(envs, 0, sizeof(struct Env) * NENV);
5     cprintf("alloc envs buffer: start=%08x, len=%08x\n", envs, NENV * sizeof(struct Env));

2) 将逻辑地址UENVS映射到envs的物理地址

 1     //////////////////////////////////////////////////////////////////////
 2     // Map the ‘envs‘ array read-only by the user at linear address UENVS
 3     // (ie. perm = PTE_U | PTE_P).
 4     // Permissions:
 5     //    - the new image at UENVS  -- kernel R, user R
 6     //    - envs itself -- kernel RW, user NONE
 7     // LAB 3: Your code here.
 8     boot_map_region(kern_pgdir,
 9                 UENVS, 
10                 ROUNDUP((sizeof(struct Env) * NENV) , PGSIZE),
11                 PADDR(envs),
12                 (PTE_U | PTE_P));

 

Exercise 2. In the file env.c, finish coding the following functions:

env_init()
Initialize all of the Env structures in the envs array and add them to the env_free_list. Also calls env_init_percpu, which configures the segmentation hardware with separate segments for privilege level 0 (kernel) and privilege level 3 (user).
env_setup_vm()
Allocate a page directory for a new environment and initialize the kernel portion of the new environments address space.
region_alloc()
Allocates and maps physical memory for an environment
load_icode()
You will need to parse an ELF binary image, much like the boot loader already does, and load its contents into the user address space of a new environment.
env_create()
Allocate an environment with env_alloc and call load_icode load an ELF binary into it.
env_run()
Start a given environment running in user mode.
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".

1) env_init 

初始化env,最终env_free_list指向env[0], 然后通过env_link链接剩余env,链表。

 1 // Mark all environments in ‘envs‘ as free, set their env_ids to 0,
 2 // and insert them into the env_free_list.
 3 // Make sure the environments are in the free list in the same order
 4 // they are in the envs array (i.e., so that the first call to
 5 // env_alloc() returns envs[0]).
 6 //
 7 void
 8 env_init(void)
 9 {
10     // Set up envs array
11     // LAB 3: Your code here.
12 
13     int i = 0;
14     env_free_list = NULL;
15     cprintf("NENV -1 : %u\n", NENV -1);
16 
17     for (i = NENV -1; i >= 0; i--)
18     {
19         envs[i].env_id = 0;
20         envs[i].env_parent_id = 0;
21         envs[i].env_type = ENV_TYPE_USER;
22         envs[i].env_status = ENV_FREE;
23         envs[i].env_runs = 0;
24         envs[i].env_pgdir = NULL;
25         envs[i].env_link = env_free_list;
26         env_free_list = &envs[i];
27     }
28 
29     cprintf("env_free_list : 0x%08x, & envs[i]: 0x%08x\n", env_free_list, &envs[i]);
30 
31     // Per-CPU part of the initialization
32     env_init_percpu();
33 }

2) env_setup_vm

env_setup_vm为进程创建进程地址空间,先通过page_alloc分配一页地址作为页目录pagedir,然后pagedir复制内核页目录表,

然后将页表项env_pgdir[PDX(UVPT)]映射到pagedir。

 1 static int
 2 env_setup_vm(struct Env *e)
 3 {
 4     int i;
 5     struct PageInfo *p = NULL;
 6 
 7     // Allocate a page for the page directory
 8     if (!(p = page_alloc(ALLOC_ZERO)))
 9         return -E_NO_MEM;
10 
11     // Now, set e->env_pgdir and initialize the page directory.
12     //
13     // Hint:
14     //    - The VA space of all envs is identical above UTOP
15     //    (except at UVPT, which we‘ve set below).
16     //    See inc/memlayout.h for permissions and layout.
17     //    Can you use kern_pgdir as a template?  Hint: Yes.
18     //    (Make sure you got the permissions right in Lab 2.)
19     //    - The initial VA below UTOP is empty.
20     //    - You do not need to make any more calls to page_alloc.
21     //    - Note: In general, pp_ref is not maintained for
22     //    physical pages mapped only above UTOP, but env_pgdir
23     //    is an exception -- you need to increment env_pgdir‘s
24     //    pp_ref for env_free to work correctly.
25     //    - The functions in kern/pmap.h are handy.
26 
27     // LAB 3: Your code here.
28     (p->pp_ref)++;
29     pde_t* page_dir = page2kva(p);
30     memcpy(page_dir, kern_pgdir, PGSIZE);
31     e->env_pgdir = page_dir;
32 
33     // UVPT maps the env‘s own page table read-only.
34     // Permissions: kernel R, user R
35     e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_P | PTE_U;
36 
37     return 0;
38 }

 

3) region_alloc()

 region_alloc 为environment *e 开辟len byte大小的物理空间,并将va虚拟地址开始的len长度大小的空间和物理空间建立映射关系。

 1 static void
 2 region_alloc(struct Env *e, void *va, size_t len)
 3 {
 4     // LAB 3: Your code here.
 5     // (But only if you need it for load_icode.)
 6     //
 7     // Hint: It is easier to use region_alloc if the caller can pass
 8     //   ‘va‘ and ‘len‘ values that are not page-aligned.
 9     //   You should round va down, and round (va + len) up.
10     //   (Watch out for corner-cases!)
11 
12     va = ROUNDDOWN(va, PGSIZE);
13     len = ROUNDUP(len, PGSIZE);
14 
15     struct PageInfo *pp;
16     int ret = 0;
17 
18     for(; len > 0; len -= PGSIZE, va += PGSIZE)
19     {
20         pp = page_alloc(0);
21 
22         if(!pp)
23         {
24             panic("region_alloc failed\n");
25         }
26 
27         ret = page_insert(e->env_pgdir, pp, va, PTE_U | PTE_W | PTE_P);
28 
29         if(ret)
30         {
31             panic("region_alloc failed\n");
32         }
33     }
34 }

 

4) load_icode

load_icode将elf格式的二进制文件load到env中。

 1 static void
 2 load_icode(struct Env *e, uint8_t * binary)
 3 {
 4     // Hints:
 5     //  Load each program segment into virtual memory
 6     //  at the address specified in the ELF section header.
 7     //  You should only load segments with ph->p_type == ELF_PROG_LOAD.
 8     //  Each segment‘s virtual address can be found in ph->p_va
 9     //  and its size in memory can be found in ph->p_memsz.
10     //  The ph->p_filesz bytes from the ELF binary, starting at
11     //  ‘binary + ph->p_offset‘, should be copied to virtual address
12     //  ph->p_va.  Any remaining memory bytes should be cleared to zero.
13     //  (The ELF header should have ph->p_filesz <= ph->p_memsz.)
14     //  Use functions from the previous lab to allocate and map pages.
15     //
16     //  All page protection bits should be user read/write for now.
17     //  ELF segments are not necessarily page-aligned, but you can
18     //  assume for this function that no two segments will touch
19     //  the same virtual page.
20     //
21     //  You may find a function like region_alloc useful.
22     //
23     //  Loading the segments is much simpler if you can move data
24     //  directly into the virtual addresses stored in the ELF binary.
25     //  So which page directory should be in force during
26     //  this function?
27     //
28     //  You must also do something with the program‘s entry point,
29     //  to make sure that the environment starts executing there.
30     //  What?  (See env_run() and env_pop_tf() below.)
31 
32     // LAB 3: Your code here.
33 
34     struct Elf* elfhdr = (struct Elf *)binary;
35     struct Proghdr *ph, *eph;
36     
37     if(elfhdr->e_magic != ELF_MAGIC)
38     {
39         panic("elf header‘s magic is not correct\n");
40     }
41 
42     ph = (struct Proghdr *)((uint8_t *)elfhdr + elfhdr->e_phoff);
43 
44     eph = ph + elfhdr->e_phnum;
45 
46     lcr3(PADDR(e->env_pgdir));
47 
48     for(;ph < eph; ph++)
49     {
50         if(ph->p_type != ELF_PROG_LOAD)
51         {
52             continue;
53         }
54 
55         if(ph->p_filesz > ph->p_memsz)
56         {
57             panic("file size is great than memory size\n");
58         }
59 
60         region_alloc(e, (void *)ph->p_va, ph->p_memsz);
61         memmove((void *)ph->p_va, binary + ph->p_offset, ph->p_filesz);
62 
63         memset((void *)ph->p_va + ph->p_filesz, 0, (ph->p_memsz - ph->p_filesz));
64     }
65 
66     // Now map one page for the program‘s initial stack
67     // at virtual address USTACKTOP - PGSIZE.
68 
69     // LAB 3: Your code here.
70 
71     lcr3(PADDR(kern_pgdir));
72 
73     e->env_tf.tf_eip = elfhdr->e_entry;
74 
75     region_alloc(e, (void *)(USTACKTOP - PGSIZE), PGSIZE);
76 }

5) env_create 

env_create 申请新的env并将elf文件load到env中.

 1 void
 2 env_create(uint8_t *binary, enum EnvType type)
 3 {
 4     // LAB 3: Your code here.
 5     int ret = 0;
 6     struct Env *e = NULL;
 7     ret = env_alloc(&e, 0);
 8 
 9     if(ret < 0)
10     {
11         panic("env_create: %e\n", ret);
12     }
13 
14     load_icode(e, binary);
15     e->env_type = type;
16 }

6) env_run

env_run实现进程切换,先将当前进程状态置为RUNNABLE,然后通过lcr3切换进程空间,最后使用env_pop_tf切换到新的进程。

 1 void
 2 env_run(struct Env *e)
 3 {
 4     // Step 1: If this is a context switch (a new environment is running):
 5     //       1. Set the current environment (if any) back to
 6     //          ENV_RUNNABLE if it is ENV_RUNNING (think about
 7     //          what other states it can be in),
 8     //       2. Set ‘curenv‘ to the new environment,
 9     //       3. Set its status to ENV_RUNNING,
10     //       4. Update its ‘env_runs‘ counter,
11     //       5. Use lcr3() to switch to its address space.
12     // Step 2: Use env_pop_tf() to restore the environment‘s
13     //       registers and drop into user mode in the
14     //       environment.
15 
16     // Hint: This function loads the new environment‘s state from
17     //    e->env_tf.  Go back through the code you wrote above
18     //    and make sure you have set the relevant parts of
19     //    e->env_tf to sensible values.
20 
21     // LAB 3: Your code here.
22 
23     //panic("env_run not yet implemented");
24 
25     if(curenv && curenv->env_status == ENV_RUNNING)
26     {
27         curenv->env_status = ENV_RUNNABLE;
28     }
29 
30     curenv = e;
31     e->env_status = ENV_RUNNING;
32     e->env_runs++;
33 
34     lcr3(PADDR(e->env_pgdir));
35 
36     env_pop_tf(&(e->env_tf));
37 }

 

Part B: Page Faults, Breakpoints Exceptions, and System Calls

 

Mit os Lab 3. User Environmen

标签:

原文地址:http://www.cnblogs.com/ym65536/p/5652121.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!