Implement parts A and B.
This commit is contained in:
		
							parent
							
								
									86c4aa03ed
								
							
						
					
					
						commit
						721a113c93
					
				@ -356,6 +356,7 @@ load_icode(struct Env *e, uint8_t *binary)
 | 
			
		||||
	// LAB 3: Your code here.
 | 
			
		||||
 | 
			
		||||
	// TODO validate the headers 
 | 
			
		||||
	lcr3(PADDR(e->env_pgdir));
 | 
			
		||||
	struct Elf* elf = (struct Elf*) binary;
 | 
			
		||||
	struct Proghdr* ph = (struct Proghdr*) (binary + elf->e_phoff);
 | 
			
		||||
	struct Proghdr* phend = ph + elf->e_phnum;
 | 
			
		||||
@ -363,11 +364,10 @@ load_icode(struct Env *e, uint8_t *binary)
 | 
			
		||||
		if(ph->p_type != ELF_PROG_LOAD) continue;
 | 
			
		||||
 | 
			
		||||
		region_alloc(e, (void*) ph->p_va, ph->p_memsz);
 | 
			
		||||
		lcr3(PADDR(e->env_pgdir));
 | 
			
		||||
		memcpy((void*) ph->p_va, binary + ph->p_offset, ph->p_filesz);
 | 
			
		||||
		memset((void*) ph->p_va + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
 | 
			
		||||
		lcr3(PADDR(kern_pgdir));
 | 
			
		||||
	}
 | 
			
		||||
	lcr3(PADDR(kern_pgdir));
 | 
			
		||||
	e->env_tf.tf_eip = elf->e_entry;
 | 
			
		||||
 | 
			
		||||
	// Now map one page for the program's initial stack
 | 
			
		||||
