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 13#ifndef __ARCH_MACHINE_DEBUG_H_ 14#define __ARCH_MACHINE_DEBUG_H_ 15 16#include <config.h> 17#ifdef CONFIG_HARDWARE_DEBUG_API 18 19#include <types.h> 20#include <api/types.h> 21#include <arch/machine/registerset.h> 22#include <mode/machine/debug.h> 23 24/* Bit in DR7 that will enable each BP respectively. */ 25#define X86_DEBUG_BP0_ENABLE_BIT ((word_t)BIT(1)) 26#define X86_DEBUG_BP1_ENABLE_BIT ((word_t)BIT(3)) 27#define X86_DEBUG_BP2_ENABLE_BIT ((word_t)BIT(5)) 28#define X86_DEBUG_BP3_ENABLE_BIT ((word_t)BIT(7)) 29 30/** Per-thread initial state setting. 31 * 32 * The most significant thing done here is that we pre-load reserved bits from 33 * the hardware registers into the TCB context. 34 * 35 * @param context TCB breakpoint context for the thread being initialized. 36 */ 37void Arch_initBreakpointContext(user_breakpoint_state_t *context); 38 39/** Discerns and handles a debug exception. 40 * 41 * Determines which hardware breakpoint triggered a debug exception, and 42 * generates a message to userspace for that breakpoint exception, or generates 43 * a message to userspace for a single-step exception, if it was a single-step 44 * event that triggered the exception. 45 * 46 * ARM's exception-path flow works differently. 47 * 48 * @param int_vector Processor-level vector number on which the exception 49 * occurred. May be 1 or 3, depending on whether the exception 50 * is a breakpoint, single-step, or INT3 exception. 51 */ 52exception_t handleUserLevelDebugException(int int_vector); 53 54/** These next two functions are part of some state flags. 55 * 56 * A bitfield of all currently enabled breakpoints for a thread is kept in that 57 * thread's TCB. These two functions here set and unset the bits in that 58 * bitfield. 59 */ 60static inline void 61setBreakpointUsedFlag(tcb_t *t, uint16_t bp_num) 62{ 63 if (t != NULL) { 64 t->tcbArch.tcbContext.breakpointState.used_breakpoints_bf |= BIT(bp_num); 65 } 66} 67 68static inline void 69unsetBreakpointUsedFlag(tcb_t *t, uint16_t bp_num) 70{ 71 if (t != NULL) { 72 t->tcbArch.tcbContext.breakpointState.used_breakpoints_bf &= ~BIT(bp_num); 73 } 74} 75 76/** Program the debug registers with values that will disable all breakpoints. 77 * 78 * This is an optimization for threads that don't use any breakpoints: we won't 79 * try to pop all the context from a block of memory, but just unset all the 80 * "enable" bits in the registers. 81 * @param at arch_tcb_t from which the reserved bits will be loaded before 82 * setting the disable bits. 83 */ 84static void 85loadAllDisabledBreakpointState(tcb_t *t) 86{ 87 word_t disable_value; 88 89 disable_value = t->tcbArch.tcbContext.breakpointState.dr[5]; 90 disable_value &= ~(X86_DEBUG_BP0_ENABLE_BIT | X86_DEBUG_BP1_ENABLE_BIT 91 | X86_DEBUG_BP2_ENABLE_BIT | X86_DEBUG_BP3_ENABLE_BIT); 92 93 writeDr7Reg(disable_value); 94} 95 96static inline void 97restore_user_debug_context(tcb_t *target_thread) 98{ 99 arch_tcb_t *uds = &target_thread->tcbArch; 100 if (uds->tcbContext.breakpointState.used_breakpoints_bf != 0) { 101 loadBreakpointState(target_thread); 102 } else { 103 loadAllDisabledBreakpointState(target_thread); 104 } 105 106 /* If single-stepping was enabled, we need to re-set the TF flag as well. */ 107 if (uds->tcbContext.breakpointState.single_step_enabled == true) { 108 uds->tcbContext.registers[FLAGS] |= FLAGS_TF; 109 /* Under ia32 we also need to ensure we return via an IRET as the 110 * sysexit return path will pop flags a couple of instructions 111 * before performing sysexit resulting in an exception, due to 112 * single stepping, inside the kernel. To avoid this we will 113 * return via an IRET, which atomically pops the flags and 114 * returns to user level */ 115#ifdef CONFIG_ARCH_IA32 116 if (getRegister(target_thread, Error) == -1) { 117 setRegister(target_thread, Error, 0); 118 /* As we did not come in from an interrupt there is no guarantee 119 * the CS and SS in the context are set to anything sensible, so 120 * force them to the correct user value */ 121 setRegister(target_thread, CS, SEL_CS_3); 122 setRegister(target_thread, SS, SEL_DS_3); 123 } 124#endif 125 } 126} 127 128static inline syscall_error_t 129Arch_decodeConfigureSingleStepping(tcb_t *t, 130 uint16_t bp_num, 131 word_t n_instr, 132 bool_t is_reply) 133{ 134 syscall_error_t ret; 135 136 ret.type = seL4_NoError; 137 return ret; 138} 139 140bool_t byte8BreakpointsSupported(void); 141 142static inline syscall_error_t 143Arch_decodeSetBreakpoint(tcb_t *t, 144 uint16_t bp_num, word_t vaddr, word_t types, 145 word_t size, word_t rw) 146{ 147 syscall_error_t ret = { 148 .type = seL4_NoError 149 }; 150 151 if (bp_num >= X86_DEBUG_BP_N_REGS) { 152 userError("Debug: invalid bp_num %u.", bp_num); 153 ret.rangeErrorMin = 0; 154 ret.rangeErrorMax = 3; 155 ret.type = seL4_RangeError; 156 return ret; 157 } 158 if (size == 8 && !byte8BreakpointsSupported()) { 159 userError("Debug: 8-byte breakpoints/watchpoints unsupported on this CPU."); 160 ret.invalidArgumentNumber = 3; 161 ret.type = seL4_InvalidArgument; 162 return ret; 163 } 164 return ret; 165} 166 167static inline syscall_error_t 168Arch_decodeGetBreakpoint(tcb_t *t, uint16_t bp_num) 169{ 170 syscall_error_t ret = { 171 .type = seL4_NoError 172 }; 173 174 if (bp_num >= X86_DEBUG_BP_N_REGS) { 175 userError("Debug: invalid bp_num %u.", bp_num); 176 ret.rangeErrorMin = 0; 177 ret.rangeErrorMax = 3; 178 ret.type = seL4_RangeError; 179 } 180 return ret; 181} 182 183static inline syscall_error_t 184Arch_decodeUnsetBreakpoint(tcb_t *t, uint16_t bp_num) 185{ 186 syscall_error_t ret = { 187 .type = seL4_NoError 188 }; 189 190 if (bp_num >= X86_DEBUG_BP_N_REGS) { 191 userError("Debug: invalid bp_num %u.", bp_num); 192 ret.rangeErrorMin = 0; 193 ret.rangeErrorMax = 3; 194 ret.type = seL4_RangeError; 195 } 196 return ret; 197} 198 199#endif /* CONFIG_HARDWARE_DEBUG_API */ 200 201#endif /* __ARCH_MACHINE_DEBUG_H_ */ 202