// Make file descriptor 'newfdnum' a duplicate of file descriptor 'oldfdnum'.
// For instance, writing onto either file descriptor will affect the
// file and the file offset of the other.
// Closes any previously open file descriptor at 'newfdnum'.
// This is implemented using virtual memory tricks (of course!).
int
dup(int oldfdnum, int newfdnum)
{
	int r;
	char *ova, *nva;
	pte_t pte;
	struct Fd *oldfd, *newfd;

	if ((r = fd_lookup(oldfdnum, &oldfd)) < 0)
		return r;
	close(newfdnum);

	newfd = INDEX2FD(newfdnum);
	ova = fd2data(oldfd);
	nva = fd2data(newfd);

	if ((vpd[VPD(ova)] & PTE_P) && (vpt[VPN(ova)] & PTE_P))
		if ((r = sys_page_map(0, ova, 0, nva, vpt[VPN(ova)] & PTE_SYSCALL)) < 0)
			goto err;
	if ((r = sys_page_map(0, oldfd, 0, newfd, vpt[VPN(oldfd)] & PTE_SYSCALL)) < 0)
		goto err;

	return newfdnum;

err:
	sys_page_unmap(0, newfd);
	sys_page_unmap(0, nva);
	return r;
}
Exemple #2
1
// Challenge!
int
sfork(void)
{
	int r;
	pde_t *pde;
	pte_t *pte;
	unsigned i;
	uint32_t addr;
	envid_t envid;
	envid = sys_exofork();//创建子环境
	if(envid < 0)
		panic("sys_exofork: %e", envid);
	if(envid==0)//子环境中
	{
		env = &envs[ENVX(sys_getenvid())];
		return 0;
	}
	else{//父环境中,注意:这里需要设置父环境的缺页异常栈,还需要设置子环境的缺页异常栈,
	//父子环境的页异常栈不共享?具体原因还得思考
		env = &envs[ENVX(sys_getenvid())];
		set_pgfault_handler(pgfault);//设置缺页异常处理函数,这里设置了父环境的缺页异常栈
		for(i=0;i<(unsigned)VPN(UTOP);i++)//重映射writable or copy-to-write的页面
		{
			addr=i*PGSIZE;
			pde =(pde_t*) &vpd[VPD(addr)];
			if(*pde&PTE_P)//这里只处理有物理页面映射的页表项
			{
				pte=(pte_t*)&vpt[VPN(addr)];
			}
			else    continue;
			if((i==(unsigned)VPN(USTACKTOP-PGSIZE))||(i==(unsigned)VPN(PFTEMP)))
								//特殊处理,用户层普通栈
			{	
				if((r=duppage(envid,i))<0)
					return r;
				continue;
			}
			if((r=sduppage(envid,i))<0)
				return r;
		}
		if((r=sys_page_alloc(envid,(void*)(UXSTACKTOP-PGSIZE),PTE_W|PTE_U|PTE_P))<0)
                        return r;//设置子环境的缺页异常栈
		if((r=sys_env_set_pgfault_upcall(envid,(void*)_pgfault_upcall))<0)
			return r;//设置子环境的缺页异常处理入口点
		if((r=sys_env_set_status(envid,ENV_RUNNABLE))<0)
			return r;//设置子环境的状态为可运行
		return envid;
	}
	//panic("sfork not implemented");
	//return -E_INVAL;
}
// Copy the mappings for shared pages into the child address space.
    static int
