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 */ 20compile_assert(InvalidRoot, lookup_fault_invalid_root + 1 == seL4_InvalidRoot) 21compile_assert(MissingCapability, lookup_fault_missing_capability + 1 == seL4_MissingCapability) 22compile_assert(DepthMismatch, lookup_fault_depth_mismatch + 1 == seL4_DepthMismatch) 23compile_assert(GuardMismatch, lookup_fault_guard_mismatch + 1 == seL4_GuardMismatch) 24compile_assert(seL4_UnknownSyscall_Syscall, (word_t) n_syscallMessage == seL4_UnknownSyscall_Syscall) 25compile_assert(seL4_UserException_Number, (word_t) n_exceptionMessage == seL4_UserException_Number) 26compile_assert(seL4_UserException_Code, (word_t) n_exceptionMessage + 1 == seL4_UserException_Code) 27 28static inline unsigned int 29setMRs_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 74static 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 99static 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 114bool_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 191word_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