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#ifdef CONFIG_HARDWARE_DEBUG_API 18 19#define DBGVCR_RESERVED_BITS_MASK (0xFFFFFFF0|BIT(5)) 20 21enum v6_breakpoint_meaning /* BCR[22:21] */ { 22 DBGBCR_V6MEANING_INSTRUCTION_VADDR_MATCH = 0u, 23 DBGBCR_V6MEANING_CONTEXT_ID_MATCH = 1u, 24 DBGBCR_V6MEANING_INSTRUCTION_VADDR_MISMATCH = 2u 25}; 26 27/** Read DBGDSCR from CP14. 28 * 29 * DBGDSCR_ext (external view) is not exposed on debug v6. Accessing it on 30 * v6 triggers an #UNDEFINED abort. 31 */ 32static word_t 33readDscrCp(void) 34{ 35 word_t v; 36 37 MRC(DBGDSCR_int, v); 38 return v; 39} 40 41/** Write DBGDSCR (Status and control register). 42 * 43 * On ARMv6, there is no mmapping, and the coprocessor doesn't expose an 44 * external vs internal view of DSCR. There's only the internal, but the MDBGEn 45 * but is RW (as opposed to V7 where the internal MDBGEn is RO). 46 * 47 * Even so, the KZM still ignores our writes anyway *shrug*. 48 */ 49static void 50writeDscrCp(word_t val) 51{ 52 MCR(DBGDSCR_int, val); 53} 54 55/** Determines whether or not 8-byte watchpoints are supported. 56 */ 57static inline bool_t 58watchpoint8bSupported(void) 59{ 60 /* V6 doesn't support 8B watchpoints. */ 61 return false; 62} 63 64/** Enables the debug architecture mode that allows us to receive debug events 65 * as exceptions. 66 * 67 * CPU can operate in one of 2 debug architecture modes: "halting" and 68 * "monitor". In halting mode, when a debug event occurs, the CPU will halt 69 * execution and enter a special state in which it can be examined by an 70 * external debugger dongle. 71 * 72 * In monitor mode, the CPU will deliver debug events to the kernel as 73 * exceptions. Monitor mode is what's actually useful to us. If it's not 74 * supported by the CPU, it's impossible for the API to work. 75 * 76 * Unfortunately, it's also gated behind a hardware pin signal, #DBGEN. If 77 * #DBGEN is held low, monitor mode is unavailable. 78 */ 79BOOT_CODE static bool_t 80enableMonitorMode(void) 81{ 82 dbg_dscr_t dscr; 83 84 dscr.words[0] = readDscrCp(); 85 /* HDBGEn is read-only on v6 debug. */ 86 if (dbg_dscr_get_haltingDebugEnable(dscr) != 0) { 87 printf("Halting debug is enabled, and can't be disabled. Monitor mode " 88 "unavailable.\n"); 89 return false; 90 } 91 92 dscr = dbg_dscr_set_monitorDebugEnable(dscr, 1); 93 writeDscrCp(dscr.words[0]); 94 isb(); 95 96 /* On V6 debug, we can tell if the #DBGEN signal is enabled by setting 97 * the DBGDSCR.MDBGEn bit. If the #DBGEN signal is not enabled, writes 98 * to DBGDSCR.MDBGEn will be ignored, and it will always read as zero. 99 * 100 * We test here to see if the DBGDSCR.MDBGEn bit is still 0, even after 101 * we set it to 1 in enableMonitorMode(). 102 * 103 * ARMv6 manual, sec D3.3.2, "Monitor debug-mode enable, bit[15]": 104 * 105 * "Monitor debug-mode has to be both selected and enabled (bit 14 106 * clear and bit 15 set) for the core to take a Debug exception." 107 * 108 * "If the external interface input DBGEN is low, DSCR[15:14] reads as 109 * 0b00. The programmed value is masked until DBGEN is taken high, at 110 * which time value is read and behavior reverts to the programmed 111 * value." 112 */ 113 /* Re-read the value */ 114 dscr.words[0] = readDscrCp(); 115 if (dbg_dscr_get_monitorDebugEnable(dscr) == 0) { 116 printf("#DBGEN signal held low. Monitor mode unavailable.\n"); 117 return false; 118 } 119 return true; 120} 121 122static inline dbg_bcr_t 123Arch_setupBcr(dbg_bcr_t in_val, bool_t is_match) 124{ 125 dbg_bcr_t bcr; 126 127 if (is_match) { 128 bcr = dbg_bcr_set_meaning(in_val, DBGBCR_V6MEANING_INSTRUCTION_VADDR_MATCH); 129 } else { 130 bcr = dbg_bcr_set_meaning(in_val, DBGBCR_V6MEANING_INSTRUCTION_VADDR_MISMATCH); 131 } 132 bcr = dbg_bcr_set_enableLinking(bcr, 0); 133 return bcr; 134} 135 136static inline dbg_wcr_t 137Arch_setupWcr(dbg_wcr_t in_val) 138{ 139 return in_val; 140} 141 142static inline bool_t 143Arch_breakpointIsMismatch(dbg_bcr_t in_val) 144{ 145 return dbg_bcr_get_meaning(in_val) == DBGBCR_V6MEANING_INSTRUCTION_VADDR_MISMATCH; 146} 147 148#endif /* CONFIG_HARDWARE_DEBUG_API */ 149#endif /* __ARCH_ARMV_DEBUG_H_ */ 150