copy_shared_pages(envid_t child)
{
    // LAB 7: Your code here.
    uint64_t vaddr;
    int r;
    for(vaddr=0; vaddr<UTOP; vaddr += PGSIZE) {
        
        // Copying from lib/fork.c bruh.
        if( // Gotta use the virtual types apparently.
            (vpml4e[VPML4E(vaddr)] & PTE_P) // Mota mota level is present.
            && ((vpde[VPDPE(vaddr)] & PTE_U) && (vpde[VPDPE(vaddr)] & PTE_P)) // Slighlt less mota level is also present.
            && ((vpd[VPD(vaddr)] & PTE_U) && (vpd[VPD(vaddr)] & PTE_P))
            &&  ((vpt[VPN(vaddr)] & PTE_U) && (vpt[VPN(vaddr)] & PTE_P))
            )
            if(vpt[VPN(vaddr)]&PTE_SHARE) {
                r = sys_page_map(0, (void*)vaddr, child, (void*)vaddr, vpt[VPN(vaddr)] & PTE_SYSCALL);
                if(r<0) {
                    cprintf("WARN: Your environments are now throughly done for man.\n");
                    return -1;
                }
            }
    }
    return 0;
}
Exemple #4
0
//
// User-level fork with copy-on-write.
// Set up our page fault handler appropriately.
// Create a child.
// Copy our address space and page fault handler setup to the child.
// Then mark the child as runnable and return.
//
// Returns: child's envid to the parent, 0 to the child, < 0 on error.
// It is also OK to panic on error.
//
// Hint:
//   Use uvpd, uvpt, and duppage.
//   Remember to fix "thisenv" in the child process.
//   Neither user exception stack should ever be marked copy-on-write,
//   so you must allocate a new page for the child's user exception stack.
//
envid_t
fork(void)
{
	// LAB 4: Your code here.
	set_pgfault_handler (pgfault);
	envid_t envid;
	uint32_t addr;
	int r;
	envid = sys_exofork();
	if (envid < 0)
		panic("sys_exofork: %e", envid);
	// We’re the child
	if (envid == 0) {
		env = &envs[ENVX(sys_getenvid())];
		return 0;
	}
	// We’re the parent.
	for (addr = UTEXT; addr < UXSTACKTOP - PGSIZE; addr += PGSIZE) {
	if ((vpd[VPD(addr)] & PTE_P) > 0 && (vpt[VPN(addr)] & PTE_P) > 0 && (vpt[
		VPN(addr)] & PTE_U) > 0)
		duppage (envid, VPN(addr));
	}

	if ((r = sys_page_alloc (envid, (void *)(UXSTACKTOP - PGSIZE), PTE_U|PTE_W|PTE_P)) < 0)
		panic ("fork: page allocation failed : %e", r);
	extern void _pgfault_upcall (void);
	sys_env_set_pgfault_upcall (envid, _pgfault_upcall);
	// Start the child environment running
	if ((r = sys_env_set_status(envid, ENV_RUNNABLE)) < 0)
		panic("fork: set child env status failed : %e", r);
	return envid;
	//panic("fork not implemented");
}
Exemple #5
0
// Copy the mappings for shared pages into the child address space.
static int
copy_shared_pages(envid_t child)
{
	// LAB 7: Your code here.
	int r;
	int pdeno, pteno;
	uint32_t pn = 0;
	
	for (pdeno = 0; pdeno < VPD(UTOP); pdeno++) 
	{
		if (vpd[pdeno] == 0) 
		{
			// skip empty PDEs
			pn += NPTENTRIES;
			continue;
		}
				
		for (pteno = 0; pteno < NPTENTRIES; pteno++,pn++) 
		{
			if (vpt[pn] == 0)
				// skip empty PTEs
				continue;
					
			int perm = vpt[pn] & PTE_USER;
			if (perm & PTE_SHARE) 
			{
				void *addr = (void *)(pn << PGSHIFT);
				r = sys_page_map(0, addr, child, addr, perm);
				if (r)
					return r;
			}
		}
	}
	return 0;
}
Exemple #6
0
//
// User-level fork with copy-on-write.
// Set up our page fault handler appropriately.
// Create a child.
// Copy our address space and page fault handler setup to the child.
// Then mark the child as runnable and return.
//
// Returns: child's envid to the parent, 0 to the child, < 0 on error.
// It is also OK to panic on error.
//
// Hint:
//   Use vpd, vpt, and duppage.
//   Remember to fix "thisenv" in the child process.
//   Neither user exception stack should ever be marked copy-on-write,
//   so you must allocate a new page for the child's user exception stack.
//
    envid_t
