1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * arch/hexagon/kernel/kgdb.c - Hexagon KGDB Support 4 * 5 * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. 6 */ 7 8 #include <linux/irq.h> 9 #include <linux/sched.h> 10 #include <linux/sched/task_stack.h> 11 #include <linux/kdebug.h> 12 #include <linux/kgdb.h> 13 14 /* All registers are 4 bytes, for now */ 15 #define GDB_SIZEOF_REG 4 16 17 /* The register names are used during printing of the regs; 18 * Keep these at three letters to pretty-print. */ 19 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { 20 { " r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, r00)}, 21 { " r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, r01)}, 22 { " r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, r02)}, 23 { " r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, r03)}, 24 { " r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, r04)}, 25 { " r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, r05)}, 26 { " r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, r06)}, 27 { " r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, r07)}, 28 { " r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, r08)}, 29 { " r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, r09)}, 30 { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, r10)}, 31 { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, r11)}, 32 { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, r12)}, 33 { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, r13)}, 34 { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, r14)}, 35 { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, r15)}, 36 { "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, r16)}, 37 { "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, r17)}, 38 { "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, r18)}, 39 { "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, r19)}, 40 { "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, r20)}, 41 { "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, r21)}, 42 { "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, r22)}, 43 { "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, r23)}, 44 { "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, r24)}, 45 { "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, r25)}, 46 { "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, r26)}, 47 { "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, r27)}, 48 { "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, r28)}, 49 { "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, r29)}, 50 { "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, r30)}, 51 { "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, r31)}, 52 53 { "usr", GDB_SIZEOF_REG, offsetof(struct pt_regs, usr)}, 54 { "preds", GDB_SIZEOF_REG, offsetof(struct pt_regs, preds)}, 55 { " m0", GDB_SIZEOF_REG, offsetof(struct pt_regs, m0)}, 56 { " m1", GDB_SIZEOF_REG, offsetof(struct pt_regs, m1)}, 57 { "sa0", GDB_SIZEOF_REG, offsetof(struct pt_regs, sa0)}, 58 { "sa1", GDB_SIZEOF_REG, offsetof(struct pt_regs, sa1)}, 59 { "lc0", GDB_SIZEOF_REG, offsetof(struct pt_regs, lc0)}, 60 { "lc1", GDB_SIZEOF_REG, offsetof(struct pt_regs, lc1)}, 61 { " gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, gp)}, 62 { "ugp", GDB_SIZEOF_REG, offsetof(struct pt_regs, ugp)}, 63 { "cs0", GDB_SIZEOF_REG, offsetof(struct pt_regs, cs0)}, 64 { "cs1", GDB_SIZEOF_REG, offsetof(struct pt_regs, cs1)}, 65 { "psp", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmpsp)}, 66 { "elr", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmel)}, 67 { "est", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmest)}, 68 { "badva", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmbadva)}, 69 { "restart_r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, restart_r0)}, 70 { "syscall_nr", GDB_SIZEOF_REG, offsetof(struct pt_regs, syscall_nr)}, 71 }; 72 73 const struct kgdb_arch arch_kgdb_ops = { 74 /* trap0(#0xDB) 0x0cdb0054 */ 75 .gdb_bpt_instr = {0x54, 0x00, 0xdb, 0x0c}, 76 }; 77 78 char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) 79 { 80 if (regno >= DBG_MAX_REG_NUM || regno < 0) 81 return NULL; 82 83 *((unsigned long *) mem) = *((unsigned long *) ((void *)regs + 84 dbg_reg_def[regno].offset)); 85 86 return dbg_reg_def[regno].name; 87 } 88 89 int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) 90 { 91 if (regno >= DBG_MAX_REG_NUM || regno < 0) 92 return -EINVAL; 93 94 *((unsigned long *) ((void *)regs + dbg_reg_def[regno].offset)) = 95 *((unsigned long *) mem); 96 97 return 0; 98 } 99 100 void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) 101 { 102 instruction_pointer(regs) = pc; 103 } 104 105 106 /* Not yet working */ 107 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, 108 struct task_struct *task) 109 { 110 struct pt_regs *thread_regs; 111 112 if (task == NULL) 113 return; 114 115 /* Initialize to zero */ 116 memset(gdb_regs, 0, NUMREGBYTES); 117 118 /* Otherwise, we have only some registers from switch_to() */ 119 thread_regs = task_pt_regs(task); 120 gdb_regs[0] = thread_regs->r00; 121 } 122 123 /** 124 * kgdb_arch_handle_exception - Handle architecture specific GDB packets. 125 * @vector: The error vector of the exception that happened. 126 * @signo: The signal number of the exception that happened. 127 * @err_code: The error code of the exception that happened. 128 * @remcom_in_buffer: The buffer of the packet we have read. 129 * @remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into. 130 * @regs: The &struct pt_regs of the current process. 131 * 132 * This function MUST handle the 'c' and 's' command packets, 133 * as well packets to set / remove a hardware breakpoint, if used. 134 * If there are additional packets which the hardware needs to handle, 135 * they are handled here. The code should return -1 if it wants to 136 * process more packets, and a %0 or %1 if it wants to exit from the 137 * kgdb callback. 138 * 139 * Not yet working. 140 */ 141 int kgdb_arch_handle_exception(int vector, int signo, int err_code, 142 char *remcom_in_buffer, char *remcom_out_buffer, 143 struct pt_regs *linux_regs) 144 { 145 switch (remcom_in_buffer[0]) { 146 case 's': 147 case 'c': 148 return 0; 149 } 150 /* Stay in the debugger. */ 151 return -1; 152 } 153 154 static int __kgdb_notify(struct die_args *args, unsigned long cmd) 155 { 156 /* cpu roundup */ 157 if (atomic_read(&kgdb_active) != -1) { 158 kgdb_nmicallback(smp_processor_id(), args->regs); 159 return NOTIFY_STOP; 160 } 161 162 if (user_mode(args->regs)) 163 return NOTIFY_DONE; 164 165 if (kgdb_handle_exception(args->trapnr & 0xff, args->signr, args->err, 166 args->regs)) 167 return NOTIFY_DONE; 168 169 return NOTIFY_STOP; 170 } 171 172 static int 173 kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) 174 { 175 unsigned long flags; 176 int ret; 177 178 local_irq_save(flags); 179 ret = __kgdb_notify(ptr, cmd); 180 local_irq_restore(flags); 181 182 return ret; 183 } 184 185 static struct notifier_block kgdb_notifier = { 186 .notifier_call = kgdb_notify, 187 188 /* 189 * Lowest-prio notifier priority, we want to be notified last: 190 */ 191 .priority = -INT_MAX, 192 }; 193 194 /** 195 * kgdb_arch_init - Perform any architecture specific initialization. 196 * 197 * This function will handle the initialization of any architecture 198 * specific callbacks. 199 */ 200 int kgdb_arch_init(void) 201 { 202 return register_die_notifier(&kgdb_notifier); 203 } 204 205 /** 206 * kgdb_arch_exit - Perform any architecture specific uninitalization. 207 * 208 * This function will handle the uninitalization of any architecture 209 * specific callbacks, for dynamic registration and unregistration. 210 */ 211 void kgdb_arch_exit(void) 212 { 213 unregister_die_notifier(&kgdb_notifier); 214 } 215
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.