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