-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementation of the user-level fault handler #376
base: ppos
Are you sure you want to change the base?
Changes from all commits
762283a
e0579b1
0f95309
41be7b0
370a243
56feb7c
f9ef836
0d3752a
e36d46f
716103b
b08e377
80c2ac8
f9863a6
ad4a0d8
b1da7b2
99a5be5
e200a66
41be2d5
964af00
9b63e45
4fb83c3
f8b5104
e87fc1b
602ac89
c8b3dcf
d7357f7
4ab36d2
2edf3a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,10 +9,20 @@ | |
#include <res_spec.h> | ||
#include <ps.h> | ||
#include <bitmap.h> | ||
#include <fault_handler.h> | ||
|
||
/* 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 */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. consider defining unsigned longs as something else in the future, perhaps ptrint_t. This is for the long term. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why aren't they just |
||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very interesting! It looks like the handler assumes the fault is always in the |
||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems hard to make portable. I wonder if we should simply make the register an int that goes through a loop with the loop bound defined by an architecture-specific variable. IP/SP/FP are all exceptions, I'm sure. I don't think this requires changes now, but should be considered in future iterations. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is a memory address fault? I know general protection faults, and page-faults. |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In a future iteration, I think we want two fault handlers for overflow and underflow. I believe the separate components might want to implement each. TODO in the future. |
||
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()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This applies to all PRINT statements, grammar doesn't seem right! |
||
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) | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
LIB_OBJS= | ||
LIBS=$(LIB_OBJS:%.o=%.a) | ||
|
||
include ../Makefile.subdir | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I'd use |
||
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 */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#include <cos_asm_server_stub_simple_stack.h> | ||
|
||
.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) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't there a function to get this? Shouldn't there be? |
||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
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 */ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name choices:
faults
,faultmgr
and of coursefault_handler
here. I actually like having the API name contain interface name as a prefix but again that's a personal preference, just wanted to mention that.