1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the GNU General Public License version 2. Note that NO WARRANTY is provided. 8 * See "LICENSE_GPLv2.txt" for details. 9 * 10 * @TAG(DATA61_GPL) 11 */ 12#ifndef __ARCH_MACHINE_DEBUG_H 13#define __ARCH_MACHINE_DEBUG_H 14 15#include <util.h> 16#include <api/types.h> 17#include <arch/machine/debug_conf.h> 18#include <plat/api/constants.h> 19#include <armv/debug.h> 20 21#ifdef ARM_BASE_CP14_SAVE_AND_RESTORE 22void restore_user_debug_context(tcb_t *target_thread); 23void saveAllBreakpointState(tcb_t *t); 24void loadAllDisabledBreakpointState(void); 25#endif 26#ifdef ARM_HYP_CP14_SAVE_AND_RESTORE_VCPU_THREADS 27void Arch_debugAssociateVCPUTCB(tcb_t *t); 28void Arch_debugDissociateVCPUTCB(tcb_t *t); 29#endif 30 31#ifdef ARM_HYP_TRAP_CP14 32/* Those of these that trap NS accesses trap all NS accesses; we can't cause the 33 * processor to only trap NS-PL0 or NS-PL1, but if we want to trap the accesses, 34 * we get both (PL0 and PL1) non-secure modes' accesses. 35 */ 36#define ARM_CP15_HDCR "p15, 4, %0, c1, c1, 1" 37#define HDCR_DEBUG_TDRA_SHIFT (11) /* Trap debug ROM access from non-secure world */ 38#define HDCR_DEBUG_TDOSA_SHIFT (10) /* Trap debug OS related access from NS world */ 39#define HDCR_DEBUG_TDA_SHIFT (9) /* Trap debug CP14 register access from NS world */ 40#define HDCR_DEBUG_TDE_SHIFT (8) /* Trap debug exceptions taken from NS world */ 41#define HDCR_PERFMON_HPME_SHIFT (7) /* Enable the hyp-mode perfmon counters. */ 42#define HDCR_PERFMON_TPM_SHIFT (6) /* Trap NS PM accesses */ 43#define HDCR_PERFMON_TPMCR_SHIFT (5) /* Trap NS PMCR reg access */ 44 45/** When running seL4 as a hypervisor, if we're building with support for the 46 * hardware debug API, we have a case of indirection that we need to handle. 47 * 48 * For native PL0 user threads in the hypervisor seL4 build, if a debug 49 * exception is triggered in one of them, the CPU will raise the exception and 50 * naturally, it will attempt to deliver it to a PL1 exception vector table -- 51 * but no such table exists for native hypervisor-seL4 threads, so the CPU will 52 * end up encountering a VM fault while trying to vector into the vector table. 53 * 54 * For this reason, for native hypervisor-seL4 threads, we need to trap the 55 * debug exception DIRECTLY into the hypervisor-seL4 instance, and handle it 56 * directly. So we need to SET HDCR.TDE for this case. 57 * 58 * For the Guest VM, if it programs the CPU to trigger breakpoints, and a 59 * debug exception gets triggered, we don't want to catch those debug exceptions 60 * since we can let the Guest VM handle them on its own. So we need to UNSET 61 * HDCR.TDE for this case. 62 * 63 * This function encapsulates the setting/unsetting, and it is called when we 64 * are about to enable/disable a VCPU. 65 * 66 * If we are enabling a vcpu (vcpu_enable) we UNSET HDCR.TDE. 67 * If we are disabling a vcpu (vcpu_disable) we SET HDCR.TDE. 68 */ 69static inline void 70setHDCRTrapDebugExceptionState(bool_t enable_trapping) 71{ 72 word_t hdcr; 73#ifdef CONFIG_ARCH_AARCH64 74 MRS("mdcr_el2", hdcr); 75#else 76 MRC(ARM_CP15_HDCR, hdcr); 77#endif 78 if (enable_trapping) { 79 /* Trap and redirect debug faults that occur in PL0 native threads by 80 * setting HDCR.TDE (trap debug exceptions). 81 */ 82 hdcr |= (BIT(HDCR_DEBUG_TDE_SHIFT) 83 | BIT(HDCR_DEBUG_TDA_SHIFT) 84 | BIT(HDCR_DEBUG_TDRA_SHIFT) 85 | BIT(HDCR_DEBUG_TDOSA_SHIFT)); 86 } else { 87 /* Let the PL1 Guest VM handle debug events on its own */ 88 hdcr &= ~(BIT(HDCR_DEBUG_TDE_SHIFT) 89 | BIT(HDCR_DEBUG_TDA_SHIFT) 90 | BIT(HDCR_DEBUG_TDRA_SHIFT) 91 | BIT(HDCR_DEBUG_TDOSA_SHIFT)); 92 } 93#ifdef CONFIG_ARCH_AARCH64 94 MSR("mdcr_el2", hdcr); 95#else 96 MCR(ARM_CP15_HDCR, hdcr); 97#endif 98} 99 100static inline void 101initHDCR(void) 102{ 103 /* By default at boot, we SET HDCR.TDE to catch and redirect native threads' 104 * PL0 debug exceptions. 105 * 106 * Unfortunately, this is complicated a bit by ARM's strange requirement that 107 * if you set HDCR.TDE, you must also set TDA, TDOSA, and TDRA: 108 * ARMv7 archref manual: section B1.8.9: 109 * "When HDCR.TDE is set to 1, the HDCR.{TDRA, TDOSA, TDA} bits must all 110 * be set to 1, otherwise behavior is UNPREDICTABLE" 111 * 112 * Subsequently on calls to vcpu_enable/disable, we will modify HDCR.TDE 113 * as needed. 114 */ 115 setHDCRTrapDebugExceptionState(true); 116} 117#endif /* ARM_HYP_TRAP_CP14 */ 118 119#ifdef CONFIG_HARDWARE_DEBUG_API 120 121static uint16_t 122convertBpNumToArch(uint16_t bp_num) 123{ 124 if (bp_num >= seL4_NumExclusiveBreakpoints) { 125 bp_num -= seL4_NumExclusiveBreakpoints; 126 } 127 return bp_num; 128} 129 130static word_t 131getTypeFromBpNum(uint16_t bp_num) 132{ 133 return (bp_num >= seL4_NumExclusiveBreakpoints) 134 ? seL4_DataBreakpoint 135 : seL4_InstructionBreakpoint; 136} 137 138static inline syscall_error_t 139Arch_decodeConfigureSingleStepping(tcb_t *t, 140 uint16_t bp_num, 141 word_t n_instr, 142 bool_t is_reply) 143{ 144 word_t type; 145 syscall_error_t ret = { 146 .type = seL4_NoError 147 }; 148 149 if (is_reply) { 150 /* If this is a single-step fault reply, just default to the already- 151 * configured bp_num. Of course, this assumes that a register had 152 * already previously been configured for single-stepping. 153 */ 154 if (!t->tcbArch.tcbContext.breakpointState.single_step_enabled) { 155 userError("Debug: Single-step reply when single-stepping not " 156 "enabled."); 157 ret.type = seL4_IllegalOperation; 158 return ret; 159 } 160 161 type = seL4_InstructionBreakpoint; 162 bp_num = t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num; 163 } else { 164 type = getTypeFromBpNum(bp_num); 165 bp_num = convertBpNumToArch(bp_num); 166 } 167 168 if (type != seL4_InstructionBreakpoint || bp_num >= seL4_FirstWatchpoint) { 169 /* Must use an instruction BP register */ 170 userError("Debug: Single-stepping can only be used with an instruction " 171 "breakpoint."); 172 ret.type = seL4_InvalidArgument; 173 ret.invalidArgumentNumber = 0; 174 return ret; 175 } 176 if (t->tcbArch.tcbContext.breakpointState.single_step_enabled == true) { 177 if (bp_num != t->tcbArch.tcbContext.breakpointState.single_step_hw_bp_num) { 178 /* Can't configure more than one register for stepping. */ 179 userError("Debug: Only one register can be configured for " 180 "single-stepping at a time."); 181 ret.type = seL4_InvalidArgument; 182 ret.invalidArgumentNumber = 0; 183 return ret; 184 } 185 } 186 187 return ret; 188} 189 190bool_t byte8WatchpointsSupported(void); 191 192static inline syscall_error_t 193Arch_decodeSetBreakpoint(tcb_t *t, 194 uint16_t bp_num, word_t vaddr, word_t type, 195 word_t size, word_t rw) 196{ 197 syscall_error_t ret = { 198 .type = seL4_NoError 199 }; 200 201 bp_num = convertBpNumToArch(bp_num); 202 203 if (type == seL4_DataBreakpoint) { 204 if (bp_num >= seL4_NumExclusiveWatchpoints) { 205 userError("Debug: invalid data-watchpoint number %u.", bp_num); 206 ret.type = seL4_RangeError; 207 ret.rangeErrorMin = 0; 208 ret.rangeErrorMax = seL4_NumExclusiveBreakpoints - 1; 209 return ret; 210 } 211 } else if (type == seL4_InstructionBreakpoint) { 212 if (bp_num >= seL4_NumExclusiveBreakpoints) { 213 userError("Debug: invalid instruction breakpoint nunber %u.", bp_num); 214 ret.type = seL4_RangeError; 215 ret.rangeErrorMin = 0; 216 ret.rangeErrorMax = seL4_NumExclusiveWatchpoints - 1; 217 return ret; 218 } 219 } 220 221 if (size == 8 && !byte8WatchpointsSupported()) { 222 userError("Debug: 8-byte watchpoints not supported on this CPU."); 223 ret.type = seL4_InvalidArgument; 224 ret.invalidArgumentNumber = 3; 225 return ret; 226 } 227 if (size == 8 && type != seL4_DataBreakpoint) { 228 userError("Debug: 8-byte sizes can only be used with watchpoints."); 229 ret.type = seL4_InvalidArgument; 230 ret.invalidArgumentNumber = 3; 231 return ret; 232 } 233 234 return ret; 235} 236 237static inline syscall_error_t 238Arch_decodeGetBreakpoint(tcb_t *t, uint16_t bp_num) 239{ 240 syscall_error_t ret = { 241 .type = seL4_NoError 242 }; 243 244 if (bp_num >= seL4_FirstWatchpoint + seL4_NumExclusiveWatchpoints) { 245 userError("Arch Debug: Invalid API bp_num %u.", bp_num); 246 ret.type = seL4_NoError; 247 return ret; 248 } 249 return ret; 250} 251 252static inline syscall_error_t 253Arch_decodeUnsetBreakpoint(tcb_t *t, uint16_t bp_num) 254{ 255 syscall_error_t ret = { 256 .type = seL4_NoError 257 }; 258 259 if (bp_num >= seL4_FirstWatchpoint + seL4_NumExclusiveWatchpoints) { 260 userError("Arch Debug: Invalid API bp_num %u.", bp_num); 261 ret.type = seL4_NoError; 262 return ret; 263 } 264 265 word_t type; 266 dbg_bcr_t bcr; 267 268 type = getTypeFromBpNum(bp_num); 269 bp_num = convertBpNumToArch(bp_num); 270 271 bcr.words[0] = t->tcbArch.tcbContext.breakpointState.breakpoint[bp_num].cr; 272 if (type == seL4_InstructionBreakpoint) { 273 if (Arch_breakpointIsMismatch(bcr) == true && dbg_bcr_get_enabled(bcr)) { 274 userError("Rejecting call to unsetBreakpoint on breakpoint configured " 275 "for single-stepping (hwid %u).", bp_num); 276 ret.type = seL4_IllegalOperation; 277 return ret; 278 } 279 } 280 281 return ret; 282} 283 284#endif /* CONFIG_HARDWARE_DEBUG_API */ 285 286#endif /* !__ARCH_MACHINE_DEBUG_H */ 287