Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: KGDB: Add Basic KGDB support

Add KGDB debug support for kernel debugging.
With this patch, basic KGDB debugging is possible.GDB register
layout is updated and GDB tool can establish connection with
target and can set/clear breakpoints.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@caviumnetworks.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Vijaya Kumar K and committed by
Catalin Marinas
bcf5763b c7db4ff5

+420
+47
arch/arm64/include/asm/debug-monitors.h
··· 26 26 #define DBG_ESR_EVT_HWWP 0x2 27 27 #define DBG_ESR_EVT_BRK 0x6 28 28 29 + /* 30 + * Break point instruction encoding 31 + */ 32 + #define BREAK_INSTR_SIZE 4 33 + 34 + /* 35 + * ESR values expected for dynamic and compile time BRK instruction 36 + */ 37 + #define DBG_ESR_VAL_BRK(x) (0xf2000000 | ((x) & 0xfffff)) 38 + 39 + /* 40 + * #imm16 values used for BRK instruction generation 41 + * Allowed values for kgbd are 0x400 - 0x7ff 42 + * 0x400: for dynamic BRK instruction 43 + * 0x401: for compile time BRK instruction 44 + */ 45 + #define KGDB_DYN_DGB_BRK_IMM 0x400 46 + #define KDBG_COMPILED_DBG_BRK_IMM 0x401 47 + 48 + /* 49 + * BRK instruction encoding 50 + * The #imm16 value should be placed at bits[20:5] within BRK ins 51 + */ 52 + #define AARCH64_BREAK_MON 0xd4200000 53 + 54 + /* 55 + * Extract byte from BRK instruction 56 + */ 57 + #define KGDB_DYN_DGB_BRK_INS_BYTE(x) \ 58 + ((((AARCH64_BREAK_MON) & 0xffe0001f) >> (x * 8)) & 0xff) 59 + 60 + /* 61 + * Extract byte from BRK #imm16 62 + */ 63 + #define KGBD_DYN_DGB_BRK_IMM_BYTE(x) \ 64 + (((((KGDB_DYN_DGB_BRK_IMM) & 0xffff) << 5) >> (x * 8)) & 0xff) 65 + 66 + #define KGDB_DYN_DGB_BRK_BYTE(x) \ 67 + (KGDB_DYN_DGB_BRK_INS_BYTE(x) | KGBD_DYN_DGB_BRK_IMM_BYTE(x)) 68 + 69 + #define KGDB_DYN_BRK_INS_BYTE0 KGDB_DYN_DGB_BRK_BYTE(0) 70 + #define KGDB_DYN_BRK_INS_BYTE1 KGDB_DYN_DGB_BRK_BYTE(1) 71 + #define KGDB_DYN_BRK_INS_BYTE2 KGDB_DYN_DGB_BRK_BYTE(2) 72 + #define KGDB_DYN_BRK_INS_BYTE3 KGDB_DYN_DGB_BRK_BYTE(3) 73 + 74 + #define CACHE_FLUSH_IS_SAFE 1 75 + 29 76 enum debug_el { 30 77 DBG_ACTIVE_EL0 = 0, 31 78 DBG_ACTIVE_EL1,
+84
arch/arm64/include/asm/kgdb.h
··· 1 + /* 2 + * AArch64 KGDB support 3 + * 4 + * Based on arch/arm/include/kgdb.h 5 + * 6 + * Copyright (C) 2013 Cavium Inc. 7 + * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.com> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License version 2 as 11 + * published by the Free Software Foundation. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 + */ 21 + 22 + #ifndef __ARM_KGDB_H 23 + #define __ARM_KGDB_H 24 + 25 + #include <linux/ptrace.h> 26 + #include <asm/debug-monitors.h> 27 + 28 + #ifndef __ASSEMBLY__ 29 + 30 + static inline void arch_kgdb_breakpoint(void) 31 + { 32 + asm ("brk %0" : : "I" (KDBG_COMPILED_DBG_BRK_IMM)); 33 + } 34 + 35 + extern void kgdb_handle_bus_error(void); 36 + extern int kgdb_fault_expected; 37 + 38 + #endif /* !__ASSEMBLY__ */ 39 + 40 + /* 41 + * gdb is expecting the following registers layout. 42 + * 43 + * General purpose regs: 44 + * r0-r30: 64 bit 45 + * sp,pc : 64 bit 46 + * pstate : 64 bit 47 + * Total: 34 48 + * FPU regs: 49 + * f0-f31: 128 bit 50 + * Total: 32 51 + * Extra regs 52 + * fpsr & fpcr: 32 bit 53 + * Total: 2 54 + * 55 + */ 56 + 57 + #define _GP_REGS 34 58 + #define _FP_REGS 32 59 + #define _EXTRA_REGS 2 60 + /* 61 + * general purpose registers size in bytes. 62 + * pstate is only 4 bytes. subtract 4 bytes 63 + */ 64 + #define GP_REG_BYTES (_GP_REGS * 8) 65 + #define DBG_MAX_REG_NUM (_GP_REGS + _FP_REGS + _EXTRA_REGS) 66 + 67 + /* 68 + * Size of I/O buffer for gdb packet. 69 + * considering to hold all register contents, size is set 70 + */ 71 + 72 + #define BUFMAX 2048 73 + 74 + /* 75 + * Number of bytes required for gdb_regs buffer. 76 + * _GP_REGS: 8 bytes, _FP_REGS: 16 bytes and _EXTRA_REGS: 4 bytes each 77 + * GDB fails to connect for size beyond this with error 78 + * "'g' packet reply is too long" 79 + */ 80 + 81 + #define NUMREGBYTES ((_GP_REGS * 8) + (_FP_REGS * 16) + \ 82 + (_EXTRA_REGS * 4)) 83 + 84 + #endif /* __ASM_KGDB_H */
+1
arch/arm64/kernel/Makefile
··· 20 20 arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 21 21 arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o 22 22 arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o 23 + arm64-obj-$(CONFIG_KGDB) += kgdb.o 23 24 24 25 obj-y += $(arm64-obj-y) vdso/ 25 26 obj-m += $(arm64-obj-m)
+288
arch/arm64/kernel/kgdb.c
··· 1 + /* 2 + * AArch64 KGDB support 3 + * 4 + * Based on arch/arm/kernel/kgdb.c 5 + * 6 + * Copyright (C) 2013 Cavium Inc. 7 + * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.com> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License version 2 as 11 + * published by the Free Software Foundation. 12 + * 13 + * This program is distributed in the hope that it will be useful, 14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 + * GNU General Public License for more details. 17 + * 18 + * You should have received a copy of the GNU General Public License 19 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 + */ 21 + 22 + #include <linux/irq.h> 23 + #include <linux/kdebug.h> 24 + #include <linux/kgdb.h> 25 + #include <asm/traps.h> 26 + 27 + struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { 28 + { "x0", 8, offsetof(struct pt_regs, regs[0])}, 29 + { "x1", 8, offsetof(struct pt_regs, regs[1])}, 30 + { "x2", 8, offsetof(struct pt_regs, regs[2])}, 31 + { "x3", 8, offsetof(struct pt_regs, regs[3])}, 32 + { "x4", 8, offsetof(struct pt_regs, regs[4])}, 33 + { "x5", 8, offsetof(struct pt_regs, regs[5])}, 34 + { "x6", 8, offsetof(struct pt_regs, regs[6])}, 35 + { "x7", 8, offsetof(struct pt_regs, regs[7])}, 36 + { "x8", 8, offsetof(struct pt_regs, regs[8])}, 37 + { "x9", 8, offsetof(struct pt_regs, regs[9])}, 38 + { "x10", 8, offsetof(struct pt_regs, regs[10])}, 39 + { "x11", 8, offsetof(struct pt_regs, regs[11])}, 40 + { "x12", 8, offsetof(struct pt_regs, regs[12])}, 41 + { "x13", 8, offsetof(struct pt_regs, regs[13])}, 42 + { "x14", 8, offsetof(struct pt_regs, regs[14])}, 43 + { "x15", 8, offsetof(struct pt_regs, regs[15])}, 44 + { "x16", 8, offsetof(struct pt_regs, regs[16])}, 45 + { "x17", 8, offsetof(struct pt_regs, regs[17])}, 46 + { "x18", 8, offsetof(struct pt_regs, regs[18])}, 47 + { "x19", 8, offsetof(struct pt_regs, regs[19])}, 48 + { "x20", 8, offsetof(struct pt_regs, regs[20])}, 49 + { "x21", 8, offsetof(struct pt_regs, regs[21])}, 50 + { "x22", 8, offsetof(struct pt_regs, regs[22])}, 51 + { "x23", 8, offsetof(struct pt_regs, regs[23])}, 52 + { "x24", 8, offsetof(struct pt_regs, regs[24])}, 53 + { "x25", 8, offsetof(struct pt_regs, regs[25])}, 54 + { "x26", 8, offsetof(struct pt_regs, regs[26])}, 55 + { "x27", 8, offsetof(struct pt_regs, regs[27])}, 56 + { "x28", 8, offsetof(struct pt_regs, regs[28])}, 57 + { "x29", 8, offsetof(struct pt_regs, regs[29])}, 58 + { "x30", 8, offsetof(struct pt_regs, regs[30])}, 59 + { "sp", 8, offsetof(struct pt_regs, sp)}, 60 + { "pc", 8, offsetof(struct pt_regs, pc)}, 61 + { "pstate", 8, offsetof(struct pt_regs, pstate)}, 62 + { "v0", 16, -1 }, 63 + { "v1", 16, -1 }, 64 + { "v2", 16, -1 }, 65 + { "v3", 16, -1 }, 66 + { "v4", 16, -1 }, 67 + { "v5", 16, -1 }, 68 + { "v6", 16, -1 }, 69 + { "v7", 16, -1 }, 70 + { "v8", 16, -1 }, 71 + { "v9", 16, -1 }, 72 + { "v10", 16, -1 }, 73 + { "v11", 16, -1 }, 74 + { "v12", 16, -1 }, 75 + { "v13", 16, -1 }, 76 + { "v14", 16, -1 }, 77 + { "v15", 16, -1 }, 78 + { "v16", 16, -1 }, 79 + { "v17", 16, -1 }, 80 + { "v18", 16, -1 }, 81 + { "v19", 16, -1 }, 82 + { "v20", 16, -1 }, 83 + { "v21", 16, -1 }, 84 + { "v22", 16, -1 }, 85 + { "v23", 16, -1 }, 86 + { "v24", 16, -1 }, 87 + { "v25", 16, -1 }, 88 + { "v26", 16, -1 }, 89 + { "v27", 16, -1 }, 90 + { "v28", 16, -1 }, 91 + { "v29", 16, -1 }, 92 + { "v30", 16, -1 }, 93 + { "v31", 16, -1 }, 94 + { "fpsr", 4, -1 }, 95 + { "fpcr", 4, -1 }, 96 + }; 97 + 98 + char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) 99 + { 100 + if (regno >= DBG_MAX_REG_NUM || regno < 0) 101 + return NULL; 102 + 103 + if (dbg_reg_def[regno].offset != -1) 104 + memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, 105 + dbg_reg_def[regno].size); 106 + else 107 + memset(mem, 0, dbg_reg_def[regno].size); 108 + return dbg_reg_def[regno].name; 109 + } 110 + 111 + int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) 112 + { 113 + if (regno >= DBG_MAX_REG_NUM || regno < 0) 114 + return -EINVAL; 115 + 116 + if (dbg_reg_def[regno].offset != -1) 117 + memcpy((void *)regs + dbg_reg_def[regno].offset, mem, 118 + dbg_reg_def[regno].size); 119 + return 0; 120 + } 121 + 122 + void 123 + sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) 124 + { 125 + struct pt_regs *thread_regs; 126 + 127 + /* Initialize to zero */ 128 + memset((char *)gdb_regs, 0, NUMREGBYTES); 129 + thread_regs = task_pt_regs(task); 130 + memcpy((void *)gdb_regs, (void *)thread_regs->regs, GP_REG_BYTES); 131 + } 132 + 133 + void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) 134 + { 135 + regs->pc = pc; 136 + } 137 + 138 + static int compiled_break; 139 + 140 + int kgdb_arch_handle_exception(int exception_vector, int signo, 141 + int err_code, char *remcom_in_buffer, 142 + char *remcom_out_buffer, 143 + struct pt_regs *linux_regs) 144 + { 145 + unsigned long addr; 146 + char *ptr; 147 + int err; 148 + 149 + switch (remcom_in_buffer[0]) { 150 + case 'D': 151 + case 'k': 152 + /* 153 + * Packet D (Detach), k (kill). No special handling 154 + * is required here. Handle same as c packet. 155 + */ 156 + case 'c': 157 + /* 158 + * Packet c (Continue) to continue executing. 159 + * Set pc to required address. 160 + * Try to read optional parameter and set pc. 161 + * If this was a compiled breakpoint, we need to move 162 + * to the next instruction else we will just breakpoint 163 + * over and over again. 164 + */ 165 + ptr = &remcom_in_buffer[1]; 166 + if (kgdb_hex2long(&ptr, &addr)) 167 + kgdb_arch_set_pc(linux_regs, addr); 168 + else if (compiled_break == 1) 169 + kgdb_arch_set_pc(linux_regs, linux_regs->pc + 4); 170 + 171 + compiled_break = 0; 172 + err = 0; 173 + break; 174 + default: 175 + err = -1; 176 + } 177 + return err; 178 + } 179 + 180 + static int kgdb_brk_fn(struct pt_regs *regs, unsigned int esr) 181 + { 182 + kgdb_handle_exception(1, SIGTRAP, 0, regs); 183 + return 0; 184 + } 185 + 186 + static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr) 187 + { 188 + compiled_break = 1; 189 + kgdb_handle_exception(1, SIGTRAP, 0, regs); 190 + 191 + return 0; 192 + } 193 + 194 + static struct break_hook kgdb_brkpt_hook = { 195 + .esr_mask = 0xffffffff, 196 + .esr_val = DBG_ESR_VAL_BRK(KGDB_DYN_DGB_BRK_IMM), 197 + .fn = kgdb_brk_fn 198 + }; 199 + 200 + static struct break_hook kgdb_compiled_brkpt_hook = { 201 + .esr_mask = 0xffffffff, 202 + .esr_val = DBG_ESR_VAL_BRK(KDBG_COMPILED_DBG_BRK_IMM), 203 + .fn = kgdb_compiled_brk_fn 204 + }; 205 + 206 + static void kgdb_call_nmi_hook(void *ignored) 207 + { 208 + kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs()); 209 + } 210 + 211 + void kgdb_roundup_cpus(unsigned long flags) 212 + { 213 + local_irq_enable(); 214 + smp_call_function(kgdb_call_nmi_hook, NULL, 0); 215 + local_irq_disable(); 216 + } 217 + 218 + static int __kgdb_notify(struct die_args *args, unsigned long cmd) 219 + { 220 + struct pt_regs *regs = args->regs; 221 + 222 + if (kgdb_handle_exception(1, args->signr, cmd, regs)) 223 + return NOTIFY_DONE; 224 + return NOTIFY_STOP; 225 + } 226 + 227 + static int 228 + kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) 229 + { 230 + unsigned long flags; 231 + int ret; 232 + 233 + local_irq_save(flags); 234 + ret = __kgdb_notify(ptr, cmd); 235 + local_irq_restore(flags); 236 + 237 + return ret; 238 + } 239 + 240 + static struct notifier_block kgdb_notifier = { 241 + .notifier_call = kgdb_notify, 242 + /* 243 + * Want to be lowest priority 244 + */ 245 + .priority = -INT_MAX, 246 + }; 247 + 248 + /* 249 + * kgdb_arch_init - Perform any architecture specific initalization. 250 + * This function will handle the initalization of any architecture 251 + * specific callbacks. 252 + */ 253 + int kgdb_arch_init(void) 254 + { 255 + int ret = register_die_notifier(&kgdb_notifier); 256 + 257 + if (ret != 0) 258 + return ret; 259 + 260 + register_break_hook(&kgdb_brkpt_hook); 261 + register_break_hook(&kgdb_compiled_brkpt_hook); 262 + return 0; 263 + } 264 + 265 + /* 266 + * kgdb_arch_exit - Perform any architecture specific uninitalization. 267 + * This function will handle the uninitalization of any architecture 268 + * specific callbacks, for dynamic registration and unregistration. 269 + */ 270 + void kgdb_arch_exit(void) 271 + { 272 + unregister_break_hook(&kgdb_brkpt_hook); 273 + unregister_break_hook(&kgdb_compiled_brkpt_hook); 274 + unregister_die_notifier(&kgdb_notifier); 275 + } 276 + 277 + /* 278 + * ARM instructions are always in LE. 279 + * Break instruction is encoded in LE format 280 + */ 281 + struct kgdb_arch arch_kgdb_ops = { 282 + .gdb_bpt_instr = { 283 + KGDB_DYN_BRK_INS_BYTE0, 284 + KGDB_DYN_BRK_INS_BYTE1, 285 + KGDB_DYN_BRK_INS_BYTE2, 286 + KGDB_DYN_BRK_INS_BYTE3, 287 + } 288 + };