process&thread
Exercise 2:创建并且运行process
首先是env_init()函数
函数的作用:1. 初始化所有的在envs数组中的 Env结构体,并把它们加入到 env_free_list中。
还要调用 env_init_percpu,这个函数要配置段式内存管理系统,让它所管理的段,可能具有两种访问优
先级其中的一种,一个是内核运行时的0优先级,以及用户运行时的3优先级
code如下:
void
env_init(void)
{
// Set up envs array
// LAB 3: Your code here.
int number;
env_free_list = NULL;
for ( number = NENV - 1; number > 0 ; number--) //the maxium number of the free_list
{
envs[i].env_id = 0;
envs[i].env_status = ENV_FREE;
envs[i].env_link = env_free_list; //the env_free_list is a pointer which point to the next free process
env_free_list = &envs[i];//update the env_free_list
}
// panic("env_init not yet implemented");
// Per-CPU part of the initialization
env_init_percpu();
}
之后是env_setup_vm()函数:
具体作用:为一个新的process分配一个页面目录,并且初始化这个页面目录中与kernal相关的部分
code:
static int
env_setup_vm(struct Env *e)
{
int i;
struct PageInfo *p = NULL;
// Allocate a page for the page directory
if (!(p = page_alloc(ALLOC_ZERO)))
return -E_NO_MEM;
// LAB 3: Your code here.
e->env_pgdir = (pde_t*)page2kva(p);
p->pp_ref++;
//put the directory below UTOP
for (i = 0; i < PDX(UTOP); i++)
{
e->env_pgdir[i] = 0;
}
//put the directory above UTOP
for ( i = PDX(UTOP) ; i < NPDENTRIES; i++)
{
e->env_pgdir[i] = kern_pgdir[i];
}
// e->env_pgdir = KADDR(page2pa(p));
// memcpy((void*)(e->env_pgdir), (void*)kern_pgdir, PGSIZE);
// UVPT maps the env's own page table read-only.
// Permissions: kernel R, user R
e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_P | PTE_U;
return 0;
}
region_alloc()函数
作用:为process分配和映射物理内存
Hint:当”len“个bytes和对应虚拟地址为”va“不是页对齐的时候会更加简单,va向下取整,而va+len向上取整
code
static void
region_alloc(struct Env *e, void *va, size_t len)
{
// LAB 3: Your code here.
// (But only if you need it for load_icode.)
//
// Hint: It is easier to use region_alloc if the caller can pass
// 'va' and 'len' values that are not page-aligned.
// You should round va down, and round (va + len) up.
// (Watch out for corner-cases!)
uint32_t VA = ROUNDDOWN((uint32_t)va, PGSIZE);
uint32_t N = ROUNDUP((uint32_t)va + len, PGSIZE);
for(uint32_t i = VA; i< N; i += PGSIZE){
if(page_lookup(e->env_pgdir, (void*)i, NULL))
continue;
struct PageInfo* pp = page_alloc(0);
if(!pp)
panic("region_alloc: alloc env region failed.");
page_insert(e->env_pgdir, pp, (void*)i, PTE_U|PTE_W);
}
}
load_icode()函数
主要作用:解析二进制ELF映像,并且把它的内容加到对应的process的用户地址空间中
code
static void
load_icode(struct Env *e, uint8_t *binary)
{
// LAB 3: Your code here.
struct Elf *elf = (struct Elf*) binary;
struct Proghdr* ph, *eph;
if (elf->e_magic != ELF_MAGIC)
panic("Not valid ELF file.");
ph = (struct Proghdr *) ((uint8_t *) elf + elf->e_phoff);
eph = ph + elf->e_phnum;
lcr3(PADDR(e->env_pgdir));
for (; ph < eph; ph++){
if(!(ph->p_filesz <= ph->p_memsz))
panic("Bad proghdr!");
if(ph->p_type != ELF_PROG_LOAD)
continue;
uint32_t va = ph->p_va;
region_alloc(e, (void*)va, ph->p_memsz);
memcpy((void*)va, (void*)(binary + ph->p_offset), ph->p_memsz);
memset((void*)va+ph->p_filesz, '\0', ph->p_memsz - ph->p_filesz);
}
// switch back to kern_pgdir
lcr3(PADDR(kern_pgdir));
// save the eip in trapframe
e->env_tf.tf_eip = elf->e_entry;
// Now map one page for the program's initial stack
// at virtual address USTACKTOP - PGSIZE.
// LAB 3: Your code here.
region_alloc(e, (void*)(USTACKTOP - PGSIZE), PGSIZE);
// note that stack top has been set by env_alloc()
}
env_creat()函数:
参数* binary:将要加载的可执行文件的起始位置,type:process类型
code:
void
env_create(uint8_t *binary, enum EnvType type)
{
// LAB 3: Your code here.
// panic("env_create not yet implemented");
struct Env* e;
int r;
if ((r = env_alloc(&e, 0) != 0)) {
panic("create env failed\n");
}
load_icode(e, binary);
e->env_type = type;
}
env_run()
void
env_run(struct Env *e)
{
if (curenv != NULL && curenv->env_status == ENV_RUNNING) {
curenv->env_status = ENV_RUNNABLE;
}
curenv = e;
e->env_status = ENV_RUNNING;
e->env_runs++;
lcr3(PADDR(e->env_pgdir));
env_pop_tf(&e->env_tf);
// LAB 3: Your code here.
panic("env_run not yet implemented");
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!