diff --git a/kern/env.c b/kern/env.c index df3a9cd..661b8dd 100644 --- a/kern/env.c +++ b/kern/env.c @@ -255,6 +255,7 @@ env_alloc(struct Env **newenv_store, envid_t parent_id) // Enable interrupts while in user mode. // LAB 4: Your code here. + e->env_tf.tf_eflags |= FL_IF; // Clear the page fault handler until user installs one. e->env_pgfault_upcall = 0; diff --git a/kern/sched.c b/kern/sched.c index cba0cac..3062cdc 100644 --- a/kern/sched.c +++ b/kern/sched.c @@ -93,7 +93,7 @@ sched_halt(void) "pushl $0\n" // LAB 4: // Uncomment the following line after completing exercise 13 - //"sti\n" + "sti\n" "1:\n" "hlt\n" "jmp 1b\n" diff --git a/kern/syscall.c b/kern/syscall.c index ca3a35c..269c9f1 100644 --- a/kern/syscall.c +++ b/kern/syscall.c @@ -294,8 +294,38 @@ sys_page_unmap(envid_t envid, void *va) static int sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm) { - // LAB 4: Your code here. - panic("sys_ipc_try_send not implemented"); + struct Env* dest_env; + struct Env* src_env; + int return_code; + + if((return_code = envid2env(0, &src_env, 0)) < 0) + return return_code; + if((return_code = envid2env(envid, &dest_env, 0)) < 0) + return return_code; + + if(!dest_env->env_ipc_recving) + return -E_IPC_NOT_RECV; + + if((uintptr_t) srcva < UTOP && dest_env->env_ipc_dstva) { + if(!SYS_CHECKADDR(srcva)) return -E_INVAL; + if(!SYS_CHECKPERMS(perm)) return -E_INVAL; + + pte_t* srcpte; + struct PageInfo* page = page_lookup(src_env->env_pgdir, srcva, &srcpte); + if(page == NULL) return -E_INVAL; + if(perm & PTE_W && !(*srcpte & PTE_W)) return -E_INVAL; + + page_insert(dest_env->env_pgdir, page, dest_env->env_ipc_dstva, perm); + dest_env->env_ipc_perm = perm; + } + + dest_env->env_ipc_from = src_env->env_id; + dest_env->env_ipc_value = value; + dest_env->env_ipc_recving = false; + if(dest_env->env_status == ENV_NOT_RUNNABLE) + dest_env->env_status = ENV_RUNNABLE; + + return 0; } // Block until a value is ready. Record that you want to receive @@ -312,8 +342,20 @@ sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, unsigned perm) static int sys_ipc_recv(void *dstva) { + struct Env* env; + int return_code; + + if((return_code = envid2env(0, &env, 1)) < 0) + return return_code; + // LAB 4: Your code here. - panic("sys_ipc_recv not implemented"); + if((uintptr_t) dstva < UTOP) { + if(!SYS_CHECKADDR(dstva)) return -E_INVAL; + env->env_ipc_dstva = dstva; + } + env->env_ipc_recving = true; + env->env_status = ENV_NOT_RUNNABLE; + return 0; } @@ -350,6 +392,10 @@ syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, return sys_page_map(a1, (void*) a2, a3, (void*) a4, a5); case SYS_page_unmap: return sys_page_unmap(a1, (void*) a2); + case SYS_ipc_try_send: + return sys_ipc_try_send(a1, a2, (void*) a3, a4); + case SYS_ipc_recv: + return sys_ipc_recv((void*) a1); default: return -E_INVAL; } diff --git a/kern/trap.c b/kern/trap.c index 6cf1d88..478149d 100644 --- a/kern/trap.c +++ b/kern/trap.c @@ -89,6 +89,13 @@ void t_simderr(); void t_syscall(); void t_default(); +void irq_timer(); +void irq_kbd(); +void irq_serial(); +void irq_spurious(); +void irq_ide(); +void irq_error(); + void trap_init(void) { @@ -125,6 +132,13 @@ trap_init(void) SETGATE(idt[T_SYSCALL], 0, GD_KT, t_syscall, 3); SETGATE(idt[T_DEFAULT], 0, GD_KT, t_default, 0); + SETGATE(idt[IRQ_OFFSET + IRQ_TIMER], 0, GD_KT, irq_timer, 0); + SETGATE(idt[IRQ_OFFSET + IRQ_KBD], 0, GD_KT, irq_kbd, 0); + SETGATE(idt[IRQ_OFFSET + IRQ_SERIAL], 0, GD_KT, irq_serial, 0); + SETGATE(idt[IRQ_OFFSET + IRQ_SPURIOUS], 0, GD_KT, irq_spurious, 0); + SETGATE(idt[IRQ_OFFSET + IRQ_IDE], 0, GD_KT, irq_ide, 0); + SETGATE(idt[IRQ_OFFSET + IRQ_ERROR], 0, GD_KT, irq_error, 0); + // Per-CPU setup trap_init_percpu(); } @@ -243,6 +257,9 @@ trap_dispatch(struct Trapframe *tf) tf->tf_regs.reg_esi); tf->tf_regs.reg_eax = returned; return; + } else if (tf->tf_trapno == IRQ_OFFSET + IRQ_TIMER) { + lapic_eoi(); + sched_yield(); } // Handle spurious interrupts diff --git a/kern/trapentry.S b/kern/trapentry.S index fb2a3c7..180061a 100644 --- a/kern/trapentry.S +++ b/kern/trapentry.S @@ -82,6 +82,12 @@ TRAPHANDLER_NOEC(t_mchk, T_MCHK); TRAPHANDLER_NOEC(t_simderr, T_SIMDERR); TRAPHANDLER_NOEC(t_syscall, T_SYSCALL); TRAPHANDLER(t_default, T_DEFAULT); +TRAPHANDLER_NOEC(irq_timer, IRQ_OFFSET + IRQ_TIMER); +TRAPHANDLER_NOEC(irq_kbd, IRQ_OFFSET + IRQ_KBD); +TRAPHANDLER_NOEC(irq_serial, IRQ_OFFSET + IRQ_SERIAL); +TRAPHANDLER_NOEC(irq_spurious, IRQ_OFFSET + IRQ_SPURIOUS); +TRAPHANDLER_NOEC(irq_ide, IRQ_OFFSET + IRQ_IDE); +TRAPHANDLER_NOEC(irq_error, IRQ_OFFSET + IRQ_ERROR); // HINT 1 : TRAPHANDLER_NOEC(t_divide, T_DIVIDE); // Do something like this if there is no error code for the trap diff --git a/lib/ipc.c b/lib/ipc.c index 2e222b9..fba6247 100644 --- a/lib/ipc.c +++ b/lib/ipc.c @@ -22,9 +22,14 @@ int32_t ipc_recv(envid_t *from_env_store, void *pg, int *perm_store) { - // LAB 4: Your code here. - panic("ipc_recv not implemented"); - return 0; + int return_code; + if((return_code = sys_ipc_recv(pg ? pg : (void*) ~0)) < 0) + return return_code; + + if(from_env_store) *from_env_store = thisenv->env_ipc_from; + if(perm_store) *perm_store = thisenv->env_ipc_perm; + + return thisenv->env_ipc_value; } // Send 'val' (and 'pg' with 'perm', if 'pg' is nonnull) to 'toenv'. @@ -38,8 +43,12 @@ ipc_recv(envid_t *from_env_store, void *pg, int *perm_store) void ipc_send(envid_t to_env, uint32_t val, void *pg, int perm) { - // LAB 4: Your code here. - panic("ipc_send not implemented"); + int return_code = -E_IPC_NOT_RECV; + while(return_code == -E_IPC_NOT_RECV) { + return_code = sys_ipc_try_send(to_env, val, pg ? pg : (void*) ~0, perm); + sys_yield(); + } + if(return_code != 0) panic("failed to send\n"); } // Find the first environment of the given type. We'll use this to