#include <api/failures.h>
#include <kernel/cspace.h>
#include <kernel/faulthandler.h>
#include <kernel/thread.h>
#include <machine/io.h>
#include <arch/machine.h>
void
handleFault(tcb_t *tptr)
{
exception_t status;
seL4_Fault_t fault = current_fault;
status = sendFaultIPC(tptr);
if (status != EXCEPTION_NONE) {
handleDoubleFault(tptr, fault);
}
}
exception_t
sendFaultIPC(tcb_t *tptr)
{
cptr_t handlerCPtr;
cap_t handlerCap;
lookupCap_ret_t lu_ret;
lookup_fault_t original_lookup_fault;
original_lookup_fault = current_lookup_fault;
handlerCPtr = tptr->tcbFaultHandler;
lu_ret = lookupCap(tptr, handlerCPtr);
if (lu_ret.status != EXCEPTION_NONE) {
current_fault = seL4_Fault_CapFault_new(handlerCPtr, false);
return EXCEPTION_FAULT;
}
handlerCap = lu_ret.cap;
if (cap_get_capType(handlerCap) == cap_endpoint_cap &&
cap_endpoint_cap_get_capCanSend(handlerCap) &&
cap_endpoint_cap_get_capCanGrant(handlerCap)) {
tptr->tcbFault = current_fault;
if (seL4_Fault_get_seL4_FaultType(current_fault) == seL4_Fault_CapFault) {
tptr->tcbLookupFailure = original_lookup_fault;
}
sendIPC(true, false,
cap_endpoint_cap_get_capEPBadge(handlerCap),
true, tptr,
EP_PTR(cap_endpoint_cap_get_capEPPtr(handlerCap)));
return EXCEPTION_NONE;
} else {
current_fault = seL4_Fault_CapFault_new(handlerCPtr, false);
current_lookup_fault = lookup_fault_missing_capability_new(0);
return EXCEPTION_FAULT;
}
}
#ifdef CONFIG_PRINTING
static void
print_fault(seL4_Fault_t f)
{
switch (seL4_Fault_get_seL4_FaultType(f)) {
case seL4_Fault_NullFault:
printf("null fault");
break;
case seL4_Fault_CapFault:
printf("cap fault in %s phase at address 0x%x",
seL4_Fault_CapFault_get_inReceivePhase(f) ? "receive" : "send",
(unsigned int)seL4_Fault_CapFault_get_address(f));
break;
case seL4_Fault_VMFault:
printf("vm fault on %s at address 0x%x with status 0x%x",
seL4_Fault_VMFault_get_instructionFault(f) ? "code" : "data",
(unsigned int)seL4_Fault_VMFault_get_address(f),
(unsigned int)seL4_Fault_VMFault_get_FSR(f));
break;
case seL4_Fault_UnknownSyscall:
printf("unknown syscall 0x%x",
(unsigned int)seL4_Fault_UnknownSyscall_get_syscallNumber(f));
break;
case seL4_Fault_UserException:
printf("user exception 0x%x code 0x%x",
(unsigned int)seL4_Fault_UserException_get_number(f),
(unsigned int)seL4_Fault_UserException_get_code(f));
break;
default:
printf("unknown fault");
break;
}
}
#endif
void
handleDoubleFault(tcb_t *tptr, seL4_Fault_t ex1)
{
#ifdef CONFIG_PRINTING
seL4_Fault_t ex2 = current_fault;
printf("Caught ");
print_fault(ex2);
printf("\nwhile trying to handle:\n");
print_fault(ex1);
#ifdef CONFIG_DEBUG_BUILD
printf("\nin thread %p \"%s\" ", tptr, tptr->tcbName);
#endif
printf("at address %p\n", (void*)getRestartPC(tptr));
printf("With stack:\n");
Arch_userStackTrace(tptr);
#endif
setThreadState(tptr, ThreadState_Inactive);
}