1/* 2 * Copyright 2014, General Dynamics C4 Systems 3 * 4 * SPDX-License-Identifier: GPL-2.0-only 5 */ 6 7#include <api/failures.h> 8#include <kernel/cspace.h> 9#include <kernel/faulthandler.h> 10#include <kernel/thread.h> 11#include <machine/io.h> 12#include <arch/machine.h> 13 14#ifdef CONFIG_KERNEL_MCS 15void handleFault(tcb_t *tptr) 16{ 17 bool_t hasFaultHandler = sendFaultIPC(tptr, TCB_PTR_CTE_PTR(tptr, tcbFaultHandler)->cap, 18 tptr->tcbSchedContext != NULL); 19 if (!hasFaultHandler) { 20 handleNoFaultHandler(tptr); 21 } 22} 23 24void handleTimeout(tcb_t *tptr) 25{ 26 assert(validTimeoutHandler(tptr)); 27 sendFaultIPC(tptr, TCB_PTR_CTE_PTR(tptr, tcbTimeoutHandler)->cap, false); 28} 29 30bool_t sendFaultIPC(tcb_t *tptr, cap_t handlerCap, bool_t can_donate) 31{ 32 if (cap_get_capType(handlerCap) == cap_endpoint_cap) { 33 assert(cap_endpoint_cap_get_capCanSend(handlerCap)); 34 assert(cap_endpoint_cap_get_capCanGrant(handlerCap) || 35 cap_endpoint_cap_get_capCanGrantReply(handlerCap)); 36 37 tptr->tcbFault = current_fault; 38 sendIPC(true, false, 39 cap_endpoint_cap_get_capEPBadge(handlerCap), 40 cap_endpoint_cap_get_capCanGrant(handlerCap), 41 cap_endpoint_cap_get_capCanGrantReply(handlerCap), 42 can_donate, tptr, 43 EP_PTR(cap_endpoint_cap_get_capEPPtr(handlerCap))); 44 45 return true; 46 } else { 47 assert(cap_get_capType(handlerCap) == cap_null_cap); 48 return false; 49 } 50} 51#else 52 53void handleFault(tcb_t *tptr) 54{ 55 exception_t status; 56 seL4_Fault_t fault = current_fault; 57 58 status = sendFaultIPC(tptr); 59 if (status != EXCEPTION_NONE) { 60 handleDoubleFault(tptr, fault); 61 } 62} 63 64exception_t sendFaultIPC(tcb_t *tptr) 65{ 66 cptr_t handlerCPtr; 67 cap_t handlerCap; 68 lookupCap_ret_t lu_ret; 69 lookup_fault_t original_lookup_fault; 70 71 original_lookup_fault = current_lookup_fault; 72 73 handlerCPtr = tptr->tcbFaultHandler; 74 lu_ret = lookupCap(tptr, handlerCPtr); 75 if (lu_ret.status != EXCEPTION_NONE) { 76 current_fault = seL4_Fault_CapFault_new(handlerCPtr, false); 77 return EXCEPTION_FAULT; 78 } 79 handlerCap = lu_ret.cap; 80 81 if (cap_get_capType(handlerCap) == cap_endpoint_cap && 82 cap_endpoint_cap_get_capCanSend(handlerCap) && 83 (cap_endpoint_cap_get_capCanGrant(handlerCap) || 84 cap_endpoint_cap_get_capCanGrantReply(handlerCap))) { 85 tptr->tcbFault = current_fault; 86 if (seL4_Fault_get_seL4_FaultType(current_fault) == seL4_Fault_CapFault) { 87 tptr->tcbLookupFailure = original_lookup_fault; 88 } 89 sendIPC(true, true, 90 cap_endpoint_cap_get_capEPBadge(handlerCap), 91 cap_endpoint_cap_get_capCanGrant(handlerCap), true, tptr, 92 EP_PTR(cap_endpoint_cap_get_capEPPtr(handlerCap))); 93 94 return EXCEPTION_NONE; 95 } else { 96 current_fault = seL4_Fault_CapFault_new(handlerCPtr, false); 97 current_lookup_fault = lookup_fault_missing_capability_new(0); 98 99 return EXCEPTION_FAULT; 100 } 101} 102#endif 103 104#ifdef CONFIG_PRINTING 105static void print_fault(seL4_Fault_t f) 106{ 107 switch (seL4_Fault_get_seL4_FaultType(f)) { 108 case seL4_Fault_NullFault: 109 printf("null fault"); 110 break; 111 case seL4_Fault_CapFault: 112 printf("cap fault in %s phase at address %p", 113 seL4_Fault_CapFault_get_inReceivePhase(f) ? "receive" : "send", 114 (void *)seL4_Fault_CapFault_get_address(f)); 115 break; 116 case seL4_Fault_VMFault: 117 printf("vm fault on %s at address %p with status %p", 118 seL4_Fault_VMFault_get_instructionFault(f) ? "code" : "data", 119 (void *)seL4_Fault_VMFault_get_address(f), 120 (void *)seL4_Fault_VMFault_get_FSR(f)); 121 break; 122 case seL4_Fault_UnknownSyscall: 123 printf("unknown syscall %p", 124 (void *)seL4_Fault_UnknownSyscall_get_syscallNumber(f)); 125 break; 126 case seL4_Fault_UserException: 127 printf("user exception %p code %p", 128 (void *)seL4_Fault_UserException_get_number(f), 129 (void *)seL4_Fault_UserException_get_code(f)); 130 break; 131#ifdef CONFIG_KERNEL_MCS 132 case seL4_Fault_Timeout: 133 printf("Timeout fault for 0x%x\n", (unsigned int) seL4_Fault_Timeout_get_badge(f)); 134 break; 135#endif 136 default: 137 printf("unknown fault"); 138 break; 139 } 140} 141#endif 142 143#ifdef CONFIG_KERNEL_MCS 144void handleNoFaultHandler(tcb_t *tptr) 145#else 146/* The second fault, ex2, is stored in the global current_fault */ 147void handleDoubleFault(tcb_t *tptr, seL4_Fault_t ex1) 148#endif 149{ 150#ifdef CONFIG_PRINTING 151#ifdef CONFIG_KERNEL_MCS 152 printf("Found thread has no fault handler while trying to handle:\n"); 153 print_fault(current_fault); 154#else 155 seL4_Fault_t ex2 = current_fault; 156 printf("Caught "); 157 print_fault(ex2); 158 printf("\nwhile trying to handle:\n"); 159 print_fault(ex1); 160#endif 161#ifdef CONFIG_DEBUG_BUILD 162 printf("\nin thread %p \"%s\" ", tptr, TCB_PTR_DEBUG_PTR(tptr)->tcbName); 163#endif /* CONFIG_DEBUG_BUILD */ 164 165 printf("at address %p\n", (void *)getRestartPC(tptr)); 166 printf("With stack:\n"); 167 Arch_userStackTrace(tptr); 168#endif 169 170 setThreadState(tptr, ThreadState_Inactive); 171} 172