fork(void)
{
    // LAB 4: Your code here.
    envid_t envid;
        uint64_t addr;
        uint32_t err;
        extern unsigned char end[];
        int r;

        set_pgfault_handler(pgfault);
        envid = sys_exofork();

        if (envid < 0)
                panic("sys_exofork: %e", envid);
        if (envid == 0) {
                // We're the child.
                // The copied value of the global variable 'thisenv'
                // is no longer valid (it refers to the parent!).
                // Fix it and return 0.

                thisenv = &envs[ENVX(sys_getenvid())];
                return 0;
        }

        //Allocate exception stack for the child
        if ((err = sys_page_alloc(envid, (void *) (UXSTACKTOP - PGSIZE), PTE_P|PTE_U|PTE_W)) < 0)
                panic("Error in sys_page_alloc: %e", err);

        // We're the parent.
        // Map our entire address space into the child.
        for (addr = UTEXT; addr < USTACKTOP-PGSIZE; addr += PGSIZE) {
               if((vpml4e[VPML4E(addr)] & PTE_P) && (vpde[VPDPE(addr)] & PTE_P)
                        && (vpd[VPD(addr)] & PTE_P) && (vpt[VPN(addr)] & PTE_P)) {
                       duppage(envid, VPN(addr));
                }
        }

        //Allocate a new stack for the child and copy the contents of parent on to it.
        addr = USTACKTOP-PGSIZE;
	if ((r = sys_page_alloc(0, (void *)PFTEMP, PTE_P|PTE_U|PTE_W)) < 0)
                panic("sys_page_alloc failed: %e\n", r);
        memcpy(PFTEMP, (void *) ROUNDDOWN(addr, PGSIZE), PGSIZE);
        void *vaTemp = (void *) ROUNDDOWN(addr, PGSIZE);
        if ((r = sys_page_map(0, (void *)PFTEMP, envid, vaTemp, PTE_P|PTE_U|PTE_W)) < 0)
                panic("sys_page_map failed: %e\n", r);
        if ((r = sys_page_unmap(0, (void *)PFTEMP)) < 0)
                panic("sys_page_unmap failed: %e\n", r);

        //Set child's page fault handler
        if ((err = sys_env_set_pgfault_upcall(envid, _pgfault_upcall) < 0))
                panic("Error in sys_env_set_pgfault_upcall: %e",err);

        //Set the child ready to run
        if ((err = sys_env_set_status(envid, ENV_RUNNABLE)) < 0)
                panic("sys_env_set_status: %e", err);

        return envid;
    panic("fork not implemented");
}
Exemple #7
0
//
// Map our virtual page pn (address pn*PGSIZE) into the target envid
// at the same virtual address.  If the page is writable or copy-on-write,
// the new mapping must be created copy-on-write, and then our mapping must be
// marked copy-on-write as well.  (Exercise: Why do we need to mark ours
// copy-on-write again if it was already copy-on-write at the beginning of
// this function?)
//
// Returns: 0 on success, < 0 on error.
// It is also OK to panic on error.
// 
static int
duppage(envid_t envid, unsigned pn)
{
	int r;

	// LAB 4: Your code here.
	pde_t *pde;
	pte_t *pte;
	void *addr=(void*)(pn*PGSIZE);
	pde =(pde_t*) &vpd[VPD(addr)];
	if(*pde&PTE_P)
	{
		pte=(pte_t*)&vpt[VPN(addr)];
	}
	else    panic("page table for pn page is not exist");
	if((*pte&PTE_W)||(*pte&PTE_COW))
	{
		if((r=sys_page_map(0,addr,envid,addr,PTE_COW|PTE_U))<0)
			return r;
		if((r=sys_page_map(0,addr,0,addr,PTE_COW|PTE_U))<0)//映射的时候注意env的id
                        return r;
	}
	else{	
		if((r=sys_page_map(0,addr,envid,addr,PTE_U|PTE_P))<0)
			return r;
	}
	//panic("duppage not implemented");
	return 0;
}
Exemple #8
0
//
// Custom page fault handler - if faulting page is copy-on-write,
// map in our own private writable copy.
//
static void
pgfault(struct UTrapframe *utf)
{
	void *addr = (void *) utf->utf_fault_va;
	uint32_t err = utf->utf_err;
	int r;

	// Check that the faulting access was (1) a write, and (2) to a
	// copy-on-write page.  If not, panic.
	// Hint:
	//   Use the read-only page table mappings at uvpt
	//   (see <inc/memlayout.h>).

	// LAB 4: Your code here.
	if ((err & FEC_WR) == 0 || (vpd[VPD(addr)] & PTE_P) == 0 || (vpt[VPN(addr)] & PTE_COW) == 0)
		panic ("pgfault: not a write or attempting to access a non-COW page");
	// Allocate a new page, map it at a temporary location (PFTEMP),
	// copy the data from the old page to the new page, then move the new
	// page to the old page's address.
	// Hint:
	//   You should make three system calls.
	//   No need to explicitly delete the old page's mapping.

	// LAB 4: Your code here.
	if ((r = sys_page_alloc (0, (void *)PFTEMP, PTE_U|PTE_P|PTE_W)) < 0)
		panic ("pgfault: page allocation failed : %e", r);
	addr = ROUNDDOWN (addr, PGSIZE);
	memmove (PFTEMP, addr, PGSIZE);
	if ((r = sys_page_map (0, PFTEMP, 0, addr, PTE_U|PTE_P|PTE_W)) < 0)
		panic ("pgfault: page mapping failed : %e", r);
	//panic("pgfault not implemented");
}
Exemple #9
0
//
// Custom page fault handler - if faulting page is copy-on-write,
// map in our own private writable copy.
//
static void
pgfault(struct UTrapframe *utf)
{
	void *addr = (void *) utf->utf_fault_va;
	uint32_t err = utf->utf_err;
	int r;

	// Check that the faulting access was (1) a write, and (2) to a
	// copy-on-write page.  If not, panic.
	// Hint:
	//   Use the read-only page table mappings at vpt
	//   (see <inc/memlayout.h>).

	// LAB 4: Your code here.
	pde_t *pde;
	pte_t *pte;
	uint32_t *va,*srcva,*dstva;
	pde =(pde_t*) &vpd[VPD(addr)];
	if(*pde&PTE_P)
	{
		pte=(pte_t*)&vpt[VPN(addr)];
	}
	else{
		cprintf("addr=%x err=%x *pde=%x utf_eip=%x\n",(uint32_t)addr,err,*pde,utf->utf_eip);	
		panic("page table for fault va is not exist");
	}
	//cprintf("addr=%x err=%x *pte=%x utf_eip=%x\n",(uint32_t)addr,err,*pte,utf->utf_eip);
	if(!(err&FEC_WR)||!(*pte&PTE_COW))
	{	
		cprintf("envid=%x addr=%x err=%x *pte=%x utf_eip=%x\n",env->env_id,(uint32_t)addr,err,*pte,utf->utf_eip);
		panic("faulting access is illegle");
	}
	// Allocate a new page, map it at a temporary location (PFTEMP),
	// copy the data from the old page to the new page, then move the new
	// page to the old page's address.
	// Hint:
	//   You should make three system calls.
	//   No need to explicitly delete the old page's mapping.

	// LAB 4: Your code here.
	//cprintf("pgfault:env_id=%x\n",env->env_id);
	if((r=sys_page_alloc(0,PFTEMP,PTE_W|PTE_U|PTE_P))<0)
			//输入id=0表示当前环境id(curenv->env_id),这个时候不能用env->env-id,子环境中env的修改会缺页
		panic("alloc a page for PFTEMP failed:%e",r);
	//cprintf("PFTEMP=%x add=%x\n",PFTEMP,(uint32_t)addr&0xfffff000);
	srcva = (uint32_t*)((uint32_t)addr&0xfffff000);
	dstva = (uint32_t*)PFTEMP;
	//strncpy((char*)PFTEMP,(char*)((uint32_t)addr&0xfffff000),PGSIZE);
	for(;srcva<(uint32_t*)(ROUNDUP(addr,PGSIZE));srcva++)//数据拷贝要注意,用strncpy出错了,原因还得分析
	{
		*dstva=*srcva;
		dstva++;
	}
	if((r=sys_page_map(0,(void*)PFTEMP,0,(void*)((uint32_t)addr&0xfffff000),PTE_W|PTE_U|PTE_P))<0)
			//输入id=0表示当前环境id(curenv->env_id),这个时候不能用env->env-id,子环境中env的修改会缺页
		panic("page mapping failed");
	//panic("pgfault not implemented");
}
Exemple #10
0
//
// User-level fork with copy-on-write.
// Set up our page fault handler appropriately.
// Create a child.
// Copy our address space and page fault handler setup to the child.
// Then mark the child as runnable and return.
//
// Returns: child's envid to the parent, 0 to the child, < 0 on error.
// It is also OK to panic on error.
//
// Hint:
//   Use vpd, vpt, and duppage.
//   Remember to fix "thisenv" in the child process.
//   Neither user exception stack should ever be marked copy-on-write,
//   so you must allocate a new page for the child's user exception stack.
//
envid_t
fork(void)
{
	// LAB 4: Your code here.
	int r;
	envid_t envid;
	set_pgfault_handler(pgfault);
	if((envid = sys_exofork())<0)
		panic("sys_exofork error: %e\n",envid);

	if(envid == 0){
		thisenv = &envs[ENVX(sys_getenvid())];
		return 0;
	}	
	


	uint32_t vaddr;
	extern unsigned char end[];

	for (vaddr = 0 ; vaddr < UTOP; vaddr += PGSIZE ){
		//Check sequentially
		if ((vpml4e[VPML4E(vaddr)] & PTE_P ) && (vpde[VPDPE(vaddr)] & PTE_P ) && (vpd[VPD(vaddr)] & PTE_P ) 
				&& (vpt[VPN(vaddr)] & PTE_P)){ //Order is imp...
			if ((vaddr != (UXSTACKTOP - PGSIZE)) && (vaddr != (USTACKTOP - PGSIZE))){
				duppage(envid, (uint64_t)vaddr / PGSIZE);
			}
		}	
	}


	if ((r = sys_page_alloc(envid,(void*)(USTACKTOP - PGSIZE), PTE_U | PTE_W | PTE_P ))<0){
		panic("error from sys_page_alloc: %e\n", r);

	}
	else 
	{
		if ((r = sys_page_alloc(0, PFTEMP, PTE_U|PTE_W|PTE_P)) < 0)
	        panic("error from sys_page_alloc: %e", r);

		memmove(PFTEMP, (void *)(USTACKTOP - PGSIZE), PGSIZE);

		if ((r = sys_page_map(0,PFTEMP, envid, (void *)(USTACKTOP - PGSIZE) , PTE_U|PTE_W|PTE_P)) < 0)
	        panic("error from sys_page_map: %e", r);
	}

	if((r = sys_page_alloc(envid,(void*)(UXSTACKTOP - PGSIZE), PTE_U | PTE_W | PTE_P ))<0)	
		panic("error from sys_page_alloc : %e\n",r);

	if((r=sys_env_set_pgfault_upcall(envid, thisenv->env_pgfault_upcall))!=0)
		panic("error from sys_env_set_pgfault_upcall : %e\n",r);

	if((r = sys_env_set_status(envid, ENV_RUNNABLE))<0)
		panic("error from sys_env_set_status : %e\n",r);
	
	return envid;

}
static int
isfree(void *v, size_t n)
{
    uintptr_t va, end_va = (uintptr_t) v + n;

    for (va = (uintptr_t) v; va < end_va; va += PGSIZE)
        if (va >= (uintptr_t) mend
                || ((vpd[VPD(va)] & PTE_P) && (vpt[VPN(va)] & PTE_P)))
            return 0;
    return 1;
}
Exemple #12
0
// Copy the mappings for shared pages into the child address space.
    static int
