1 /*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7 #include <config.h>
8 #include <types.h>
9 #include <api/faults.h>
10 #include <api/syscall.h>
11 #include <kernel/thread.h>
12 #include <arch/kernel/thread.h>
13 #include <machine/debug.h>
14 #ifdef CONFIG_KERNEL_MCS
15 #include <mode/api/ipc_buffer.h>
16 #include <object/schedcontext.h>
17 #endif
18
19 /* consistency with libsel4 */
20 compile_assert(InvalidRoot, lookup_fault_invalid_root + 1 == seL4_InvalidRoot)
21 compile_assert(MissingCapability, lookup_fault_missing_capability + 1 == seL4_MissingCapability)
22 compile_assert(DepthMismatch, lookup_fault_depth_mismatch + 1 == seL4_DepthMismatch)
23 compile_assert(GuardMismatch, lookup_fault_guard_mismatch + 1 == seL4_GuardMismatch)
24 compile_assert(seL4_UnknownSyscall_Syscall, (word_t) n_syscallMessage == seL4_UnknownSyscall_Syscall)
25 compile_assert(seL4_UserException_Number, (word_t) n_exceptionMessage == seL4_UserException_Number)
26 compile_assert(seL4_UserException_Code, (word_t) n_exceptionMessage + 1 == seL4_UserException_Code)
27
28 static inline unsigned int
setMRs_lookup_failure(tcb_t * receiver,word_t * receiveIPCBuffer,lookup_fault_t luf,unsigned int offset)29 setMRs_lookup_failure(tcb_t *receiver, word_t *receiveIPCBuffer,
30 lookup_fault_t luf, unsigned int offset)
31 {
32 word_t lufType = lookup_fault_get_lufType(luf);
33 word_t i;
34
35 i = setMR(receiver, receiveIPCBuffer, offset, lufType + 1);
36
37 /* check constants match libsel4 */
38 if (offset == seL4_CapFault_LookupFailureType) {
39 assert(offset + 1 == seL4_CapFault_BitsLeft);
40 assert(offset + 2 == seL4_CapFault_DepthMismatch_BitsFound);
41 assert(offset + 2 == seL4_CapFault_GuardMismatch_GuardFound);
42 assert(offset + 3 == seL4_CapFault_GuardMismatch_BitsFound);
43 } else {
44 assert(offset == 1);
45 }
46
47 switch (lufType) {
48 case lookup_fault_invalid_root:
49 return i;
50
51 case lookup_fault_missing_capability:
52 return setMR(receiver, receiveIPCBuffer, offset + 1,
53 lookup_fault_missing_capability_get_bitsLeft(luf));
54
55 case lookup_fault_depth_mismatch:
56 setMR(receiver, receiveIPCBuffer, offset + 1,
57 lookup_fault_depth_mismatch_get_bitsLeft(luf));
58 return setMR(receiver, receiveIPCBuffer, offset + 2,
59 lookup_fault_depth_mismatch_get_bitsFound(luf));
60
61 case lookup_fault_guard_mismatch:
62 setMR(receiver, receiveIPCBuffer, offset + 1,
63 lookup_fault_guard_mismatch_get_bitsLeft(luf));
64 setMR(receiver, receiveIPCBuffer, offset + 2,
65 lookup_fault_guard_mismatch_get_guardFound(luf));
66 return setMR(receiver, receiveIPCBuffer, offset + 3,
67 lookup_fault_guard_mismatch_get_bitsFound(luf));
68
69 default:
70 fail("Invalid lookup failure");
71 }
72 }
73
copyMRsFaultReply(tcb_t * sender,tcb_t * receiver,MessageID_t id,word_t length)74 static inline void copyMRsFaultReply(tcb_t *sender, tcb_t *receiver, MessageID_t id, word_t length)
75 {
76 word_t i;
77 bool_t archInfo;
78
79 archInfo = Arch_getSanitiseRegisterInfo(receiver);
80
81 for (i = 0; i < MIN(length, n_msgRegisters); i++) {
82 register_t r = fault_messages[id][i];
83 word_t v = getRegister(sender, msgRegisters[i]);
84 setRegister(receiver, r, sanitiseRegister(r, v, archInfo));
85 }
86
87 if (i < length) {
88 word_t *sendBuf = lookupIPCBuffer(false, sender);
89 if (sendBuf) {
90 for (; i < length; i++) {
91 register_t r = fault_messages[id][i];
92 word_t v = sendBuf[i + 1];
93 setRegister(receiver, r, sanitiseRegister(r, v, archInfo));
94 }
95 }
96 }
97 }
98
copyMRsFault(tcb_t * sender,tcb_t * receiver,MessageID_t id,word_t length,word_t * receiveIPCBuffer)99 static inline void copyMRsFault(tcb_t *sender, tcb_t *receiver, MessageID_t id,
100 word_t length, word_t *receiveIPCBuffer)
101 {
102 word_t i;
103 for (i = 0; i < MIN(length, n_msgRegisters); i++) {
104 setRegister(receiver, msgRegisters[i], getRegister(sender, fault_messages[id][i]));
105 }
106
107 if (receiveIPCBuffer) {
108 for (; i < length; i++) {
109 receiveIPCBuffer[i + 1] = getRegister(sender, fault_messages[id][i]);
110 }
111 }
112 }
113
handleFaultReply(tcb_t * receiver,tcb_t * sender)114 bool_t handleFaultReply(tcb_t *receiver, tcb_t *sender)
115 {
116 /* These lookups are moved inward from doReplyTransfer */
117 seL4_MessageInfo_t tag = messageInfoFromWord(getRegister(sender, msgInfoRegister));
118 word_t label = seL4_MessageInfo_get_label(tag);
119 word_t length = seL4_MessageInfo_get_length(tag);
120 seL4_Fault_t fault = receiver->tcbFault;
121
122 switch (seL4_Fault_get_seL4_FaultType(fault)) {
123 case seL4_Fault_CapFault:
124 return true;
125
126 case seL4_Fault_UnknownSyscall:
127 copyMRsFaultReply(sender, receiver, MessageID_Syscall, MIN(length, n_syscallMessage));
128 return (label == 0);
129
130 case seL4_Fault_UserException:
131 copyMRsFaultReply(sender, receiver, MessageID_Exception, MIN(length, n_exceptionMessage));
132 return (label == 0);
133
134 #ifdef CONFIG_KERNEL_MCS
135 case seL4_Fault_Timeout:
136 copyMRsFaultReply(sender, receiver, MessageID_TimeoutReply, MIN(length, n_timeoutMessage));
137 return (label == 0);
138 #endif
139 #ifdef CONFIG_HARDWARE_DEBUG_API
140 case seL4_Fault_DebugException: {
141 word_t n_instrs;
142
143 if (seL4_Fault_DebugException_get_exceptionReason(fault) != seL4_SingleStep) {
144 /* Only single-step replies are required to set message registers.
145 */
146 return (label == 0);
147 }
148
149 if (length < DEBUG_REPLY_N_EXPECTED_REGISTERS) {
150 /* A single-step reply doesn't mean much if it isn't composed of the bp
151 * number and number of instructions to skip. But even if both aren't
152 * set, we can still allow the thread to continue because replying
153 * should uniformly resume thread execution, based on the general seL4
154 * API model.
155 *
156 * If it was single-step, but no reply registers were set, just
157 * default to skipping 1 and continuing.
158 *
159 * On x86, bp_num actually doesn't matter for single-stepping
160 * because single-stepping doesn't use a hardware register -- it
161 * uses EFLAGS.TF.
162 */
163 n_instrs = 1;
164 } else {
165 /* If the reply had all expected registers set, proceed as normal */
166 n_instrs = getRegister(sender, msgRegisters[0]);
167 }
168
169 syscall_error_t res;
170
171 res = Arch_decodeConfigureSingleStepping(receiver, 0, n_instrs, true);
172 if (res.type != seL4_NoError) {
173 return false;
174 };
175
176 configureSingleStepping(receiver, 0, n_instrs, true);
177
178 /* Replying will always resume the thread: the only variant behaviour
179 * is whether or not the thread will be resumed with stepping still
180 * enabled.
181 */
182 return (label == 0);
183 }
184 #endif
185
186 default:
187 return Arch_handleFaultReply(receiver, sender, seL4_Fault_get_seL4_FaultType(fault));
188 }
189 }
190
setMRs_fault(tcb_t * sender,tcb_t * receiver,word_t * receiveIPCBuffer)191 word_t setMRs_fault(tcb_t *sender, tcb_t *receiver, word_t *receiveIPCBuffer)
192 {
193 switch (seL4_Fault_get_seL4_FaultType(sender->tcbFault)) {
194 case seL4_Fault_CapFault:
195 setMR(receiver, receiveIPCBuffer, seL4_CapFault_IP, getRestartPC(sender));
196 setMR(receiver, receiveIPCBuffer, seL4_CapFault_Addr,
197 seL4_Fault_CapFault_get_address(sender->tcbFault));
198 setMR(receiver, receiveIPCBuffer, seL4_CapFault_InRecvPhase,
199 seL4_Fault_CapFault_get_inReceivePhase(sender->tcbFault));
200 return setMRs_lookup_failure(receiver, receiveIPCBuffer,
201 sender->tcbLookupFailure, seL4_CapFault_LookupFailureType);
202
203 case seL4_Fault_UnknownSyscall: {
204 copyMRsFault(sender, receiver, MessageID_Syscall, n_syscallMessage,
205 receiveIPCBuffer);
206
207 return setMR(receiver, receiveIPCBuffer, n_syscallMessage,
208 seL4_Fault_UnknownSyscall_get_syscallNumber(sender->tcbFault));
209 }
210
211 case seL4_Fault_UserException: {
212 copyMRsFault(sender, receiver, MessageID_Exception,
213 n_exceptionMessage, receiveIPCBuffer);
214 setMR(receiver, receiveIPCBuffer, n_exceptionMessage,
215 seL4_Fault_UserException_get_number(sender->tcbFault));
216 return setMR(receiver, receiveIPCBuffer, n_exceptionMessage + 1u,
217 seL4_Fault_UserException_get_code(sender->tcbFault));
218 }
219
220 #ifdef CONFIG_KERNEL_MCS
221 case seL4_Fault_Timeout: {
222 word_t len = setMR(receiver, receiveIPCBuffer, seL4_Timeout_Data,
223 seL4_Fault_Timeout_get_badge(sender->tcbFault));
224 if (sender->tcbSchedContext) {
225 time_t consumed = schedContext_updateConsumed(sender->tcbSchedContext);
226 return mode_setTimeArg(len, consumed,
227 receiveIPCBuffer, receiver);
228 } else {
229 return len;
230 }
231 }
232 #endif
233 #ifdef CONFIG_HARDWARE_DEBUG_API
234 case seL4_Fault_DebugException: {
235 word_t reason = seL4_Fault_DebugException_get_exceptionReason(sender->tcbFault);
236
237 setMR(receiver, receiveIPCBuffer,
238 seL4_DebugException_FaultIP, getRestartPC(sender));
239 unsigned int ret = setMR(receiver, receiveIPCBuffer,
240 seL4_DebugException_ExceptionReason, reason);
241
242 if (reason != seL4_SingleStep && reason != seL4_SoftwareBreakRequest) {
243 ret = setMR(receiver, receiveIPCBuffer,
244 seL4_DebugException_TriggerAddress,
245 seL4_Fault_DebugException_get_breakpointAddress(sender->tcbFault));
246
247 /* Breakpoint messages also set a "breakpoint number" register. */
248 ret = setMR(receiver, receiveIPCBuffer,
249 seL4_DebugException_BreakpointNumber,
250 seL4_Fault_DebugException_get_breakpointNumber(sender->tcbFault));
251 }
252 return ret;
253 }
254 #endif /* CONFIG_HARDWARE_DEBUG_API */
255
256 default:
257 return Arch_setMRs_fault(sender, receiver, receiveIPCBuffer,
258 seL4_Fault_get_seL4_FaultType(sender->tcbFault));
259 }
260 }
261