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_ARMV_DEBUG_H_ 14#define __ARCH_ARMV_DEBUG_H_ 15 16#include <config.h> 17 18#if defined(CONFIG_HARDWARE_DEBUG_API) || defined(CONFIG_EXPORT_PMU_USER) 19 20#include <mode/machine/debug.h> 21#include <mode/machine.h> /* MRC/MCR */ 22 23/** Read DBGDSCR from CP14. 24 */ 25static inline word_t 26readDscrCp(void) 27{ 28 word_t v; 29 30 MRC(DBGDSCR_ext, v); 31 return v; 32} 33 34/** Write DBGDSCR (Status and control register). 35 * On ARMv7, the external view of the CP14 DBGDSCR register is preferred since 36 * the internal view is fully read-only. 37 */ 38static inline void 39writeDscrCp(word_t val) 40{ 41 MCR(DBGDSCR_ext, val); 42} 43#endif /* CONFIG_HARDWARE_DEBUG_API CONFIG_EXPORT_PMU_USER */ 44 45#ifdef CONFIG_HARDWARE_DEBUG_API 46#define DBGVCR_RESERVED_BITS_MASK \ 47 (BIT(5)|BIT(8)|BIT(9)|BIT(13)|BIT(16)|BIT(24)|BIT(29)) 48 49#define DBGWCR_BAS_HIGH_SHIFT (9u) 50#define DBGWCR_0 "p14,0,%0,c0,c0,7" 51 52enum v7_breakpoint_type { 53 DBGBCR_TYPE_UNLINKED_INSTRUCTION_MATCH = 0u, 54 DBGBCR_TYPE_LINKED_INSTRUCTION_MATCH = 0x1u, 55 DBGBCR_TYPE_UNLINKED_CONTEXT_MATCH = 0x2u, 56 DBGBCR_TYPE_LINKED_CONTEXT_MATCH = 0x3u, 57 58 DBGBCR_TYPE_UNLINKED_INSTRUCTION_MISMATCH = 0x4u, 59 DBGBCR_TYPE_LINKED_INSTRUCTION_MISMATCH = 0x5u, 60 61 DBGBCR_TYPE_UNLINKED_VMID_MATCH = 0x8u, 62 DBGBCR_TYPE_LINKED_VMID_MATCH = 0x9u, 63 DBGBCR_TYPE_UNLINKED_VMID_AND_CONTEXT_MATCH = 0xAu, 64 DBGBCR_TYPE_LINKED_VMID_AND_CONTEXT_MATCH = 0xBu 65}; 66 67 68/** Determines whether or not 8-byte watchpoints are supported. 69 * 70 * Checks to see if the 8-byte byte-address-select high bits ignore writes. 71 */ 72static inline bool_t 73watchpoint8bSupported(void) 74{ 75 word_t wcrtmp; 76 77 /* ARMv7 manual: C11.11.44: 78 * "A 4-bit Byte address select field is DBGWCR[8:5]. DBGWCR[12:9] is RAZ/WI." 79 * 80 * So if 8-byte WPs aren't supported, then the higher 4-bits of the BAS 81 * field will be RAZ/WI. We can just test the first WP's BAS bits and see 82 * what happens. 83 */ 84 MRC(DBGWCR_0, wcrtmp); 85 wcrtmp |= BIT(DBGWCR_BAS_HIGH_SHIFT); 86 MCR(DBGWCR_0, wcrtmp); 87 88 /* Re-read to know if the write to the bit was ignored */ 89 MRC(DBGWCR_0, wcrtmp); 90 return wcrtmp & BIT(DBGWCR_BAS_HIGH_SHIFT); 91} 92 93/** Enables the debug architecture mode that allows us to receive debug events 94 * as exceptions. 95 * 96 * CPU can operate in one of 2 debug architecture modes: "halting" and 97 * "monitor". In halting mode, when a debug event occurs, the CPU will halt 98 * execution and enter a special state in which it can be examined by an 99 * external debugger dongle. 100 * 101 * In monitor mode, the CPU will deliver debug events to the kernel as 102 * exceptions. Monitor mode is what's actually useful to us. If it's not 103 * supported by the CPU, it's impossible for the API to work. 104 * 105 * Unfortunately, it's also gated behind a hardware pin signal, #DBGEN. If 106 * #DBGEN is held low, monitor mode is unavailable. 107 */ 108BOOT_CODE static bool_t 109enableMonitorMode(void) 110{ 111 dbg_dscr_t dscr; 112 113 dscr.words[0] = readDscrCp(); 114 dscr = dbg_dscr_set_haltingDebugEnable(dscr, 0); 115 dscr = dbg_dscr_set_disableAllUserAccesses(dscr, 1); 116 dscr = dbg_dscr_set_monitorDebugEnable(dscr, 1); 117 118 writeDscrCp(dscr.words[0]); 119 isb(); 120 121 /* We can tell if the #DBGEN signal is enabled by setting 122 * the DBGDSCR.MDBGEn bit. If the #DBGEN signal is not enabled, writes 123 * to DBGDSCR.MDBGEn will be ignored, and it will always read as zero. 124 * 125 * We test here to see if the DBGDSCR.MDBGEn bit is still 0, even after 126 * we set it to 1 in enableMonitorMode(). 127 * 128 * ARMv6 manual, sec D3.3.2, "Monitor debug-mode enable, bit[15]": 129 * 130 * "Monitor debug-mode has to be both selected and enabled (bit 14 131 * clear and bit 15 set) for the core to take a Debug exception." 132 * 133 * "If the external interface input DBGEN is low, DSCR[15:14] reads as 134 * 0b00. The programmed value is masked until DBGEN is taken high, at 135 * which time value is read and behavior reverts to the programmed 136 * value." 137 */ 138 /* Re-read the value */ 139 dscr.words[0] = readDscrCp(); 140 if (dbg_dscr_get_monitorDebugEnable(dscr) == 0) { 141 printf("#DBGEN signal held low. Monitor mode unavailable.\n"); 142 return false; 143 } 144 return true; 145} 146 147static inline dbg_bcr_t 148Arch_setupBcr(dbg_bcr_t in_val, bool_t is_match) 149{ 150 dbg_bcr_t bcr; 151 152 bcr = dbg_bcr_set_addressMask(in_val, 0); 153 bcr = dbg_bcr_set_hypeModeControl(bcr, 0); 154 bcr = dbg_bcr_set_secureStateControl(bcr, 0); 155 if (is_match) { 156 bcr = dbg_bcr_set_breakpointType(bcr, DBGBCR_TYPE_UNLINKED_INSTRUCTION_MATCH); 157 } else { 158 bcr = dbg_bcr_set_breakpointType(bcr, DBGBCR_TYPE_UNLINKED_INSTRUCTION_MISMATCH); 159 } 160 return bcr; 161} 162 163static inline dbg_wcr_t 164Arch_setupWcr(dbg_wcr_t in_val) 165{ 166 dbg_wcr_t wcr; 167 168 wcr = dbg_wcr_set_addressMask(in_val, 0); 169 wcr = dbg_wcr_set_hypeModeControl(wcr, 0); 170 wcr = dbg_wcr_set_secureStateControl(wcr, 0); 171 return wcr; 172} 173 174static inline bool_t 175Arch_breakpointIsMismatch(dbg_bcr_t in_val) 176{ 177 /* Detect if the register is set up for mismatch (single-step). */ 178 if (dbg_bcr_get_breakpointType(in_val) == DBGBCR_TYPE_UNLINKED_INSTRUCTION_MISMATCH) { 179 return true; 180 } 181 return false; 182} 183 184#endif /* CONFIG_HARDWARE_DEBUG_API */ 185#endif /* __ARCH_ARMV_DEBUG_H_ */ 186