copy_shared_pages(envid_t child)
{
	// LAB 7: Your code here.
        uint64_t addr;
	for (addr = UTEXT; addr < USTACKTOP-PGSIZE; addr += PGSIZE) {
               if((vpml4e[VPML4E(addr)] & PTE_P) && (vpde[VPDPE(addr)] & PTE_P)  
                 && (vpd[VPD(addr)] & PTE_P) && (vpt[VPN(addr)] & PTE_P)) {
                        int perm_share = vpt[VPN(addr)] & PTE_USER;
                        if (perm_share & PTE_SHARE)
                                sys_page_map(0, (void *)addr, child, (void *)addr, perm_share);
                }
        }

	return 0;
}
// Finds the smallest i from 0 to MAXFD-1 that doesn't have
// its fd page mapped.
// Sets *fd_store to the corresponding fd page virtual address.
//
// fd_alloc does NOT actually allocate an fd page.
// It is up to the caller to allocate the page somehow.
// This means that if someone calls fd_alloc twice in a row
// without allocating the first page we return, we'll return the same
// page the second time.
//
// Hint: Use INDEX2FD.
//
// Returns 0 on success, < 0 on error.  Errors are:
//	-E_MAX_FD: no more file descriptors
// On error, *fd_store is set to 0.
int
fd_alloc(struct Fd **fd_store)
{
	int i;
	struct Fd *fd;

	for (i = 0; i < MAXFD; i++) {
		fd = INDEX2FD(i);
		if ((vpd[VPD(fd)] & PTE_P) == 0 || (vpt[VPN(fd)] & PTE_P) == 0) {
			*fd_store = fd;
			return 0;
		}
	}
	*fd_store = 0;
	return -E_MAX_OPEN;
}
Exemple #14
0
//
// User-level fork with copy-on-write.
// Set up our page fault handler appropriately.
// Create a child.
// Copy our address space and page fault handler setup to the child.
// Then mark the child as runnable and return.
//
// Returns: child's envid to the parent, 0 to the child, < 0 on error.
// It is also OK to panic on error.
//
// Hint:
//   Use vpd, vpt, and duppage.
//   Remember to fix "env" in the child process.
//   Neither user exception stack should ever be marked copy-on-write,
//   so you must allocate a new page for the child's user exception stack.
//
envid_t
fork(void)
{
	// LAB 4: Your code here.	
	int r;
	pde_t *pde;
	pte_t *pte;
	unsigned i;
	uint32_t addr;
	envid_t envid;
	envid = sys_exofork();//创建子环境
	if(envid < 0)
		panic("sys_exofork: %e", envid);
	if(envid==0)//子环境中
	{
		env = &envs[ENVX(sys_getenvid())];
		return 0;
	}
	else{//父环境中
		set_pgfault_handler(pgfault);//设置缺页异常处理函数,这里设置了父环境的缺页异常栈
		for(i=0;i<(unsigned)VPN(UTOP);i++)//重映射writable or copy-to-write的页面
		{
			if(i==(unsigned)VPN(UXSTACKTOP-PGSIZE))//特殊处理,用户层缺页异常栈
				continue;
			addr=i*PGSIZE;
			pde =(pde_t*) &vpd[VPD(addr)];
			if(*pde&PTE_P)//这里只处理有物理页面映射的页表项
			{
				pte=(pte_t*)&vpt[VPN(addr)];
			}
			else    continue;
			if((*pte&PTE_W)||(*pte&PTE_COW))
			{
				if((r=duppage(envid,i))<0)
					return r;
			}
		}
		if((r=sys_page_alloc(envid,(void*)(UXSTACKTOP-PGSIZE),PTE_W|PTE_U|PTE_P))<0)
			return r;//设置子环境的缺页异常栈
		if((r=sys_env_set_pgfault_upcall(envid,(void*)_pgfault_upcall))<0)
			return r;//设置子环境的缺页异常处理入口点
		if((r=sys_env_set_status(envid,ENV_RUNNABLE))<0)
			return r;//设置子环境的状态为可运行
		return envid;
	}
	//panic("fork not implemented");
}
int32_t net_host_send(char *pg, int len) {
    // LAB 8: Your code here.

    if (pg == NULL)
        pg = (void*) UTOP;

    uint64_t addr = (uint64_t)pg;                                                                                                                                   

    if( (vpml4e[VPML4E(addr)] & PTE_P)   &&   (vpde[VPDPE(addr)] & PTE_P)                                                                                     
            &&  (vpd[VPD(addr)] & PTE_P)  &&  (vpt[VPN(addr)] & PTE_P)  )
    {
        pg = (void *) PTE_ADDR( vpt[VPN(addr)] );
    }

    int ret =  vm_call( VMX_VMCALL_NETSEND, (uint64_t) pg , (uint64_t) len, 0, 0, 0 );
    return ret;
}
// Check that fdnum is in range and mapped.
// If it is, set *fd_store to the fd page virtual address.
//
// Returns 0 on success (the page is in range and mapped), < 0 on error.
// Errors are:
//	-E_INVAL: fdnum was either not in range or not mapped.
int
fd_lookup(int fdnum, struct Fd **fd_store)
{
	struct Fd *fd;

	if (fdnum < 0 || fdnum >= MAXFD) {
		if (debug)
			cprintf("[%08x] bad fd %d\n", thisenv->env_id, fdnum);
		return -E_INVAL;
	}
	fd = INDEX2FD(fdnum);
	if (!(vpd[VPD(fd)] & PTE_P) || !(vpt[VPN(fd)] & PTE_P)) {
		if (debug)
			cprintf("[%08x] closed fd %d\n", thisenv->env_id, fdnum);
		return -E_INVAL;
	}
	*fd_store = fd;
	return 0;
}
Exemple #17
0
// 		The parent installs pgfault() as the C-level page fault handler, using the set_pgfault_handler() function you implemented above.
//		 The parent calls sys_exofork() to create a child environment.
//		 For each writable or copy-on-write page in its address space below UTOP, the parent calls duppage, which should map the page copy-on-write into the address space of the child and then remap the page copy-on-write in its own address space. duppage sets both PTEs so that the page is not writeable, and to contain PTE_COW in the "avail" field to distinguish copy-on-write pages from genuine read-only pages.
//		 The exception stack is not remapped this way, however. Instead you need to allocate a fresh page in the child for the exception stack. 
// 		Since the page fault handler will be doing the actual copying and the page fault handler runs on the exception stack, the exception stack cannot be made copy-on-write: who would copy it?
// 		fork() also needs to handle pages that are present, but not writable or copy-on-write.
// 		The parent sets the user page fault entrypoint for the child to look like its own.
// 		The child is now ready to run, so the parent marks it runnable.
//
// User-level fork with copy-on-write.
// Set up our page fault handler appropriately.
// Create a child.
// Copy our address space and page fault handler setup to the child.
// Then mark the child as runnable and return.
//
// Returns: child's envid to the parent, 0 to the child, < 0 on error.
// It is also OK to panic on error.
//
// Hint:
//   Use vpd, vpt, and duppage.
//   Remember to fix "thisenv" in the child process.
//   Neither user exception stack should ever be marked copy-on-write,
//   so you must allocate a new page for the child's user exception stack.
//
    envid_t
