diff --git a/src/components/implementation/no_interface/llbooter/Makefile b/src/components/implementation/no_interface/llbooter/Makefile index 6c7b3686ae..041a1ee3e3 100644 --- a/src/components/implementation/no_interface/llbooter/Makefile +++ b/src/components/implementation/no_interface/llbooter/Makefile @@ -1,7 +1,7 @@ COMPONENT=llbooter.o ASM_OBJS=s_stub.o COMPONENT=llboot_comp.o -INTERFACES= +INTERFACES=fault_handler DEPENDENCIES= IF_LIB= ADDITIONAL_LIBS=-lcobj_format -lcos_kernel_api -lcos_defkernel_api diff --git a/src/components/implementation/no_interface/llbooter/boot_deps.h b/src/components/implementation/no_interface/llbooter/boot_deps.h index e1140221e9..483f3dcd0c 100644 --- a/src/components/implementation/no_interface/llbooter/boot_deps.h +++ b/src/components/implementation/no_interface/llbooter/boot_deps.h @@ -9,10 +9,20 @@ #include #include #include +#include /* Assembly function for sinv from new component */ extern word_t hypercall_entry_rets_inv(spdid_t cur, int op, word_t arg1, word_t arg2, word_t arg3, word_t *ret2, word_t *ret3); +/* Assembly function for sinv for the fault handlers */ +extern word_t fault_div_by_zero_inv(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +extern word_t fault_memory_access_inv(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +extern word_t fault_breakpoint_inv(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +extern word_t fault_invalid_inst_inv(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +extern word_t fault_invstk_inv(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +extern word_t fault_comp_not_exist_inv(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +extern word_t fault_handler_not_exist_inv(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); + extern int num_cobj; extern spdid_t capmgr_spdid; extern spdid_t root_spdid[]; @@ -114,6 +124,96 @@ boot_spd_initaep_get(spdid_t spdid) return cos_sched_aep_get(boot_spd_defcompinfo_get(spdid)); } +void +fault_reg_print(spdid_t spdid) +{ + struct pt_regs fault_regs; + + struct cos_aep_info *child_aep = boot_spd_initaep_get(spdid); + struct cos_compinfo *boot_info = boot_spd_compinfo_curr_get(); + + /* + * TODO: make it more portable by making the register an int that goes through a loop + * which is bounded by architecture-specific variables. + */ + fault_regs.ax = cos_introspect(boot_info, child_aep->thd, THD_GET_FAULT_REG0); + fault_regs.bx = cos_introspect(boot_info, child_aep->thd, THD_GET_FAULT_REG1); + fault_regs.cx = cos_introspect(boot_info, child_aep->thd, THD_GET_FAULT_REG2); + fault_regs.dx = cos_introspect(boot_info, child_aep->thd, THD_GET_FAULT_REG3); + fault_regs.si = cos_introspect(boot_info, child_aep->thd, THD_GET_FAULT_REG10); + fault_regs.di = cos_introspect(boot_info, child_aep->thd, THD_GET_FAULT_REG11); + fault_regs.ip = cos_introspect(boot_info, child_aep->thd, THD_GET_FAULT_REG12); + fault_regs.sp = cos_introspect(boot_info, child_aep->thd, THD_GET_FAULT_REG13); + fault_regs.bp = cos_introspect(boot_info, child_aep->thd, THD_GET_FAULT_REG14); + fault_regs.flags = cos_introspect(boot_info, child_aep->thd, THD_GET_FAULT_REG15); + + printc("registers:\n"); + printc("General registers-> EAX: %x, EBX: %x, ECX: %x, EDX: %x, SI: %x, DI: %x\n", (unsigned int)fault_regs.ax, + (unsigned int)fault_regs.bx, (unsigned int)fault_regs.cx, (unsigned int)fault_regs.dx, (unsigned int)fault_regs.si, + (unsigned int)fault_regs.di); + printc("Index registers-> IP: %x, SP: %x, BP: %x\n", (unsigned int)fault_regs.ip, (unsigned int)fault_regs.sp, + (unsigned int)fault_regs.bp); + printc("Indicator->EFLAGS: %x\n", (unsigned int)fault_regs.flags); +} + +/* The fault handlers*/ +void +fault_div_by_zero(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type) +{ + PRINTLOG(PRINT_ERROR, "in div by zero error fault handler, fault happens in component:%u\n\n", (unsigned int)cos_inv_token()); + fault_reg_print(cos_inv_token()); + return; +} + +void +fault_memory_access(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type) +{ + PRINTLOG(PRINT_ERROR, "in memory access handler, fault happens in component:%u\n\n", (unsigned int)cos_inv_token()); + fault_reg_print(cos_inv_token()); + return; +} + +void +fault_breakpoint(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type) +{ + PRINTLOG(PRINT_ERROR, "in breakpoint trap handler, fault happens in component:%u\n\n", (unsigned int)cos_inv_token()); + fault_reg_print(cos_inv_token()); + return; +} + +void +fault_invalid_inst(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type) +{ + PRINTLOG(PRINT_ERROR, "in invalid instruction trap handler, fault happens in component:%u\n\n", (unsigned int)cos_inv_token()); + fault_reg_print(cos_inv_token()); + return; +} + +/* TODO: needs to separate overflow and underflow into two fault handlers. */ +void +fault_invstk(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type) +{ + PRINTLOG(PRINT_ERROR, "in invstk overflow and underflow fault handler, fault happens in component:%u\n\n", (unsigned int)cos_inv_token()); + fault_reg_print(cos_inv_token()); + return; +} + +void +fault_comp_not_exist(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type) +{ + PRINTLOG(PRINT_ERROR, "in component does not exist fault handler, fault happens in component:%u\n\n", (unsigned int)cos_inv_token()); + fault_reg_print(cos_inv_token()); + return; +} + +void +fault_handler_not_exist(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type) +{ + PRINTLOG(PRINT_ERROR, "in fault handler does not exist fault handler, fault happens in component:%u\n\n", (unsigned int)cos_inv_token()); + fault_reg_print(cos_inv_token()); + return; +} + static vaddr_t boot_deps_map_sect(spdid_t spdid, vaddr_t *mapaddr) { @@ -144,6 +244,35 @@ boot_capmgr_mem_alloc(void) cos_meminfo_alloc(capmgr_info, BOOT_MEM_KM_BASE, mem_sz); } +static void +boot_fault_handler_sinv_alloc(spdid_t spdid) +{ + invtoken_t token = (invtoken_t)spdid; + int ret; + + struct cos_compinfo *comp_info = boot_spd_compinfo_get(spdid); + struct cos_compinfo *boot_info = boot_spd_compinfo_curr_get(); + + /* + * All sinv caps created here are CAP_FLT, + * a different capability type to avoid an extra branch in fast-path. + */ + ret = cos_fault_sinv_alloc_at(comp_info, COMP_CAPTBL_FLT_DIVZERO, boot_info->comp_cap, (vaddr_t)fault_div_by_zero_inv, token); + assert(ret == 0); + ret = cos_fault_sinv_alloc_at(comp_info, COMP_CAPTBL_FLT_MEM_ACCESS, boot_info->comp_cap, (vaddr_t)fault_memory_access_inv, token); + assert(ret == 0); + ret = cos_fault_sinv_alloc_at(comp_info, COMP_CAPTBL_FLT_BRKPT, boot_info->comp_cap, (vaddr_t)fault_breakpoint_inv, token); + assert(ret == 0); + ret = cos_fault_sinv_alloc_at(comp_info, COMP_CAPTBL_FLT_INVLD_INS, boot_info->comp_cap, (vaddr_t)fault_invalid_inst_inv, token); + assert(ret == 0); + ret = cos_fault_sinv_alloc_at(comp_info, COMP_CAPTBL_FLT_INVSTK, boot_info->comp_cap, (vaddr_t)fault_invstk_inv, token); + assert(ret == 0); + ret = cos_fault_sinv_alloc_at(comp_info, COMP_CAPTBL_FLT_COMP_NOT_EXIST, boot_info->comp_cap, (vaddr_t)fault_comp_not_exist_inv, token); + assert(ret == 0); + ret = cos_fault_sinv_alloc_at(comp_info, COMP_CAPTBL_FLT_HAND_NOT_EXIST, boot_info->comp_cap, (vaddr_t)fault_handler_not_exist_inv, token); + assert(ret == 0); +} + void boot_comp_mem_alloc(spdid_t spdid) { diff --git a/src/components/implementation/no_interface/llbooter/llbooter.c b/src/components/implementation/no_interface/llbooter/llbooter.c index e60d732370..88a099ee82 100644 --- a/src/components/implementation/no_interface/llbooter/llbooter.c +++ b/src/components/implementation/no_interface/llbooter/llbooter.c @@ -364,6 +364,7 @@ boot_create_cap_system(void) if (boot_comp_map(h, spdid, ci)) BUG(); boot_newcomp_create(spdid, boot_spd_compinfo_get(spdid)); + boot_fault_handler_sinv_alloc(spdid); PRINTLOG(PRINT_DEBUG, "Comp %d (%s) created @ %x!\n", h->id, h->name, sect->vaddr); } diff --git a/src/components/include/cos_kernel_api.h b/src/components/include/cos_kernel_api.h index 911f025e01..bfd5d790fc 100644 --- a/src/components/include/cos_kernel_api.h +++ b/src/components/include/cos_kernel_api.h @@ -119,6 +119,7 @@ thdcap_t cos_thd_alloc_ext(struct cos_compinfo *ci, compcap_t comp, thdclosure_i /* Create the initial (cos_init) thread */ thdcap_t cos_initthd_alloc(struct cos_compinfo *ci, compcap_t comp); sinvcap_t cos_sinv_alloc(struct cos_compinfo *srcci, compcap_t dstcomp, vaddr_t entry, invtoken_t token); +int cos_fault_sinv_alloc_at(struct cos_compinfo *srcci, capid_t cap, compcap_t dstcomp, vaddr_t entry, invtoken_t token); arcvcap_t cos_arcv_alloc(struct cos_compinfo *ci, thdcap_t thdcap, tcap_t tcapcap, compcap_t compcap, arcvcap_t enotif); asndcap_t cos_asnd_alloc(struct cos_compinfo *ci, arcvcap_t arcvcap, captblcap_t ctcap); diff --git a/src/components/interface/fault_handler/Makefile b/src/components/interface/fault_handler/Makefile new file mode 100644 index 0000000000..f49881efcc --- /dev/null +++ b/src/components/interface/fault_handler/Makefile @@ -0,0 +1,5 @@ +LIB_OBJS= +LIBS=$(LIB_OBJS:%.o=%.a) + +include ../Makefile.subdir + diff --git a/src/components/interface/fault_handler/fault_handler.h b/src/components/interface/fault_handler/fault_handler.h new file mode 100644 index 0000000000..e335daa5fa --- /dev/null +++ b/src/components/interface/fault_handler/fault_handler.h @@ -0,0 +1,12 @@ +#ifndef FAULT_HANDLER_H +#define FAULT_HANDLER_H + +void fault_div_by_zero(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +void fault_memory_access(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +void fault_breakpoint(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +void fault_invalid_inst(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +void fault_invstk(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +void fault_comp_not_exist(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); +void fault_handler_not_exist(unsigned long sp, unsigned long ip, unsigned long fault_addr, unsigned long fault_type); + +#endif /* FAULT_HANDLER_H */ diff --git a/src/components/interface/fault_handler/stubs/s_stub.S b/src/components/interface/fault_handler/stubs/s_stub.S new file mode 100644 index 0000000000..a3ab4fc8bb --- /dev/null +++ b/src/components/interface/fault_handler/stubs/s_stub.S @@ -0,0 +1,11 @@ +#include + +.text + +cos_asm_server_stub(fault_div_by_zero) +cos_asm_server_stub(fault_breakpoint) +cos_asm_server_stub(fault_memory_access) +cos_asm_server_stub(fault_invalid_inst) +cos_asm_server_stub(fault_comp_not_exist) +cos_asm_server_stub(fault_invstk) +cos_asm_server_stub(fault_handler_not_exist) diff --git a/src/components/lib/cos_kernel_api.c b/src/components/lib/cos_kernel_api.c index 54e5afc647..5c7223f8d1 100644 --- a/src/components/lib/cos_kernel_api.c +++ b/src/components/lib/cos_kernel_api.c @@ -711,6 +711,19 @@ cos_sinv_alloc(struct cos_compinfo *srcci, compcap_t dstcomp, vaddr_t entry, inv return cap; } +int +cos_fault_sinv_alloc_at(struct cos_compinfo *srcci, capid_t cap, compcap_t dstcomp, vaddr_t entry, invtoken_t token) +{ + printd("cos_fault_sinv_alloc_at\n"); + + assert(srcci && dstcomp); + + if (!cap) return 0; + if (call_cap_op(srcci->captbl_cap, CAPTBL_OP_FAULTACTIVATE, cap, dstcomp, entry, token)) BUG(); + + return 0; +} + int cos_sinv(sinvcap_t sinv, word_t arg1, word_t arg2, word_t arg3, word_t arg4) { diff --git a/src/kernel/capinv.c b/src/kernel/capinv.c index 0a294301fb..23152f7f4c 100644 --- a/src/kernel/capinv.c +++ b/src/kernel/capinv.c @@ -406,7 +406,8 @@ cap_thd_switch(struct pt_regs *regs, struct thread *curr, struct thread *next, s struct cos_cpu_local_info *cos_info) { struct next_thdinfo *nti = &cos_info->next_ti; - struct comp_info * next_ci = &(next->invstk[next->invstk_top].comp_info); + /* invstk_top never contains in_fault flag in its captbl. So we can use it as comp_info */ + struct comp_info * next_ci = (struct comp_info *)&(next->invstk[next->invstk_top].comp_invstk_info); int preempt = 0; assert(next_ci && curr && next); @@ -685,7 +686,7 @@ cap_ipi_process(struct pt_regs *regs) thd_curr = thd_next = thd_current(cos_info); receiver_rings = &IPI_cap_dest[get_cpuid()]; tcap_curr = tcap_next = tcap_current(cos_info); - ci = thd_invstk_current(thd_curr, &ip, &sp, cos_info); + ci = thd_invstk_current(thd_curr, cos_info, &ip, &sp); assert(ci && ci->captbl); scan_base = receiver_rings->start; @@ -818,7 +819,7 @@ cap_hw_asnd(struct cap_asnd *asnd, struct pt_regs *regs) thd = thd_current(cos_info); tcap = tcap_current(cos_info); assert(thd); - ci = thd_invstk_current(thd, &ip, &sp, cos_info); + ci = thd_invstk_current(thd, cos_info, &ip, &sp); assert(ci && ci->captbl); assert(!(thd->state & THD_STATE_PREEMPTED)); rcv_thd = arcv->thd; @@ -872,7 +873,7 @@ timer_process(struct pt_regs *regs) assert(cos_info); thd_curr = thd_current(cos_info); assert(thd_curr && thd_curr->cpuid == get_cpuid()); - comp = thd_invstk_current(thd_curr, &ip, &sp, cos_info); + comp = thd_invstk_current(thd_curr, cos_info, &ip, &sp); assert(comp); return expended_process(regs, thd_curr, comp, cos_info, 1); @@ -997,8 +998,7 @@ composite_syscall_handler(struct pt_regs *regs) /* fast path: invocation return (avoiding captbl accesses) */ if (cap == COS_DEFAULT_RET_CAP) { /* No need to lookup captbl */ - sret_ret(thd, regs, cos_info); - return 0; + return sret_ret(thd, regs, cos_info); } /* FIXME: use a cap for print */ @@ -1007,7 +1007,7 @@ composite_syscall_handler(struct pt_regs *regs) return 0; } - ci = thd_invstk_current(thd, &ip, &sp, cos_info); + ci = thd_invstk_current(thd, cos_info, &ip, &sp); assert(ci && ci->captbl); /* @@ -1022,7 +1022,7 @@ composite_syscall_handler(struct pt_regs *regs) } /* fastpath: invocation */ if (likely(ch->type == CAP_SINV)) { - sinv_call(thd, (struct cap_sinv *)ch, regs, cos_info); + sinv_call(thd, (struct cap_sinv *)ch, regs, cos_info, 0); return 0; } @@ -1094,7 +1094,7 @@ static int __attribute__((noinline)) composite_syscall_slowpath(struct pt_regs * cap = __userregs_getcap(regs); capin = __userregs_get1(regs); - ci = thd_invstk_current(thd, &ip, &sp, cos_info); + ci = thd_invstk_current(thd, cos_info, &ip, &sp); assert(ci && ci->captbl); ct = ci->captbl; @@ -1294,7 +1294,7 @@ static int __attribute__((noinline)) composite_syscall_slowpath(struct pt_regs * vaddr_t entry_addr = __userregs_get3(regs); invtoken_t token = __userregs_get4(regs); - ret = sinv_activate(ct, cap, capin, dest_comp_cap, entry_addr, token); + ret = sinv_activate(ct, cap, capin, dest_comp_cap, CAP_SINV, entry_addr, token); break; } case CAPTBL_OP_SINVDEACTIVATE: { @@ -1303,6 +1303,14 @@ static int __attribute__((noinline)) composite_syscall_slowpath(struct pt_regs * ret = sinv_deactivate(op_cap, capin, lid); break; } + case CAPTBL_OP_FAULTACTIVATE: { + capid_t dest_comp_cap = __userregs_get2(regs); + vaddr_t entry_addr = __userregs_get3(regs); + invtoken_t token = __userregs_get4(regs); + + ret = sinv_activate(ct, cap, capin, dest_comp_cap, CAP_FLT, entry_addr, token); + break; + } case CAPTBL_OP_SRETACTIVATE: { ret = -EINVAL; break; @@ -1517,8 +1525,7 @@ static int __attribute__((noinline)) composite_syscall_slowpath(struct pt_regs * * We usually don't have sret cap as we have 0 as the * default return cap. */ - sret_ret(thd, regs, cos_info); - return 0; + return sret_ret(thd, regs, cos_info); } case CAP_TCAP: { /* TODO: Validate that all tcaps are on the same core */ diff --git a/src/kernel/include/inv.h b/src/kernel/include/inv.h index 089c784b54..4eda042f1f 100644 --- a/src/kernel/include/inv.h +++ b/src/kernel/include/inv.h @@ -51,7 +51,7 @@ struct cap_arcv { } __attribute__((packed)); static int -sinv_activate(struct captbl *t, capid_t cap, capid_t capin, capid_t comp_cap, vaddr_t entry_addr, invtoken_t token) +sinv_activate(struct captbl *t, capid_t cap, capid_t capin, capid_t comp_cap, cap_t type, vaddr_t entry_addr, invtoken_t token) { struct cap_sinv *sinvc; struct cap_comp *compc; @@ -60,14 +60,14 @@ sinv_activate(struct captbl *t, capid_t cap, capid_t capin, capid_t comp_cap, va compc = (struct cap_comp *)captbl_lkup(t, comp_cap); if (unlikely(!compc || compc->h.type != CAP_COMP)) return -EINVAL; - sinvc = (struct cap_sinv *)__cap_capactivate_pre(t, cap, capin, CAP_SINV, &ret); + sinvc = (struct cap_sinv *)__cap_capactivate_pre(t, cap, capin, type, &ret); if (!sinvc) return ret; sinvc->token = token; memcpy(&sinvc->comp_info, &compc->info, sizeof(struct comp_info)); sinvc->entry_addr = entry_addr; - __cap_capactivate_post(&sinvc->h, CAP_SINV); + __cap_capactivate_post(&sinvc->h, type); return 0; } @@ -286,7 +286,7 @@ arcv_introspect(struct cap_arcv *r, unsigned long op, unsigned long *retval) */ static inline void -sinv_call(struct thread *thd, struct cap_sinv *sinvc, struct pt_regs *regs, struct cos_cpu_local_info *cos_info) +sinv_call(struct thread *thd, struct cap_sinv *sinvc, struct pt_regs *regs, struct cos_cpu_local_info *cos_info, unsigned long in_fault) { unsigned long ip, sp; @@ -306,7 +306,7 @@ sinv_call(struct thread *thd, struct cap_sinv *sinvc, struct pt_regs *regs, stru return; } - if (unlikely(thd_invstk_push(thd, &sinvc->comp_info, ip, sp, cos_info))) { + if (unlikely(thd_invstk_push(thd, &sinvc->comp_info, ip, sp, in_fault, cos_info))) { __userregs_set(regs, -1, sp, ip); return; } @@ -321,28 +321,36 @@ sinv_call(struct thread *thd, struct cap_sinv *sinvc, struct pt_regs *regs, stru return; } -static inline void +static inline int sret_ret(struct thread *thd, struct pt_regs *regs, struct cos_cpu_local_info *cos_info) { - struct comp_info *ci; - unsigned long ip, sp; + struct comp_info * ci; + unsigned long ip = 0; + unsigned long sp = 0; + unsigned long in_fault = 0; - ci = thd_invstk_pop(thd, &ip, &sp, cos_info); + ci = thd_invstk_pop(thd, cos_info, &ip, &sp, &in_fault); if (unlikely(!ci)) { __userregs_set(regs, 0xDEADDEAD, 0, 0); - return; + goto ret; } if (unlikely(!ltbl_isalive(&ci->liveness))) { printk("cos: ret comp (liveness %d) doesn't exist!\n", ci->liveness.id); // FIXME: add fault handling here. __userregs_set(regs, -EFAULT, __userregs_getsp(regs), __userregs_getip(regs)); - return; + goto ret; } pgtbl_update(ci->pgtbl); /* Set return sp and ip and function return value in eax */ __userregs_set(regs, __userregs_getinvret(regs), sp, ip); +ret: + if (unlikely(in_fault)) { + copy_all_regs(&(thd->fault_regs), regs); + return 1; + } + return 0; } static void diff --git a/src/kernel/include/shared/cos_types.h b/src/kernel/include/shared/cos_types.h index f3714097e2..056b5eb5c8 100644 --- a/src/kernel/include/shared/cos_types.h +++ b/src/kernel/include/shared/cos_types.h @@ -88,6 +88,7 @@ typedef enum { CAPTBL_OP_COMPDEACTIVATE, CAPTBL_OP_SINVACTIVATE, CAPTBL_OP_SINVDEACTIVATE, + CAPTBL_OP_FAULTACTIVATE, CAPTBL_OP_SRETACTIVATE, CAPTBL_OP_SRETDEACTIVATE, CAPTBL_OP_ASNDACTIVATE, @@ -130,6 +131,7 @@ typedef enum { typedef enum { CAP_FREE = 0, CAP_SINV, /* synchronous communication -- invoke */ + CAP_FLT, /* communication of fault handler -- invoke*/ CAP_SRET, /* synchronous communication -- return */ CAP_ASND, /* async communication; sender */ CAP_ARCV, /* async communication; receiver */ @@ -203,6 +205,7 @@ __captbl_cap2sz(cap_t c) case CAP_HW: /* TODO: 256bits = 32B * 8b */ return CAP_SZ_32B; case CAP_SINV: + case CAP_FLT: case CAP_COMP: case CAP_ASND: case CAP_ARCV: @@ -222,17 +225,21 @@ captbl_idsize(cap_t c) * LLBooter initial captbl setup: * 0 = sret, * 1-3 = nil, - * 4-5 = this captbl, - * 6-7 = our pgtbl root, - * 8-11 = our component, - * 12-13 = vm pte for booter - * 14-15 = untyped memory pgtbl root, - * 16-17 = vm pte for physical memory, - * 18-19 = km pte, - * 20-21 = comp0 captbl, - * 22-23 = comp0 pgtbl root, - * 24-27 = comp0 component, - * 28~(20+2*NCPU) = per core alpha thd + * 4-7 = memory access fault handler, + * 8-11 = divide by zero fault handler, + * 12-15 = breakpoint fault handler, + * 16-19 = invalid instruction fault handler, + * 20-23 = invstk overflow and underflow fault handler, + * 24-27 = component does not exist fault handler, + * 28-31 = fault handler does not exist fault handler, + * 32-33 = this captbl, + * 34-35 = our pgtbl root, + * 36-39 = our component, + * 40-41 = vm pte for booter + * 42-43 = untyped memory pgtbl root, + * 44-45 = vm pte for physical memory, + * 46-47 = km pte, + * 48~(48+2*NCPU) = per core alpha thd * * Initial pgtbl setup (addresses): * 1GB+8MB-> = boot component VM @@ -241,24 +248,28 @@ captbl_idsize(cap_t c) */ enum { - BOOT_CAPTBL_SRET = 0, - BOOT_CAPTBL_PRINT_HACK = 2, /* This slot is not used for any capability and SRET is 16B (1slot).. */ - BOOT_CAPTBL_SELF_CT = 4, - BOOT_CAPTBL_SELF_PT = 6, - BOOT_CAPTBL_SELF_COMP = 8, - BOOT_CAPTBL_BOOTVM_PTE = 12, - BOOT_CAPTBL_SELF_UNTYPED_PT = 14, - BOOT_CAPTBL_PHYSM_PTE = 16, - BOOT_CAPTBL_KM_PTE = 18, - - BOOT_CAPTBL_SINV_CAP = 20, - BOOT_CAPTBL_SELF_INITHW_BASE = 24, - BOOT_CAPTBL_SELF_INITTHD_BASE = 28, - /* - * NOTE: kernel doesn't support sharing a cache-line across cores, - * so optimize to place INIT THD/TCAP on same cache line and bump by 64B for next CPU - */ - BOOT_CAPTBL_SELF_INITRCV_BASE = round_up_to_pow2(BOOT_CAPTBL_SELF_INITTHD_BASE + NUM_CPU * CAP64B_IDSZ, + BOOT_CAPTBL_SRET = 0, + BOOT_CAPTBL_PRINT_HACK = 2, /* This slot is not used for any capability and SRET is 16B (1slot).. */ + BOOT_CAPTBL_FLT_MEM_ACCESS = 4, + BOOT_CAPTBL_FLT_DIVZERO = 8, + BOOT_CAPTBL_FLT_BRKPT = 12, + BOOT_CAPTBL_FLT_INVLD_INS = 16, + BOOT_CAPTBL_FLT_INVSTK = 20, + BOOT_CAPTBL_FLT_COMP_NOT_EXIST = 24, + BOOT_CAPTBL_FLT_HAND_NOT_EXISt = 28, + BOOT_CAPTBL_SELF_CT = 32, + BOOT_CAPTBL_SELF_PT = 34, + BOOT_CAPTBL_SELF_COMP = 36, + BOOT_CAPTBL_BOOTVM_PTE = 40, + BOOT_CAPTBL_SELF_UNTYPED_PT = 42, + BOOT_CAPTBL_PHYSM_PTE = 44, + BOOT_CAPTBL_KM_PTE = 46, + + BOOT_CAPTBL_SINV_CAP = 48, + BOOT_CAPTBL_SELF_INITHW_BASE = 52, + BOOT_CAPTBL_SELF_INITTHD_BASE = 56, + BOOT_CAPTBL_SELF_INITTCAP_BASE = BOOT_CAPTBL_SELF_INITTHD_BASE + NUM_CPU * CAP16B_IDSZ, + BOOT_CAPTBL_SELF_INITRCV_BASE = round_up_to_pow2(BOOT_CAPTBL_SELF_INITTCAP_BASE + NUM_CPU * CAP16B_IDSZ, CAPMAX_ENTRY_SZ), BOOT_CAPTBL_LAST_CAP = BOOT_CAPTBL_SELF_INITRCV_BASE + NUM_CPU * CAP64B_IDSZ, /* round up to next entry */ @@ -274,6 +285,19 @@ enum #define BOOT_CAPTBL_SELF_INITTCAP_BASE_CPU(cpuid) (BOOT_CAPTBL_SELF_INITTHD_BASE_CPU(cpuid) + CAP16B_IDSZ) #define BOOT_CAPTBL_SELF_INITRCV_BASE_CPU(cpuid) (BOOT_CAPTBL_SELF_INITRCV_BASE + cpuid * CAP64B_IDSZ) +/* + * The slots of the sinv to user-level fault handlers. + */ +typedef enum { + COMP_CAPTBL_FLT_MEM_ACCESS = BOOT_CAPTBL_FLT_MEM_ACCESS, + COMP_CAPTBL_FLT_DIVZERO = BOOT_CAPTBL_FLT_DIVZERO, + COMP_CAPTBL_FLT_BRKPT = BOOT_CAPTBL_FLT_BRKPT, + COMP_CAPTBL_FLT_INVLD_INS = BOOT_CAPTBL_FLT_INVLD_INS, + COMP_CAPTBL_FLT_INVSTK = BOOT_CAPTBL_FLT_INVSTK, + COMP_CAPTBL_FLT_COMP_NOT_EXIST = BOOT_CAPTBL_FLT_COMP_NOT_EXIST, + COMP_CAPTBL_FLT_HAND_NOT_EXIST = BOOT_CAPTBL_FLT_HAND_NOT_EXISt, +} cap_flt_off; + /* * The half of the first page of init captbl is devoted to root node. So, the * first page of captbl can contain 128 caps, and every extra page can hold 256 @@ -287,11 +311,27 @@ enum BOOT_MEM_KM_BASE = PGD_SIZE, /* kernel & user memory @ 4M, pgd aligned start address */ }; -enum -{ +typedef enum { /* thread id */ THD_GET_TID, -}; + /* get regs */ + THD_GET_FAULT_REG0, + THD_GET_FAULT_REG1, + THD_GET_FAULT_REG2, + THD_GET_FAULT_REG3, + THD_GET_FAULT_REG4, + THD_GET_FAULT_REG5, + THD_GET_FAULT_REG6, + THD_GET_FAULT_REG7, + THD_GET_FAULT_REG8, + THD_GET_FAULT_REG9, + THD_GET_FAULT_REG10, + THD_GET_FAULT_REG11, + THD_GET_FAULT_REG12, + THD_GET_FAULT_REG13, + THD_GET_FAULT_REG14, + THD_GET_FAULT_REG15, +} cap_thdop_t; enum { diff --git a/src/kernel/include/thd.h b/src/kernel/include/thd.h index 8c10d536cc..8c2288e434 100644 --- a/src/kernel/include/thd.h +++ b/src/kernel/include/thd.h @@ -18,8 +18,24 @@ #include "tcap.h" #include "list.h" -struct invstk_entry { +/* + * Comp_invstk_info contains all information to identify which component to + * return into (via sret). It is similar to comp_info. The reason why we're using + * comp_invstk_info instead of comp_info is that we need to track if the current + * invocation is due to an explicit sinv or due to an exception or fault, as + * the return protocol for each is different. + * Thus, in this structure we use the lowest-order bit in the captbl to store + * a flag which indicates this invocation is due to an exception (or fault) or not. + * We can use the lowest-order bit because captbl is 4096-byte aligned, + * the last 12 bits of captbl are always '0'. + * Though this design makes it a bit complex, it keeps the structure 16-byte aligned. + */ +struct comp_invstk_info { struct comp_info comp_info; +}; + +struct invstk_entry { + struct comp_invstk_info comp_invstk_info; unsigned long sp, ip; /* to return to */ } HALF_CACHE_ALIGNED; @@ -256,7 +272,6 @@ thd_rcvcap_pending(struct thread *t) { if (t->rcvcap.pending) return t->rcvcap.pending; return !list_isempty(&t->event_head); - ; } static sched_tok_t @@ -332,6 +347,19 @@ thd_scheduler_set(struct thread *thd, struct thread *sched) if (unlikely(thd->scheduler_thread != sched)) thd->scheduler_thread = sched; } +/* + * This function is used to reset the invocation flag (if it is an explicit sinv or fault/exception). + */ +static inline struct comp_info * +thd_invstk_comp_info_reset(struct comp_invstk_info* comp_invstk_info) +{ + struct comp_info *comp_info = &comp_invstk_info->comp_info; + + comp_info->captbl = (struct captbl *)((unsigned long)comp_info->captbl & (~1u)); + + return comp_info; +} + static int thd_activate(struct captbl *t, capid_t cap, capid_t capin, struct thread *thd, capid_t compcap, thdclosure_index_t init_data) { @@ -348,7 +376,7 @@ thd_activate(struct captbl *t, capid_t cap, capid_t capin, struct thread *thd, c if (!tc) return ret; /* initialize the thread */ - memcpy(&(thd->invstk[0].comp_info), &compc->info, sizeof(struct comp_info)); + memcpy(&(thd->invstk[0].comp_invstk_info.comp_info), &compc->info, sizeof(struct comp_info)); thd->invstk[0].ip = thd->invstk[0].sp = 0; thd->tid = thdid_alloc(); thd->refcnt = 1; @@ -472,17 +500,31 @@ curr_invstk_top(struct cos_cpu_local_info *cos_info) return cos_info->invstk_top; } +/* + * This function returns information about the currently active component which the thread + * is executing in. In addition to thd_invstk_fault, this function returns if the component + * was invoked by a exception or fault. + */ static inline struct comp_info * -thd_invstk_current(struct thread *curr_thd, unsigned long *ip, unsigned long *sp, struct cos_cpu_local_info *cos_info) +thd_invstk_current_fault(struct thread *curr_thd, struct cos_cpu_local_info *cos_info, unsigned long *ip, unsigned long *sp, unsigned long *in_fault) { /* curr_thd should be the current thread! We are using cached invstk_top. */ struct invstk_entry *curr; - curr = &curr_thd->invstk[curr_invstk_top(cos_info)]; - *ip = curr->ip; - *sp = curr->sp; + curr = &curr_thd->invstk[curr_invstk_top(cos_info)]; + *ip = curr->ip; + *sp = curr->sp; + *in_fault = (unsigned long)curr->comp_invstk_info.comp_info.captbl & 1u; + + return thd_invstk_comp_info_reset(&curr->comp_invstk_info); +} - return &curr->comp_info; +static inline struct comp_info * +thd_invstk_current(struct thread *curr_thd, struct cos_cpu_local_info *cos_info, unsigned long *ip, unsigned long *sp) +{ + unsigned long in_fault; + + return thd_invstk_current_fault(curr_thd, cos_info, ip, sp, &in_fault); } static inline pgtbl_t @@ -493,34 +535,49 @@ thd_current_pgtbl(struct thread *thd) /* don't use the cached invstk_top here. We need the stack * pointer of the specified thread. */ curr_entry = &thd->invstk[thd->invstk_top]; - return curr_entry->comp_info.pgtbl; + + return curr_entry->comp_invstk_info.comp_info.pgtbl; +} + +static inline void +thd_invstk_modify_current(struct thread *thd, unsigned long ip, unsigned long sp, unsigned long in_fault, + struct cos_cpu_local_info *cos_info) +{ + struct invstk_entry *curr_entry; + struct comp_info *curr_comp_info; + + curr_entry = &thd->invstk[curr_invstk_top(cos_info)]; + curr_comp_info = &curr_entry->comp_invstk_info.comp_info; + curr_entry->ip = ip; + curr_entry->sp = sp; + + curr_comp_info->captbl = (struct captbl*)(((unsigned long)curr_comp_info->captbl & (~1u)) | in_fault); } static inline int -thd_invstk_push(struct thread *thd, struct comp_info *ci, unsigned long ip, unsigned long sp, +thd_invstk_push(struct thread *thd, struct comp_info *ci, unsigned long ip, unsigned long sp, unsigned long in_fault, struct cos_cpu_local_info *cos_info) { - struct invstk_entry *top, *prev; + struct invstk_entry *top; if (unlikely(curr_invstk_top(cos_info) >= THD_INVSTK_MAXSZ)) return -1; - prev = &thd->invstk[curr_invstk_top(cos_info)]; + thd_invstk_modify_current(thd, ip, sp, in_fault, cos_info); top = &thd->invstk[curr_invstk_top(cos_info) + 1]; curr_invstk_inc(cos_info); - prev->ip = ip; - prev->sp = sp; - memcpy(&top->comp_info, ci, sizeof(struct comp_info)); + memcpy(&top->comp_invstk_info.comp_info, ci, sizeof(struct comp_info)); top->ip = top->sp = 0; return 0; } static inline struct comp_info * -thd_invstk_pop(struct thread *thd, unsigned long *ip, unsigned long *sp, struct cos_cpu_local_info *cos_info) +thd_invstk_pop(struct thread *thd, struct cos_cpu_local_info *cos_info, unsigned long *ip, unsigned long *sp, unsigned long *in_fault) { if (unlikely(curr_invstk_top(cos_info) == 0)) return NULL; curr_invstk_dec(cos_info); - return thd_invstk_current(thd, ip, sp, cos_info); + + return thd_invstk_current_fault(thd, cos_info, ip, sp, in_fault); } static inline void @@ -577,15 +634,36 @@ thd_switch_update(struct thread *thd, struct pt_regs *regs, int issame) return preempt; } +#define THD_REG_READ(op, reg_name) \ + case THD_GET_FAULT_##op: \ + *retval = t->fault_regs.reg_name; \ + break \ + static inline int thd_introspect(struct thread *t, unsigned long op, unsigned long *retval) { switch (op) { - case THD_GET_TID: - *retval = t->tid; - break; - default: - return -EINVAL; + case THD_GET_TID: + *retval = t->tid; + break; + THD_REG_READ(REG0, ax); + THD_REG_READ(REG1, bx); + THD_REG_READ(REG2, cx); + THD_REG_READ(REG3, dx); + THD_REG_READ(REG4, cs); + THD_REG_READ(REG5, ds); + THD_REG_READ(REG6, es); + THD_REG_READ(REG7, fs); + THD_REG_READ(REG8, gs); + THD_REG_READ(REG9, ss); + THD_REG_READ(REG10, si); + THD_REG_READ(REG11, di); + THD_REG_READ(REG12, ip); + THD_REG_READ(REG13, sp); + THD_REG_READ(REG14, bp); + THD_REG_READ(REG15, flags); + default: + return -EINVAL; } return 0; } diff --git a/src/platform/i386/chal/call_convention.h b/src/platform/i386/chal/call_convention.h index a956f2870a..201b16b710 100644 --- a/src/platform/i386/chal/call_convention.h +++ b/src/platform/i386/chal/call_convention.h @@ -64,6 +64,14 @@ __userregs_sinvupdate(struct pt_regs *regs) /* regs->di = regs->di; */ regs->bp = regs->dx; } +static inline void +__userregs_sinvargset(struct pt_regs *regs, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4) +{ + regs->bx = arg1; + regs->si = arg2; + regs->di = arg3; + regs->di = arg4; +} static inline int __userregs_get1(struct pt_regs *regs) { diff --git a/src/platform/i386/exception.c b/src/platform/i386/exception.c index 5b6694c01a..f42f24585b 100644 --- a/src/platform/i386/exception.c +++ b/src/platform/i386/exception.c @@ -13,19 +13,47 @@ print_regs_state(struct pt_regs *regs) { PRINTK("registers:\n"); PRINTK("General registers-> EAX: %x, EBX: %x, ECX: %x, EDX: %x\n", regs->ax, regs->bx, regs->cx, regs->dx); - PRINTK("Segment registers-> CS: %x, DS: %x, ES: %x, FS: %x, GS: %x, SS: %x\n", regs->cs, regs->ds, regs->es, - regs->fs, regs->gs, regs->ss); - PRINTK("Index registers-> ESI: %x, EDI: %x, EIP: %x, ESP: %x, EBP: %x\n", regs->si, regs->di, regs->ip, - regs->sp, regs->bp); + PRINTK("Segment registers-> CS: %x, DS: %x, ES: %x, FS: %x, GS: %x, SS: %x, ESI: %x, EDI: %x \n", regs->cs, regs->ds, regs->es, + regs->fs, regs->gs, regs->ss, regs->si, regs->di); + PRINTK("Index registers-> EIP: %x, ESP: %x, EBP: %x\n", regs->ip, regs->sp, regs->bp); PRINTK("Indicator-> EFLAGS: %x\n", regs->flags); PRINTK("(Exception Error Code-> ORIG_AX: %x)\n", regs->orig_ax); } +void +fault_regs_save(struct pt_regs *regs, struct thread *thd) +{ + copy_all_regs(regs, &(thd->fault_regs)); +} + +void +fault_handler_sinv(struct pt_regs *regs, capid_t cap) +{ + struct cos_cpu_local_info *ci = cos_cpu_local_info(); + struct thread * curr_thd = thd_current(ci); + struct cap_header * fh; + struct comp_info * cos_info; + thdid_t thdid = curr_thd->tid; + unsigned long ip, sp; + u32_t fault_addr = 0, errcode, eip; + + fault_regs_save(regs, curr_thd); + cos_info = thd_invstk_current(curr_thd, ci, &ip, &sp); + fh = captbl_lkup(cos_info->captbl, cap); + __userregs_sinvargset(regs, regs->sp, regs->ip, fault_addr, cap); + /* FIXME: This is a software fault and should be fixed in the future. */ + if (unlikely(!fh)) { + die("FAULT: Fault handler not found\n"); + return; + } + + sinv_call(curr_thd, (struct cap_sinv *)fh, regs, ci, 1); +} + int div_by_zero_err_fault_handler(struct pt_regs *regs) { - print_regs_state(regs); - die("FAULT: Divide by Zero Error\n\n"); + fault_handler_sinv(regs, COMP_CAPTBL_FLT_DIVZERO); return 1; } @@ -42,8 +70,7 @@ debug_trap_handler(struct pt_regs *regs) int breakpoint_trap_handler(struct pt_regs *regs) { - print_regs_state(regs); - die("TRAP: Breakpoint\n"); + fault_handler_sinv(regs, COMP_CAPTBL_FLT_BRKPT); return 1; } @@ -60,8 +87,7 @@ overflow_trap_handler(struct pt_regs *regs) int bound_range_exceed_fault_handler(struct pt_regs *regs) { - print_regs_state(regs); - die("FAULT: Bound Range Exceeded\n"); + fault_handler_sinv(regs, COMP_CAPTBL_FLT_INVSTK); return 1; } @@ -69,8 +95,7 @@ bound_range_exceed_fault_handler(struct pt_regs *regs) int invalid_opcode_fault_handler(struct pt_regs *regs) { - print_regs_state(regs); - die("FAULT: Invalid opcode\n"); + fault_handler_sinv(regs, COMP_CAPTBL_FLT_INVLD_INS); return 1; } @@ -123,8 +148,7 @@ stack_seg_fault_handler(struct pt_regs *regs) int gen_protect_fault_handler(struct pt_regs *regs) { - print_regs_state(regs); - die("FAULT: General Protection Fault\n"); + fault_handler_sinv(regs, COMP_CAPTBL_FLT_MEM_ACCESS); return 1; } @@ -132,20 +156,8 @@ gen_protect_fault_handler(struct pt_regs *regs) int page_fault_handler(struct pt_regs *regs) { - u32_t fault_addr, errcode = 0, eip = 0; - struct cos_cpu_local_info *ci = cos_cpu_local_info(); - thdid_t thdid = thd_current(ci)->tid; - - print_regs_state(regs); - fault_addr = chal_cpu_fault_vaddr(regs); - errcode = chal_cpu_fault_errcode(regs); - eip = chal_cpu_fault_ip(regs); - - die("FAULT: Page Fault in thd %d (%s %s %s %s %s) @ 0x%x, ip 0x%x\n", thdid, - errcode & PGTBL_PRESENT ? "present" : "not-present", - errcode & PGTBL_WRITABLE ? "write-fault" : "read-fault", errcode & PGTBL_USER ? "user-mode" : "system", - errcode & PGTBL_WT ? "reserved" : "", errcode & PGTBL_NOCACHE ? "instruction-fetch" : "", fault_addr, eip); - + fault_handler_sinv(regs, COMP_CAPTBL_FLT_MEM_ACCESS); + return 1; }