《MIT JOS Lab3: User Environments》实验报告

本文详细介绍了操作系统中环境初始化过程,包括将环境结构插入到空闲队列,以及为新环境初始化页目录和地址空间的方法。通过具体代码示例,展示了如何分配页目录,设置环境的页目录,并正确处理物理页面的引用计数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

// Mark all environments in 'envs' as free, set their env_ids to 0,
// and insert them into the env_free_list.
// Make sure the environments are in the free list in the same order
// they are in the envs array (i.e., so that the first call to
// env_alloc() returns envs[0]).
void
env_init(void)
{
        // Set up envs array
        // LAB 3: Your code here.
        env_free_list = NULL;
        int i;
        for (i = NENV -1; i >= 0; i--){
                envs[i].env_id = 0;
                envs[i].env_parent_id = 0;
                envs[i].env_type = ENV_TYPE_USER;
                envs[i].env_status = ENV_FREE;
                envs[i].env_runs = 0;
                envs[i].env_pgdir = NULL;
                envs[i].env_link = env_free_list;
                env_free_list = &envs[i];
        }

        cprintf("env_free_list : 0x%08x, & envs[i]: 0x%08x\n", env_free_list, &envs[i]);
        // Per-CPU part of the initialization
        env_init_percpu();
}

这个函数是用来初始化所有环境中的envs结构,并把他们全部插入到空闲队列env_free_list中。

在文章开头部分提到了在 inc/env.h 中可以查看 envs的结构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
};
//
// Initialize the kernel virtual memory layout for environment e.
// Allocate a page directory, set e->env_pgdir accordingly,
// and initialize the kernel portion of the new environment's address space.
// Do NOT (yet) map anything into the user portion
// of the environment's virtual address space.
//
// Returns 0 on success, < 0 on error.  Errors include:
//      -E_NO_MEM if page directory or table could not be allocated.
//
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;

        // Now, set e->env_pgdir and initialize the page directory.
        //
        // Hint:
        //    - The VA space of all envs is identical above UTOP
        //      (except at UVPT, which we've set below).
        //      See inc/memlayout.h for permissions and layout.
        //      Can you use kern_pgdir as a template?  Hint: Yes.
        //      (Make sure you got the permissions right in Lab 2.)
        //    - The initial VA below UTOP is empty.
        //    - You do not need to make any more calls to page_alloc.
        //    - Note: In general, pp_ref is not maintained for
        //      physical pages mapped only above UTOP, but env_pgdir
        //      is an exception -- you need to increment env_pgdir's
        //      pp_ref for env_free to work correctly.
        //    - The functions in kern/pmap.h are handy.

        // LAB 3: Your code here.
        (p->pp_ref)++;
        pde_t* page_dir = page2kva(p);
        memcpy(page_dir, kern_pgdir, PGSIZE);
        e->env_pgdir = page_dir;

        // 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;
}

为新环境初始化目录页,并初始化内和部分新环境的地址空间。不同的进程有不同的虚拟地址空间,所以就会有自己的页目录和页表,该函数的任务就是初始化页目录。

首先分配一个空闲页面当页目录。然后将这个页目录映射内核地址空间,不需要映射页表因为可以和内核共用页表。接着添加对此虚拟页面的物理页面引用:将此页面的虚拟地址赋值给进程的pgdir,然后使得进程有权限操作自己的pgdir。

p是一个Page结构,分配完后为一个指针类型,想要将一个指针返回他的虚拟地址那么就要用到page2kva函数,将其转换为地址。Page结构中的 pp_ref 指的是页面的引用次数。这里要加一是因为 env_pgdir 对应的 Page 被某一用户进程使用,会出现释放掉当前未结束的用户进程的资源的情况,导致用户进程崩溃。

void
bootmain(void)
{
        struct Proghdr *ph, *eph;

        // read 1st page off disk
        readseg((uint32_t) ELFHDR, SECTSIZE*8, 0);

        // is this a valid ELF?
        if (ELFHDR->e_magic != ELF_MAGIC)
                goto bad;

        // load each program segment (ignores ph flags)
        ph = (struct Proghdr *) ((uint8_t *) ELFHDR + ELFHDR->e_phoff);
        eph = ph + ELFHDR->e_phnum;
        for (; ph < eph; ph++)
                // p_pa is the load address of this segment (as well
                // as the physical address)
                readseg(ph->p_pa, ph->p_memsz, ph->p_offset);

        // call the entry point from the ELF header
        // note: does not return!
        ((void (*)(void)) (ELFHDR->e_entry))();

bad:
        outw(0x8A00, 0x8A00);
        outw(0x8A00, 0x8E00);
        while (1)
                /* do nothing */;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值