1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
25cbad0ebSJason Wessel /*
35cbad0ebSJason Wessel * arch/arm/kernel/kgdb.c
45cbad0ebSJason Wessel *
55cbad0ebSJason Wessel * ARM KGDB support
65cbad0ebSJason Wessel *
75cbad0ebSJason Wessel * Copyright (c) 2002-2004 MontaVista Software, Inc
85cbad0ebSJason Wessel * Copyright (c) 2008 Wind River Systems, Inc.
95cbad0ebSJason Wessel *
105cbad0ebSJason Wessel * Authors: George Davis <davis_g@mvista.com>
115cbad0ebSJason Wessel * Deepak Saxena <dsaxena@plexity.net>
125cbad0ebSJason Wessel */
135d8614ccSWill Deacon #include <linux/irq.h>
1462a0309cSJason Wessel #include <linux/kdebug.h>
155cbad0ebSJason Wessel #include <linux/kgdb.h>
1623a4e405SDoug Anderson #include <linux/uaccess.h>
1723a4e405SDoug Anderson
18fca08f32SWang Nan #include <asm/patch.h>
195cbad0ebSJason Wessel #include <asm/traps.h>
205cbad0ebSJason Wessel
2122eeef4bSJason Wessel struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
225cbad0ebSJason Wessel {
2322eeef4bSJason Wessel { "r0", 4, offsetof(struct pt_regs, ARM_r0)},
2422eeef4bSJason Wessel { "r1", 4, offsetof(struct pt_regs, ARM_r1)},
2522eeef4bSJason Wessel { "r2", 4, offsetof(struct pt_regs, ARM_r2)},
2622eeef4bSJason Wessel { "r3", 4, offsetof(struct pt_regs, ARM_r3)},
2722eeef4bSJason Wessel { "r4", 4, offsetof(struct pt_regs, ARM_r4)},
2822eeef4bSJason Wessel { "r5", 4, offsetof(struct pt_regs, ARM_r5)},
2922eeef4bSJason Wessel { "r6", 4, offsetof(struct pt_regs, ARM_r6)},
3022eeef4bSJason Wessel { "r7", 4, offsetof(struct pt_regs, ARM_r7)},
3122eeef4bSJason Wessel { "r8", 4, offsetof(struct pt_regs, ARM_r8)},
3222eeef4bSJason Wessel { "r9", 4, offsetof(struct pt_regs, ARM_r9)},
3322eeef4bSJason Wessel { "r10", 4, offsetof(struct pt_regs, ARM_r10)},
3422eeef4bSJason Wessel { "fp", 4, offsetof(struct pt_regs, ARM_fp)},
3522eeef4bSJason Wessel { "ip", 4, offsetof(struct pt_regs, ARM_ip)},
3622eeef4bSJason Wessel { "sp", 4, offsetof(struct pt_regs, ARM_sp)},
3722eeef4bSJason Wessel { "lr", 4, offsetof(struct pt_regs, ARM_lr)},
3822eeef4bSJason Wessel { "pc", 4, offsetof(struct pt_regs, ARM_pc)},
3922eeef4bSJason Wessel { "f0", 12, -1 },
4022eeef4bSJason Wessel { "f1", 12, -1 },
4122eeef4bSJason Wessel { "f2", 12, -1 },
4222eeef4bSJason Wessel { "f3", 12, -1 },
4322eeef4bSJason Wessel { "f4", 12, -1 },
4422eeef4bSJason Wessel { "f5", 12, -1 },
4522eeef4bSJason Wessel { "f6", 12, -1 },
4622eeef4bSJason Wessel { "f7", 12, -1 },
4722eeef4bSJason Wessel { "fps", 4, -1 },
4822eeef4bSJason Wessel { "cpsr", 4, offsetof(struct pt_regs, ARM_cpsr)},
4922eeef4bSJason Wessel };
505cbad0ebSJason Wessel
dbg_get_reg(int regno,void * mem,struct pt_regs * regs)5122eeef4bSJason Wessel char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
5222eeef4bSJason Wessel {
5322eeef4bSJason Wessel if (regno >= DBG_MAX_REG_NUM || regno < 0)
5422eeef4bSJason Wessel return NULL;
555cbad0ebSJason Wessel
5622eeef4bSJason Wessel if (dbg_reg_def[regno].offset != -1)
5722eeef4bSJason Wessel memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
5822eeef4bSJason Wessel dbg_reg_def[regno].size);
5922eeef4bSJason Wessel else
6022eeef4bSJason Wessel memset(mem, 0, dbg_reg_def[regno].size);
6122eeef4bSJason Wessel return dbg_reg_def[regno].name;
625cbad0ebSJason Wessel }
635cbad0ebSJason Wessel
dbg_set_reg(int regno,void * mem,struct pt_regs * regs)6422eeef4bSJason Wessel int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
655cbad0ebSJason Wessel {
6622eeef4bSJason Wessel if (regno >= DBG_MAX_REG_NUM || regno < 0)
6722eeef4bSJason Wessel return -EINVAL;
6822eeef4bSJason Wessel
6922eeef4bSJason Wessel if (dbg_reg_def[regno].offset != -1)
7022eeef4bSJason Wessel memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
7122eeef4bSJason Wessel dbg_reg_def[regno].size);
7222eeef4bSJason Wessel return 0;
735cbad0ebSJason Wessel }
745cbad0ebSJason Wessel
755cbad0ebSJason Wessel void
sleeping_thread_to_gdb_regs(unsigned long * gdb_regs,struct task_struct * task)765cbad0ebSJason Wessel sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
775cbad0ebSJason Wessel {
78001bf455SDoug Anderson struct thread_info *ti;
795cbad0ebSJason Wessel int regno;
805cbad0ebSJason Wessel
815cbad0ebSJason Wessel /* Just making sure... */
825cbad0ebSJason Wessel if (task == NULL)
835cbad0ebSJason Wessel return;
845cbad0ebSJason Wessel
855cbad0ebSJason Wessel /* Initialize to zero */
86834b2964SRabin Vincent for (regno = 0; regno < GDB_MAX_REGS; regno++)
875cbad0ebSJason Wessel gdb_regs[regno] = 0;
885cbad0ebSJason Wessel
895cbad0ebSJason Wessel /* Otherwise, we have only some registers from switch_to() */
90001bf455SDoug Anderson ti = task_thread_info(task);
91001bf455SDoug Anderson gdb_regs[_R4] = ti->cpu_context.r4;
92001bf455SDoug Anderson gdb_regs[_R5] = ti->cpu_context.r5;
93001bf455SDoug Anderson gdb_regs[_R6] = ti->cpu_context.r6;
94001bf455SDoug Anderson gdb_regs[_R7] = ti->cpu_context.r7;
95001bf455SDoug Anderson gdb_regs[_R8] = ti->cpu_context.r8;
96001bf455SDoug Anderson gdb_regs[_R9] = ti->cpu_context.r9;
97001bf455SDoug Anderson gdb_regs[_R10] = ti->cpu_context.sl;
98001bf455SDoug Anderson gdb_regs[_FP] = ti->cpu_context.fp;
99001bf455SDoug Anderson gdb_regs[_SPT] = ti->cpu_context.sp;
100001bf455SDoug Anderson gdb_regs[_PC] = ti->cpu_context.pc;
1015cbad0ebSJason Wessel }
1025cbad0ebSJason Wessel
kgdb_arch_set_pc(struct pt_regs * regs,unsigned long pc)103dcc78711SJason Wessel void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
104dcc78711SJason Wessel {
105dcc78711SJason Wessel regs->ARM_pc = pc;
106dcc78711SJason Wessel }
107dcc78711SJason Wessel
1085cbad0ebSJason Wessel static int compiled_break;
1095cbad0ebSJason Wessel
kgdb_arch_handle_exception(int exception_vector,int signo,int err_code,char * remcom_in_buffer,char * remcom_out_buffer,struct pt_regs * linux_regs)1105cbad0ebSJason Wessel int kgdb_arch_handle_exception(int exception_vector, int signo,
1115cbad0ebSJason Wessel int err_code, char *remcom_in_buffer,
1125cbad0ebSJason Wessel char *remcom_out_buffer,
1135cbad0ebSJason Wessel struct pt_regs *linux_regs)
1145cbad0ebSJason Wessel {
1155cbad0ebSJason Wessel unsigned long addr;
1165cbad0ebSJason Wessel char *ptr;
1175cbad0ebSJason Wessel
1185cbad0ebSJason Wessel switch (remcom_in_buffer[0]) {
1195cbad0ebSJason Wessel case 'D':
1205cbad0ebSJason Wessel case 'k':
1215cbad0ebSJason Wessel case 'c':
1225cbad0ebSJason Wessel /*
1235cbad0ebSJason Wessel * Try to read optional parameter, pc unchanged if no parm.
1245cbad0ebSJason Wessel * If this was a compiled breakpoint, we need to move
1255cbad0ebSJason Wessel * to the next instruction or we will just breakpoint
1265cbad0ebSJason Wessel * over and over again.
1275cbad0ebSJason Wessel */
1285cbad0ebSJason Wessel ptr = &remcom_in_buffer[1];
1295cbad0ebSJason Wessel if (kgdb_hex2long(&ptr, &addr))
1305cbad0ebSJason Wessel linux_regs->ARM_pc = addr;
1315cbad0ebSJason Wessel else if (compiled_break == 1)
1325cbad0ebSJason Wessel linux_regs->ARM_pc += 4;
1335cbad0ebSJason Wessel
1345cbad0ebSJason Wessel compiled_break = 0;
1355cbad0ebSJason Wessel
1365cbad0ebSJason Wessel return 0;
1375cbad0ebSJason Wessel }
1385cbad0ebSJason Wessel
1395cbad0ebSJason Wessel return -1;
1405cbad0ebSJason Wessel }
1415cbad0ebSJason Wessel
kgdb_brk_fn(struct pt_regs * regs,unsigned int instr)1425cbad0ebSJason Wessel static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr)
1435cbad0ebSJason Wessel {
1445cbad0ebSJason Wessel kgdb_handle_exception(1, SIGTRAP, 0, regs);
1455cbad0ebSJason Wessel
1465cbad0ebSJason Wessel return 0;
1475cbad0ebSJason Wessel }
1485cbad0ebSJason Wessel
kgdb_compiled_brk_fn(struct pt_regs * regs,unsigned int instr)1495cbad0ebSJason Wessel static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr)
1505cbad0ebSJason Wessel {
1515cbad0ebSJason Wessel compiled_break = 1;
1525cbad0ebSJason Wessel kgdb_handle_exception(1, SIGTRAP, 0, regs);
1535cbad0ebSJason Wessel
1545cbad0ebSJason Wessel return 0;
1555cbad0ebSJason Wessel }
1565cbad0ebSJason Wessel
157*d920eaa4SRussell King (Oracle) static struct undef_hook kgdb_brkpt_arm_hook = {
1585cbad0ebSJason Wessel .instr_mask = 0xffffffff,
1595cbad0ebSJason Wessel .instr_val = KGDB_BREAKINST,
160*d920eaa4SRussell King (Oracle) .cpsr_mask = PSR_T_BIT | MODE_MASK,
1616bf755dbSOmar Sandoval .cpsr_val = SVC_MODE,
1625cbad0ebSJason Wessel .fn = kgdb_brk_fn
1635cbad0ebSJason Wessel };
1645cbad0ebSJason Wessel
165*d920eaa4SRussell King (Oracle) static struct undef_hook kgdb_brkpt_thumb_hook = {
166*d920eaa4SRussell King (Oracle) .instr_mask = 0xffff,
167*d920eaa4SRussell King (Oracle) .instr_val = KGDB_BREAKINST & 0xffff,
168*d920eaa4SRussell King (Oracle) .cpsr_mask = PSR_T_BIT | MODE_MASK,
169*d920eaa4SRussell King (Oracle) .cpsr_val = PSR_T_BIT | SVC_MODE,
170*d920eaa4SRussell King (Oracle) .fn = kgdb_brk_fn
171*d920eaa4SRussell King (Oracle) };
172*d920eaa4SRussell King (Oracle)
173*d920eaa4SRussell King (Oracle) static struct undef_hook kgdb_compiled_brkpt_arm_hook = {
1745cbad0ebSJason Wessel .instr_mask = 0xffffffff,
1755cbad0ebSJason Wessel .instr_val = KGDB_COMPILED_BREAK,
176*d920eaa4SRussell King (Oracle) .cpsr_mask = PSR_T_BIT | MODE_MASK,
1776bf755dbSOmar Sandoval .cpsr_val = SVC_MODE,
1785cbad0ebSJason Wessel .fn = kgdb_compiled_brk_fn
1795cbad0ebSJason Wessel };
1805cbad0ebSJason Wessel
181*d920eaa4SRussell King (Oracle) static struct undef_hook kgdb_compiled_brkpt_thumb_hook = {
182*d920eaa4SRussell King (Oracle) .instr_mask = 0xffff,
183*d920eaa4SRussell King (Oracle) .instr_val = KGDB_COMPILED_BREAK & 0xffff,
184*d920eaa4SRussell King (Oracle) .cpsr_mask = PSR_T_BIT | MODE_MASK,
185*d920eaa4SRussell King (Oracle) .cpsr_val = PSR_T_BIT | SVC_MODE,
186*d920eaa4SRussell King (Oracle) .fn = kgdb_compiled_brk_fn
187*d920eaa4SRussell King (Oracle) };
188*d920eaa4SRussell King (Oracle)
__kgdb_notify(struct die_args * args,unsigned long cmd)18962a0309cSJason Wessel static int __kgdb_notify(struct die_args *args, unsigned long cmd)
19062a0309cSJason Wessel {
19162a0309cSJason Wessel struct pt_regs *regs = args->regs;
19262a0309cSJason Wessel
19362a0309cSJason Wessel if (kgdb_handle_exception(1, args->signr, cmd, regs))
19462a0309cSJason Wessel return NOTIFY_DONE;
19562a0309cSJason Wessel return NOTIFY_STOP;
19662a0309cSJason Wessel }
19762a0309cSJason Wessel static int
kgdb_notify(struct notifier_block * self,unsigned long cmd,void * ptr)19862a0309cSJason Wessel kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
19962a0309cSJason Wessel {
20062a0309cSJason Wessel unsigned long flags;
20162a0309cSJason Wessel int ret;
20262a0309cSJason Wessel
20362a0309cSJason Wessel local_irq_save(flags);
20462a0309cSJason Wessel ret = __kgdb_notify(ptr, cmd);
20562a0309cSJason Wessel local_irq_restore(flags);
20662a0309cSJason Wessel
20762a0309cSJason Wessel return ret;
20862a0309cSJason Wessel }
20962a0309cSJason Wessel
21062a0309cSJason Wessel static struct notifier_block kgdb_notifier = {
21162a0309cSJason Wessel .notifier_call = kgdb_notify,
21262a0309cSJason Wessel .priority = -INT_MAX,
21362a0309cSJason Wessel };
21462a0309cSJason Wessel
21562a0309cSJason Wessel
2165cbad0ebSJason Wessel /**
2175cbad0ebSJason Wessel * kgdb_arch_init - Perform any architecture specific initalization.
2185cbad0ebSJason Wessel *
2195cbad0ebSJason Wessel * This function will handle the initalization of any architecture
2205cbad0ebSJason Wessel * specific callbacks.
2215cbad0ebSJason Wessel */
kgdb_arch_init(void)2225cbad0ebSJason Wessel int kgdb_arch_init(void)
2235cbad0ebSJason Wessel {
22462a0309cSJason Wessel int ret = register_die_notifier(&kgdb_notifier);
22562a0309cSJason Wessel
22662a0309cSJason Wessel if (ret != 0)
22762a0309cSJason Wessel return ret;
22862a0309cSJason Wessel
229*d920eaa4SRussell King (Oracle) register_undef_hook(&kgdb_brkpt_arm_hook);
230*d920eaa4SRussell King (Oracle) register_undef_hook(&kgdb_brkpt_thumb_hook);
231*d920eaa4SRussell King (Oracle) register_undef_hook(&kgdb_compiled_brkpt_arm_hook);
232*d920eaa4SRussell King (Oracle) register_undef_hook(&kgdb_compiled_brkpt_thumb_hook);
2335cbad0ebSJason Wessel
2345cbad0ebSJason Wessel return 0;
2355cbad0ebSJason Wessel }
2365cbad0ebSJason Wessel
2375cbad0ebSJason Wessel /**
2385cbad0ebSJason Wessel * kgdb_arch_exit - Perform any architecture specific uninitalization.
2395cbad0ebSJason Wessel *
2405cbad0ebSJason Wessel * This function will handle the uninitalization of any architecture
2415cbad0ebSJason Wessel * specific callbacks, for dynamic registration and unregistration.
2425cbad0ebSJason Wessel */
kgdb_arch_exit(void)2435cbad0ebSJason Wessel void kgdb_arch_exit(void)
2445cbad0ebSJason Wessel {
245*d920eaa4SRussell King (Oracle) unregister_undef_hook(&kgdb_brkpt_arm_hook);
246*d920eaa4SRussell King (Oracle) unregister_undef_hook(&kgdb_brkpt_thumb_hook);
247*d920eaa4SRussell King (Oracle) unregister_undef_hook(&kgdb_compiled_brkpt_arm_hook);
248*d920eaa4SRussell King (Oracle) unregister_undef_hook(&kgdb_compiled_brkpt_thumb_hook);
24962a0309cSJason Wessel unregister_die_notifier(&kgdb_notifier);
2505cbad0ebSJason Wessel }
2515cbad0ebSJason Wessel
kgdb_arch_set_breakpoint(struct kgdb_bkpt * bpt)25223a4e405SDoug Anderson int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
25323a4e405SDoug Anderson {
25423a4e405SDoug Anderson int err;
25523a4e405SDoug Anderson
25623a4e405SDoug Anderson /* patch_text() only supports int-sized breakpoints */
25723a4e405SDoug Anderson BUILD_BUG_ON(sizeof(int) != BREAK_INSTR_SIZE);
25823a4e405SDoug Anderson
259fe557319SChristoph Hellwig err = copy_from_kernel_nofault(bpt->saved_instr, (char *)bpt->bpt_addr,
26023a4e405SDoug Anderson BREAK_INSTR_SIZE);
26123a4e405SDoug Anderson if (err)
26223a4e405SDoug Anderson return err;
26323a4e405SDoug Anderson
2647ae85dc7SDoug Anderson /* Machine is already stopped, so we can use __patch_text() directly */
2657ae85dc7SDoug Anderson __patch_text((void *)bpt->bpt_addr,
26623a4e405SDoug Anderson *(unsigned int *)arch_kgdb_ops.gdb_bpt_instr);
26723a4e405SDoug Anderson
26823a4e405SDoug Anderson return err;
26923a4e405SDoug Anderson }
27023a4e405SDoug Anderson
kgdb_arch_remove_breakpoint(struct kgdb_bkpt * bpt)27123a4e405SDoug Anderson int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
27223a4e405SDoug Anderson {
2737ae85dc7SDoug Anderson /* Machine is already stopped, so we can use __patch_text() directly */
2747ae85dc7SDoug Anderson __patch_text((void *)bpt->bpt_addr, *(unsigned int *)bpt->saved_instr);
27523a4e405SDoug Anderson
27623a4e405SDoug Anderson return 0;
27723a4e405SDoug Anderson }
27823a4e405SDoug Anderson
2795cbad0ebSJason Wessel /*
2805cbad0ebSJason Wessel * Register our undef instruction hooks with ARM undef core.
281ad61dd30SStephen Boyd * We register a hook specifically looking for the KGB break inst
2825cbad0ebSJason Wessel * and we handle the normal undef case within the do_undefinstr
2835cbad0ebSJason Wessel * handler.
2845cbad0ebSJason Wessel */
285cc028297SChristophe Leroy const struct kgdb_arch arch_kgdb_ops = {
2865cbad0ebSJason Wessel #ifndef __ARMEB__
2875cbad0ebSJason Wessel .gdb_bpt_instr = {0xfe, 0xde, 0xff, 0xe7}
2885cbad0ebSJason Wessel #else /* ! __ARMEB__ */
2895cbad0ebSJason Wessel .gdb_bpt_instr = {0xe7, 0xff, 0xde, 0xfe}
2905cbad0ebSJason Wessel #endif
2915cbad0ebSJason Wessel };
292