@ -528,6 +528,7 @@ env_run(struct Env *e)
 | 
			
		||||
	e->env_status = ENV_RUNNING;
 | 
			
		||||
	e->env_runs++;
 | 
			
		||||
	lcr3(PADDR(e->env_pgdir));
 | 
			
		||||
	unlock_kernel();
 | 
			
		||||
	env_pop_tf(&e->env_tf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -55,6 +55,7 @@ i386_init(void)
 | 
			
		||||
 | 
			
		||||
	// Acquire the big kernel lock before waking up APs
 | 
			
		||||
	// Your code here:
 | 
			
		||||
	lock_kernel();
 | 
			
		||||
 | 
			
		||||
	// Starting non-boot CPUs
 | 
			
		||||
	boot_aps();
 | 
			
		||||
@ -64,7 +65,10 @@ i386_init(void)
 | 
			
		||||
	ENV_CREATE(TEST, ENV_TYPE_USER);
 | 
			
		||||
#else
 | 
			
		||||
	// Touch all you want.
 | 
			
		||||
	ENV_CREATE(user_primes, ENV_TYPE_USER);
 | 
			
		||||
	ENV_CREATE(user_yield, ENV_TYPE_USER);
 | 
			
		||||
	ENV_CREATE(user_yield, ENV_TYPE_USER);
 | 
			
		||||
	ENV_CREATE(user_yield, ENV_TYPE_USER);
 | 
			
		||||
	ENV_CREATE(user_yield, ENV_TYPE_USER);
 | 
			
		||||
#endif // TEST*
 | 
			
		||||
 | 
			
		||||
	// Schedule and run the first user environment!
 | 
			
		||||
@ -121,6 +125,8 @@ mp_main(void)
 | 
			
		||||
	// only one CPU can enter the scheduler at a time!
 | 
			
		||||
	//
 | 
			
		||||
	// Your code here:
 | 
			
		||||
	lock_kernel();
 | 
			
		||||
	sched_yield();
 | 
			
		||||
 | 
			
		||||
	// Remove this after you finish Exercise 6
 | 
			
		||||
	for (;;);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								kern/pmap.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								kern/pmap.c
									
									
									
									
									
								
							@ -195,6 +195,7 @@ mem_init(void)
 | 
			
		||||
	//    - the new image at UENVS  -- kernel R, user R
 | 
			
		||||
	//    - envs itself -- kernel RW, user NONE
 | 
			
		||||
	// LAB 3: Your code here.
 | 
			
		||||
	cprintf("Mapping envs from %p to %p\n", UENVS, ROUNDUP(envs_size, PGSIZE));
 | 
			
		||||
	boot_map_region(kern_pgdir,
 | 
			
		||||
		UENVS, ROUNDUP(envs_size, PGSIZE),
 | 
			
		||||
		PADDR(envs), PTE_U);
 | 
			
		||||
@ -276,6 +277,11 @@ mem_init_mp(void)
 | 
			
		||||
	//     Permissions: kernel RW, user NONE
 | 
			
		||||
	//
 | 
			
		||||
	// LAB 4: Your code here:
 | 
			
		||||
	for(int i = 0; i < NCPU; i++) {
 | 
			
		||||
		uintptr_t kstacktop = KSTACKTOP - i * (KSTKSIZE + KSTKGAP);
 | 
			
		||||
		boot_map_region(kern_pgdir, kstacktop - KSTKSIZE,
 | 
			
		||||
				KSTKSIZE, PADDR(percpu_kstacks[i]), PTE_W);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -289,6 +295,7 @@ is_reserved(size_t pagenum) {
 | 
			
		||||
	if(pagenum == 0) return true;
 | 
			
		||||
	if(pagenum >= PGNUM(IOPHYSMEM) &&
 | 
			
		||||
		pagenum < PGNUM(PADDR(boot_alloc(0)))) return true;
 | 
			
		||||
	if(pagenum == PGNUM(MPENTRY_PADDR)) return true;
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
@ -596,7 +603,15 @@ mmio_map_region(physaddr_t pa, size_t size)
 | 
			
		||||
	// Hint: The staff solution uses boot_map_region.
 | 
			
		||||
	//
 | 
			
		||||
	// Your code here:
 | 
			
		||||
	panic("mmio_map_region not implemented");
 | 
			
		||||
	size = ROUNDUP(size, PGSIZE);
 | 
			
		||||
	if((base + size) > MMIOLIM)
 | 
			
		||||
		panic("Not enough memory-mapped IO space!");
 | 
			
		||||
 | 
			
		||||
	boot_map_region(kern_pgdir, base, size, pa, PTE_PCD | PTE_PWT | PTE_W);
 | 
			
		||||
	uintptr_t to_return = base;
 | 
			
		||||
	base += size;
 | 
			
		||||
 | 
			
		||||
	return (void*) to_return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uintptr_t user_mem_check_addr;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								kern/sched.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								kern/sched.c
									
									
									
									
									
								
							@ -29,6 +29,23 @@ sched_yield(void)
 | 
			
		||||
	// below to halt the cpu.
 | 
			
		||||
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	struct Env* next_env = curenv ? curenv + 1 : envs;
 | 
			
		||||
	struct Env* end_env = envs + NENV;
 | 
			
		||||
	struct Env* to_run = NULL;
 | 
			
		||||
 | 
			
		||||
	for(int i = 0; i < NENV; i++, next_env++) {
 | 
			
		||||
		if(next_env == end_env) next_env = envs;
 | 
			
		||||
		if(next_env->env_status == ENV_RUNNABLE) {
 | 
			
		||||
			to_run = next_env;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(!to_run && curenv && curenv->env_status == ENV_RUNNING) {
 | 
			
		||||
		to_run = curenv;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(to_run) env_run(to_run);
 | 
			
		||||
 | 
			
		||||
	// sched_halt never returns
 | 
			
		||||
	sched_halt();
 | 
			
		||||
 | 
			
		||||
@ -80,9 +80,16 @@ sys_exofork(void)
 | 
			
		||||
	// status is set to ENV_NOT_RUNNABLE, and the register set is copied
 | 
			
		||||
	// from the current environment -- but tweaked so sys_exofork
 | 
			
		||||
	// will appear to return 0.
 | 
			
		||||
	struct Env* new_env;
 | 
			
		||||
	int error_code;
 | 
			
		||||
	
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	panic("sys_exofork not implemented");
 | 
			
		||||
	error_code = env_alloc(&new_env, curenv->env_id);
 | 
			
		||||
	if(error_code < 0) return error_code;
 | 
			
		||||
 | 
			
		||||
	new_env->env_tf = curenv->env_tf;
 | 
			
		||||
	new_env->env_tf.tf_regs.reg_eax = 0;
 | 
			
		||||
	new_env->env_status = ENV_NOT_RUNNABLE;
 | 
			
		||||
	return new_env->env_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set envid's env_status to status, which must be ENV_RUNNABLE
 | 
			
		||||
@ -100,9 +107,17 @@ sys_env_set_status(envid_t envid, int status)
 | 
			
		||||
	// You should set envid2env's third argument to 1, which will
 | 
			
		||||
	// check whether the current environment has permission to set
 | 
			
		||||
	// envid's status.
 | 
			
		||||
	struct Env* env;
 | 
			
		||||
	int error_code;
 | 
			
		||||
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	panic("sys_env_set_status not implemented");
 | 
			
		||||
	error_code = envid2env(envid, &env, 1);
 | 
			
		||||
	if(error_code < 0) return error_code;
 | 
			
		||||
 | 
			
		||||
	if(status != ENV_RUNNABLE && status != ENV_NOT_RUNNABLE)
 | 
			
		||||
		return -E_INVAL;
 | 
			
		||||
 | 
			
		||||
	env->env_status = status;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set the page fault upcall for 'envid' by modifying the corresponding struct
 | 
			
		||||
@ -116,10 +131,18 @@ sys_env_set_status(envid_t envid, int status)
 | 
			
		||||
static int
 | 
			
		||||
sys_env_set_pgfault_upcall(envid_t envid, void *func)
 | 
			
		||||
{
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	panic("sys_env_set_pgfault_upcall not implemented");
 | 
			
		||||
	struct Env* env;
 | 
			
		||||
	int return_code;
 | 
			
		||||
	if((return_code = envid2env(envid, &env, 1)) < 0) return return_code;
 | 
			
		||||
	env->env_pgfault_upcall = func;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define SYS_CHECKPERMS(perm) \
 | 
			
		||||
	((((perm) & (PTE_P | PTE_U)) == (PTE_P | PTE_U)) && \
 | 
			
		||||
	 (((perm) & ~(PTE_P | PTE_U | PTE_W | PTE_AVAIL)) == 0))
 | 
			
		||||
#define SYS_CHECKADDR(addr) (((uintptr_t) (addr) < UTOP) && ((uintptr_t) (addr) % PGSIZE == 0))
 | 
			
		||||
 | 
			
		||||
// Allocate a page of memory and map it at 'va' with permission
 | 
			
		||||
// 'perm' in the address space of 'envid'.
 | 
			
		||||
// The page's contents are set to 0.
 | 
			
		||||
@ -145,9 +168,22 @@ sys_page_alloc(envid_t envid, void *va, int perm)
 | 
			
		||||
	//   parameters for correctness.
 | 
			
		||||
	//   If page_insert() fails, remember to free the page you
 | 
			
		||||
	//   allocated!
 | 
			
		||||
	struct Env* env;
 | 
			
		||||
	int return_code;
 | 
			
		||||
	if((return_code = envid2env(envid, &env, 1)) < 0) return return_code;
 | 
			
		||||
	
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	panic("sys_page_alloc not implemented");
 | 
			
		||||
	if(!SYS_CHECKPERMS(perm)) return -E_INVAL;
 | 
			
		||||
	if(!SYS_CHECKADDR(va)) return -E_INVAL;
 | 
			
		||||
 | 
			
		||||
	struct PageInfo* page = page_alloc(1);
 | 
			
		||||
	if(!page) return -E_NO_MEM;
 | 
			
		||||
 | 
			
		||||
	if((return_code = page_insert(env->env_pgdir, page, va, perm)) < 0) {
 | 
			
		||||
		page_free(page);
 | 
			
		||||
		return return_code;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Map the page of memory at 'srcva' in srcenvid's address space
 | 
			
		||||
@ -176,9 +212,24 @@ sys_page_map(envid_t srcenvid, void *srcva,
 | 
			
		||||
	//   parameters for correctness.
 | 
			
		||||
	//   Use the third argument to page_lookup() to
 | 
			
		||||
	//   check the current permissions on the page.
 | 
			
		||||
	struct Env *srcenv, *dstenv;
 | 
			
		||||
	pte_t* srcpte;
 | 
			
		||||
	int return_code;
 | 
			
		||||
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	panic("sys_page_map not implemented");
 | 
			
		||||
	if((return_code = envid2env(srcenvid, &srcenv, 1)) < 0) return return_code;
 | 
			
		||||
	if((return_code = envid2env(dstenvid, &dstenv, 1)) < 0) return return_code;
 | 
			
		||||
 | 
			
		||||
	if(!SYS_CHECKADDR(srcva)) return -E_INVAL;
 | 
			
		||||
	if(!SYS_CHECKADDR(dstva)) return -E_INVAL;
 | 
			
		||||
	if(!SYS_CHECKPERMS(perm)) return -E_INVAL;
 | 
			
		||||
 | 
			
		||||
	struct PageInfo* page = page_lookup(srcenv->env_pgdir, srcva, &srcpte);
 | 
			
		||||
	if(page == NULL) return -E_INVAL;
 | 
			
		||||
	if(perm & PTE_W && !(*srcpte & PTE_W)) return -E_INVAL;
 | 
			
		||||
 | 
			
		||||
	if((return_code = page_insert(dstenv->env_pgdir, page, dstva, perm)) < 0)
 | 
			
		||||
		return return_code;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Unmap the page of memory at 'va' in the address space of 'envid'.
 | 
			
		||||
@ -192,9 +243,14 @@ static int
 | 
			
		||||
sys_page_unmap(envid_t envid, void *va)
 | 
			
		||||
{
 | 
			
		||||
	// Hint: This function is a wrapper around page_remove().
 | 
			
		||||
	struct Env* env;
 | 
			
		||||
	int return_code;
 | 
			
		||||
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	panic("sys_page_unmap not implemented");
 | 
			
		||||
	if((return_code = envid2env(envid, &env, 1)) < 0) return return_code;
 | 
			
		||||
	if(!SYS_CHECKADDR(va)) return -E_INVAL;
 | 
			
		||||
 | 
			
		||||
	page_remove(env->env_pgdir, va);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Try to send 'value' to the target env 'envid'.
 | 
			
		||||
@ -279,6 +335,21 @@ syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
 | 
			
		||||
		return sys_getenvid();
 | 
			
		||||
	case SYS_env_destroy:
 | 
			
		||||
		return sys_env_destroy(a1);
 | 
			
		||||
	case SYS_yield:
 | 
			
		||||
		sys_yield();
 | 
			
		||||
		return 0;
 | 
			
		||||
	case SYS_exofork:
 | 
			
		||||
		return sys_exofork();
 | 
			
		||||
	case SYS_env_set_status:
 | 
			
		||||
		return sys_env_set_status(a1, a2);
 | 
			
		||||
	case SYS_env_set_pgfault_upcall:
 | 
			
		||||
		return sys_env_set_pgfault_upcall(a1, (void*) a2);
 | 
			
		||||
	case SYS_page_alloc:
 | 
			
		||||
		return sys_page_alloc(a1, (void*) a2, a3);
 | 
			
		||||
	case SYS_page_map:
 | 
			
		||||
		return sys_page_map(a1, (void*) a2, a3, (void*) a4, a5);
 | 
			
		||||
	case SYS_page_unmap:
 | 
			
		||||
		return sys_page_unmap(a1, (void*) a2);
 | 
			
		||||
	default:
 | 
			
		||||
		return -E_INVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										43
									
								
								kern/trap.c
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								kern/trap.c
									
									
									
									
									
								
							@ -160,18 +160,18 @@ trap_init_percpu(void)
 | 
			
		||||
 | 
			
		||||
	// Setup a TSS so that we get the right stack
 | 
			
		||||
	// when we trap to the kernel.
 | 
			
		||||
	ts.ts_esp0 = KSTACKTOP;
 | 
			
		||||
	ts.ts_ss0 = GD_KD;
 | 
			
		||||
	ts.ts_iomb = sizeof(struct Taskstate);
 | 
			
		||||
	thiscpu->cpu_ts.ts_esp0 = KSTACKTOP - thiscpu->cpu_id * (KSTKSIZE + KSTKGAP);
 | 
			
		||||
	thiscpu->cpu_ts.ts_ss0 = GD_KD;
 | 
			
		||||
	thiscpu->cpu_ts.ts_iomb = sizeof(struct Taskstate);
 | 
			
		||||
 | 
			
		||||
	// Initialize the TSS slot of the gdt.
 | 
			
		||||
	gdt[GD_TSS0 >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
 | 
			
		||||
	gdt[(GD_TSS0 >> 3) + cpunum()] = SEG16(STS_T32A, (uint32_t) (&thiscpu->cpu_ts),
 | 
			
		||||
					sizeof(struct Taskstate) - 1, 0);
 | 
			
		||||
	gdt[GD_TSS0 >> 3].sd_s = 0;
 | 
			
		||||
	gdt[(GD_TSS0 >> 3) + cpunum()].sd_s = 0;
 | 
			
		||||
 | 
			
		||||
	// Load the TSS selector (like other segment selectors, the
 | 
			
		||||
	// bottom three bits are special; we leave them 0)
 | 
			
		||||
	ltr(GD_TSS0);
 | 
			
		||||
	ltr(GD_TSS0 + (cpunum() << 3));
 | 
			
		||||
 | 
			
		||||
	// Load the IDT
 | 
			
		||||
	lidt(&idt_pd);
 | 
			
		||||
@ -294,6 +294,7 @@ trap(struct Trapframe *tf)
 | 
			
		||||
		// Acquire the big kernel lock before doing any
 | 
			
		||||
		// serious kernel work.
 | 
			
		||||
		// LAB 4: Your code here.
 | 
			
		||||
		lock_kernel();
 | 
			
		||||
		assert(curenv);
 | 
			
		||||
 | 
			
		||||
		// Garbage collect if current enviroment is a zombie
 | 
			
		||||
@ -373,11 +374,39 @@ page_fault_handler(struct Trapframe *tf)
 | 
			
		||||
	//   (the 'tf' variable points at 'curenv->env_tf').
 | 
			
		||||
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
 | 
			
		||||
	if(!curenv->env_pgfault_upcall) {
 | 
			
		||||
		// Destroy the environment that caused the fault.
 | 
			
		||||
		cprintf("[%08x] user fault va %08x ip %08x\n",
 | 
			
		||||
				curenv->env_id, fault_va, tf->tf_eip);
 | 
			
		||||
		print_trapframe(tf);
 | 
			
		||||
		env_destroy(curenv);
 | 
			
		||||
	}
 | 
			
		||||
	user_mem_assert(curenv, curenv->env_pgfault_upcall, 1, PTE_U | PTE_P);
 | 
			
		||||
	user_mem_assert(curenv, (void*) UXSTACKTOP - 1, 1, PTE_U | PTE_P | PTE_W);
 | 
			
		||||
 | 
			
		||||
	uintptr_t top_addr = UXSTACKTOP;
 | 
			
		||||
	if(tf->tf_esp <= UXSTACKTOP && tf->tf_esp >= (UXSTACKTOP - PGSIZE)) {
 | 
			
		||||
		top_addr = tf->tf_esp - 4;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	struct UTrapframe utf;
 | 
			
		||||
	utf.utf_eflags = tf->tf_eflags;
 | 
			
		||||
	utf.utf_eip = tf->tf_eip;
 | 
			
		||||
	utf.utf_err = tf->tf_err;
 | 
			
		||||
	utf.utf_esp = tf->tf_esp;
 | 
			
		||||
	utf.utf_fault_va = fault_va;
 | 
			
		||||
	utf.utf_regs = tf->tf_regs;
 | 
			
		||||
 | 
			
		||||
	struct UTrapframe* push_to = (struct UTrapframe*) top_addr - 1;
 | 
			
		||||
	if((uintptr_t) push_to < USTACKTOP - PGSIZE) {
 | 
			
		||||
		cprintf("[%08x] stack overflow in page fault handler\n",
 | 
			
		||||
				curenv->env_id);
 | 
			
		||||
		env_destroy(curenv);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*push_to = utf;
 | 
			
		||||
	curenv->env_tf.tf_eip = (uintptr_t) curenv->env_pgfault_upcall;
 | 
			
		||||
	curenv->env_tf.tf_esp = (uintptr_t) push_to;
 | 
			
		||||
	env_run(curenv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										75
									
								
								lib/fork.c
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								lib/fork.c
									
									
									
									
									
								
							@ -23,18 +23,22 @@ pgfault(struct UTrapframe *utf)
 | 
			
		||||
	// Hint:
 | 
			
		||||
	//   Use the read-only page table mappings at uvpt
 | 
			
		||||
	//   (see <inc/memlayout.h>).
 | 
			
		||||
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	if(!((err & FEC_WR) && (uvpt[(uintptr_t) addr >> PGSHIFT] & PTE_COW)))
 | 
			
		||||
		panic("page fault (addr %p)! %c", addr, (err & FEC_WR) ? 'w' : 'r');
 | 
			
		||||
 | 
			
		||||
	// 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.
 | 
			
		||||
	void* temp_addr = (void*) PFTEMP;
 | 
			
		||||
	void* fault_addr = ROUNDDOWN(addr, PGSIZE);
 | 
			
		||||
	if(sys_page_alloc(0, temp_addr, PTE_P | PTE_W | PTE_U) < 0)
 | 
			
		||||
		panic("failed to allocate new page");
 | 
			
		||||
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
 | 
			
		||||
	panic("pgfault not implemented");
 | 
			
		||||
	memcpy(temp_addr, fault_addr, PGSIZE);
 | 
			
		||||
	sys_page_map(0, temp_addr, 0, fault_addr, PTE_P | PTE_U | PTE_W);
 | 
			
		||||
	sys_page_unmap(0, temp_addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
@ -52,9 +56,27 @@ static int
 | 
			
		||||
duppage(envid_t envid, unsigned pn)
 | 
			
		||||
{
 | 
			
		||||
	int r;
 | 
			
		||||
	bool change_own = false;
 | 
			
		||||
	pte_t new_pte = uvpt[pn];
 | 
			
		||||
	pte_t perms = new_pte & (PTE_P | PTE_U | PTE_W | PTE_AVAIL);
 | 
			
		||||
	void* addr = (void*) (pn * PGSIZE);
 | 
			
		||||
 | 
			
		||||
	// If we're writable, remove write permission
 | 
			
		||||
	if((new_pte & PTE_W) || (new_pte & PTE_COW)) {
 | 
			
		||||
		perms = (perms & ~PTE_W) | PTE_COW;
 | 
			
		||||
		change_own = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Map either with the same permissions or with COW.
 | 
			
		||||
	if((r = sys_page_map(0, addr, envid, addr, perms)) < 0)
 | 
			
		||||
		return r;
 | 
			
		||||
 | 
			
		||||
	// Update our own permissions if necessary
 | 
			
		||||
	if(change_own) {
 | 
			
		||||
		if((r = sys_page_map(0, addr, 0, addr, perms)) < 0)
 | 
			
		||||
			return r;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	panic("duppage not implemented");
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -77,8 +99,43 @@ duppage(envid_t envid, unsigned pn)
 | 
			
		||||
envid_t
 | 
			
		||||
fork(void)
 | 
			
		||||
{
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	panic("fork not implemented");
 | 
			
		||||
	set_pgfault_handler(pgfault);
 | 
			
		||||
 | 
			
		||||
	int return_code;
 | 
			
		||||
	envid_t forked;
 | 
			
		||||
 | 
			
		||||
	forked = sys_exofork();
 | 
			
		||||
	if(forked < 0) return forked;
 | 
			
		||||
	if(forked == 0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; }
 | 
			
		||||
 | 
			
		||||
	// Map all accessible page directory entries
 | 
			
		||||
	for(int pde_i = 0; pde_i < PDX(UTOP); pde_i++) {
 | 
			
		||||
		pde_t pde = uvpd[pde_i];
 | 
			
		||||
		if(!(pde & PTE_P)) continue;
 | 
			
		||||
 | 
			
		||||
		// For each PDE, map all the underlying PTEs
 | 
			
		||||
		for(int pte_i = 0; pte_i < NPTENTRIES; pte_i++) {
 | 
			
		||||
			int pn = pde_i * NPTENTRIES + pte_i;
 | 
			
		||||
			pte_t pte = uvpt[pn];
 | 
			
		||||
			if(!(pte & PTE_P)) continue;
 | 
			
		||||
 | 
			
		||||
			// Do not map user exception stack, though
 | 
			
		||||
			if(pn == ((UXSTACKTOP - PGSIZE) >> PGSHIFT)) continue;
 | 
			
		||||
 | 
			
		||||
			if((return_code = duppage(forked, pn)) < 0) return return_code;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Allocate new page for the exception stack
 | 
			
		||||
	return_code = sys_page_alloc(forked, (void*) UXSTACKTOP - PGSIZE,
 | 
			
		||||
			PTE_P | PTE_U | PTE_W);
 | 
			
		||||
	if(return_code < 0) return return_code;
 | 
			
		||||
 | 
			
		||||
	// Set the upcall entry point
 | 
			
		||||
	sys_env_set_pgfault_upcall(forked, thisenv->env_pgfault_upcall);
 | 
			
		||||
	sys_env_set_status(forked, ENV_RUNNABLE);
 | 
			
		||||
 | 
			
		||||
	return forked;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Challenge!
 | 
			
		||||
 | 
			
		||||
@ -65,18 +65,29 @@ _pgfault_upcall:
 | 
			
		||||
	// ways as registers become unavailable as scratch space.
 | 
			
		||||
	//
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	mov 40(%esp), %eax // Take the EIP from memory
 | 
			
		||||
	mov 48(%esp), %ebp // Take the ESP from memory
 | 
			
		||||
	sub $4, %ebp // Push onto trap-time ESP
 | 
			
		||||
	mov %eax, (%ebp)
 | 
			
		||||
	mov %ebp, 48(%esp) // Put ESP back
 | 
			
		||||
 | 
			
		||||
	// Restore the trap-time registers.  After you do this, you
 | 
			
		||||
	// can no longer modify any general-purpose registers.
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	add $0x8, %esp
 | 
			
		||||
	popal
 | 
			
		||||
 | 
			
		||||
	// Restore eflags from the stack.  After you do this, you can
 | 
			
		||||
	// no longer use arithmetic operations or anything else that
 | 
			
		||||
	// modifies eflags.
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	add $0x4, %esp
 | 
			
		||||
	popfl
 | 
			
		||||
 | 
			
		||||
	// Switch back to the adjusted trap-time stack.
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	pop %esp
 | 
			
		||||
 | 
			
		||||
	// Return to re-execute the instruction that faulted.
 | 
			
		||||
	// LAB 4: Your code here.
 | 
			
		||||
	ret
 | 
			
		||||
 | 
			
		||||
@ -27,9 +27,9 @@ set_pgfault_handler(void (*handler)(struct UTrapframe *utf))
 | 
			
		||||
	int r;
 | 
			
		||||
 | 
			
		||||
	if (_pgfault_handler == 0) {
 | 
			
		||||
		// First time through!
 | 
			
		||||
		// LAB 4: Your code here.
 | 
			
		||||
		panic("set_pgfault_handler not implemented");
 | 
			
		||||
		if(sys_page_alloc(0, (void*) UXSTACKTOP - PGSIZE, PTE_U | PTE_P | PTE_W) < 0)
 | 
			
		||||
			panic("set_pgfault_handler");
 | 
			
		||||
		sys_env_set_pgfault_upcall(0, _pgfault_upcall);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Save handler pointer for assembly to call.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user