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
handleFault(tcb_t * tptr)15 void 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 
handleTimeout(tcb_t * tptr)24 void handleTimeout(tcb_t *tptr)
25 {
26     assert(validTimeoutHandler(tptr));
27     sendFaultIPC(tptr, TCB_PTR_CTE_PTR(tptr, tcbTimeoutHandler)->cap, false);
28 }
29 
sendFaultIPC(tcb_t * tptr,cap_t handlerCap,bool_t can_donate)30 bool_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 
handleFault(tcb_t * tptr)53 void 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 
sendFaultIPC(tcb_t * tptr)64 exception_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
print_fault(seL4_Fault_t f)105 static 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
handleNoFaultHandler(tcb_t * tptr)144 void handleNoFaultHandler(tcb_t *tptr)
145 #else
146 /* The second fault, ex2, is stored in the global current_fault */
147 void 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