Implement parts A and B.
This commit is contained in:
@@ -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;
|
||||
|
||||
error_code = env_alloc(&new_env, curenv->env_id);
|
||||
if(error_code < 0) return error_code;
|
||||
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_exofork not implemented");
|
||||
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;
|
||||
|
||||
if(!SYS_CHECKPERMS(perm)) return -E_INVAL;
|
||||
if(!SYS_CHECKADDR(va)) return -E_INVAL;
|
||||
|
||||
// LAB 4: Your code here.
|
||||
panic("sys_page_alloc not implemented");
|
||||
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;
|
||||
}
|
||||
|
||||
51
kern/trap.c
51
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);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user