fork(void)
{
	// LAB 4: Your code here.
	set_pgfault_handler(pgfault);
	envid_t eid = sys_exofork();
	if(eid < 0) // error
		panic("couldn't fork child. %e",eid);
	else if(eid == 0) { // child
		thisenv = envs+ENVX(sys_getenvid());
		return 0;
	}
	else { //parent
		uint64_t r;
    		for (r = 0; r < (uint64_t)(UXSTACKTOP-PGSIZE); r += PGSIZE) {
    			if(	(vpml4e[VPML4E(r)] & PTE_P) &&
    				(vpde[VPDPE(r)] & PTE_P) &&
 	   			(vpd[VPD(r)] & PTE_P) && 
 	   			(vpt[VPN(r)] & PTE_P)) 
 	   			{	
					duppage(eid, VPN(r));
				}
			}
		
		//Duppage the stack for the child
		duppage(eid, VPN(USTACKTOP-PGSIZE));
		
		// Instead you need to allocate a fresh page in the child for the exception stack
		if((r= sys_page_alloc(eid, (void *)(UXSTACKTOP-PGSIZE), PTE_U|PTE_P|PTE_W)) < 0)
			panic("fork failed setting UXSTACK for child %e", r);
		
		//The parent sets the user page fault entrypoint for the child to look like its own.
		if((r= sys_env_set_pgfault_upcall(eid, thisenv->env_pgfault_upcall)) < 0) //
			panic("fork failed setting pgfault handler %e", r);
		
		//The child is now ready to run, so the parent marks it runnable.
		if((r= sys_env_set_status(eid, ENV_RUNNABLE)) < 0)
			panic("fork failed setting status %e", r);
		//cprintf("forked the child\n");
		return eid;
	}
	//panic("fork not implemented");
}
Exemple #18
0
// Copy the mappings for shared pages into the child address space.
static int
copy_shared_pages(envid_t child) {
  // LAB 7: Your code here.

  int i,j, r;
  void* va;

  for (i=0; i < VPD(UTOP); i++) {
    if (vpd[i] & PTE_P) {
      for (j=0; j<NPTENTRIES && i*NPDENTRIES+j < (UXSTACKTOP-PGSIZE)/PGSIZE; j++) { // make sure not to remap exception stack this way
        if ((vpt[i*NPDENTRIES+j] & (PTE_P | PTE_SHARE)) == (PTE_P | PTE_SHARE)) {
          va = (void *)((i*NPDENTRIES+j) << PGSHIFT);
          if ((r = sys_page_map(0, va, child, va, vpt[i*NPDENTRIES+j] & PTE_USER)) < 0) {
            return r;
          }
        }
      }
    }
  }

  return 0;

}
Exemple #19
0
// Unmap any file pages that no longer represent valid file pages
// when the size of the file as mapped in our address space decreases.
// Harmlessly does nothing if newsize >= oldsize.
static int
funmap(struct Fd* fd, off_t oldsize, off_t newsize, bool dirty)
{
	size_t i;
	char *va;
	int r, ret;

	va = fd2data(fd);

	// Check vpd to see if anything is mapped.
	if (!(vpd[VPD(va)] & PTE_P))
		return 0;

	ret = 0;
	for (i = ROUNDUP(newsize, PGSIZE); i < oldsize; i += PGSIZE)
		if (vpt[VPN(va + i)] & PTE_P) {
			if (dirty
			    && (vpt[VPN(va + i)] & PTE_D)
			    && (r = fsipc_dirty(fd->fd_file.id, i)) < 0)
				ret = r;
			sys_page_unmap(0, va + i);
		}
  	return ret;
}
Exemple #20
0
//
// User-level fork with copy-on-write.
// Set up our page fault handler appropriately.
// Create a child.
// Copy our address space and page fault handler setup to the child.
// Then mark the child as runnable and return.
//
// Returns: child's envid to the parent, 0 to the child, < 0 on error.
// It is also OK to panic on error.
//
// Hint:
//   Use vpd, vpt, and duppage.
//   Remember to fix "env" in the child process.
//   Neither user exception stack should ever be marked copy-on-write,
//   so you must allocate a new page for the child's user exception stack.
//
envid_t
fork(void)
{
	// LAB 4: Your code here.
	// panic("fork not implemented");
	envid_t child_envid;
	extern void _pgfault_upcall(void);
	int r;
	uint32_t pde_x, pte_x, vpn;	// page directory index, page table index and page number
	

	// Set up our page fault handler appropriately.
	set_pgfault_handler(pgfault);
	if (debug)
		cprintf("\n After set_pgfaulthandler()\n");
	// Create a child.
	child_envid = sys_exofork();
	if (debug)
		cprintf("\n After exofork()\n");
	if (child_envid < 0)
		return child_envid;
	if (debug)
		cprintf("\n After child_envid >= 0\n");
		// panic(" panic in lib/fork.c - fork():sys_exofork: %e", child_env);
	// fix "env" in the child process
	if (child_envid == 0)
	{
		if (debug)
			cprintf("\n After child_envid == 0\n");
		env = &envs[ENVX(sys_getenvid())];
		return 0;
	}
	// reached here... we're the parent process
	// Map the address space except the user exception stack
	if (debug)
		cprintf("\n After child_envid > 0\n");
	for (pde_x = VPD(0); pde_x < VPD(UTOP); pde_x++)
	{
		if ((vpd[pde_x] & PTE_P) == PTE_P)
		{
			for (pte_x = 0; pte_x < NPTENTRIES; pte_x++)
			{
				vpn = (pde_x << (PDXSHIFT - PTXSHIFT)) + pte_x;		//removed hardcoding
				if(((vpt[vpn] & PTE_P) == PTE_P) && (vpn < VPN(UXSTACKTOP - PGSIZE)))
				{
					if (debug)
						cprintf("\n Before duppage\n");		
					duppage(child_envid, vpn);
					if (debug)
						cprintf("\n After duppage\n");		
				}
			}
		}
	}	
	if (debug)
		cprintf("\n After duppaging()\n");
	// Allocate and copy the use exception stack for the child environment
	// Allocate a page for the stack in the child
	if ((r = sys_page_alloc(child_envid, (void*)(UXSTACKTOP - PGSIZE), PTE_P | PTE_U | PTE_W)) < 0)
		return r;
	if (debug)
		cprintf("\n After set_pgfaulthandler()\n");
	// Map this page to a free virtual address space in parent
	if ((r = sys_page_map(child_envid, (void*)(UXSTACKTOP - PGSIZE), 0, (void*)UTEMP, PTE_P | PTE_U | PTE_W)) < 0)
		return r;
	if (debug)
		cprintf("\n After sys_page_map()\n");
	// Copy the parent exception stack to the above, i.e. page from child mapped to parent's address space
	memmove((void*)UTEMP, (void*)(UXSTACKTOP - PGSIZE), PGSIZE);
	if (debug)
		cprintf("\n After memmove()\n");
	// Unmap this page from the parent
	sys_page_unmap(0, (void*)UTEMP);
	if (debug)
		cprintf("\n After sys_page_unmap()\n");

	// Set up the page fault handler
	if ((r = sys_env_set_pgfault_upcall(child_envid, _pgfault_upcall)) < 0)
		return r;
		// panic(" panic in lib/fork.c - fork():sys_env_set_pgfault_upcall: %e", child_env);
	if (debug)
		cprintf("\n After set_upcall()\n");

	// Mark the child runnable
	if ((r = sys_env_set_status(child_envid, ENV_RUNNABLE)) < 0)
		return r;
		// panic(" panic in lib/fork.c - fork():sys_env_set_status: %e", child_env);
	if (debug)
		cprintf("\n After set_status()\n");
	
	return child_envid;
	
}
Exemple #21
0
// Is this virtual address mapped?
bool
va_is_mapped(void *va)
{
	return (vpml4e[VPML4E(va)] & PTE_P) && (vpde[VPDPE(va)] & PTE_P) && (vpd[VPD(va)] & PTE_P) && (vpt[PPN(va)] & PTE_P);
}