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