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