xref: /openbmc/linux/arch/arm64/kernel/kgdb.c (revision af6c0bd5)
1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2bcf5763bSVijaya Kumar K /*
3bcf5763bSVijaya Kumar K  * AArch64 KGDB support
4bcf5763bSVijaya Kumar K  *
5bcf5763bSVijaya Kumar K  * Based on arch/arm/kernel/kgdb.c
6bcf5763bSVijaya Kumar K  *
7bcf5763bSVijaya Kumar K  * Copyright (C) 2013 Cavium Inc.
8bcf5763bSVijaya Kumar K  * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
9bcf5763bSVijaya Kumar K  */
10bcf5763bSVijaya Kumar K 
1167787b68SAKASHI Takahiro #include <linux/bug.h>
12bcf5763bSVijaya Kumar K #include <linux/irq.h>
13bcf5763bSVijaya Kumar K #include <linux/kdebug.h>
14bcf5763bSVijaya Kumar K #include <linux/kgdb.h>
1544b53f67SPratyush Anand #include <linux/kprobes.h>
1668db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
1768db0cf1SIngo Molnar 
1867787b68SAKASHI Takahiro #include <asm/debug-monitors.h>
1967787b68SAKASHI Takahiro #include <asm/insn.h>
2078b92c73SMark Rutland #include <asm/patching.h>
21bcf5763bSVijaya Kumar K #include <asm/traps.h>
22bcf5763bSVijaya Kumar K 
23bcf5763bSVijaya Kumar K struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
24bcf5763bSVijaya Kumar K 	{ "x0", 8, offsetof(struct pt_regs, regs[0])},
25bcf5763bSVijaya Kumar K 	{ "x1", 8, offsetof(struct pt_regs, regs[1])},
26bcf5763bSVijaya Kumar K 	{ "x2", 8, offsetof(struct pt_regs, regs[2])},
27bcf5763bSVijaya Kumar K 	{ "x3", 8, offsetof(struct pt_regs, regs[3])},
28bcf5763bSVijaya Kumar K 	{ "x4", 8, offsetof(struct pt_regs, regs[4])},
29bcf5763bSVijaya Kumar K 	{ "x5", 8, offsetof(struct pt_regs, regs[5])},
30bcf5763bSVijaya Kumar K 	{ "x6", 8, offsetof(struct pt_regs, regs[6])},
31bcf5763bSVijaya Kumar K 	{ "x7", 8, offsetof(struct pt_regs, regs[7])},
32bcf5763bSVijaya Kumar K 	{ "x8", 8, offsetof(struct pt_regs, regs[8])},
33bcf5763bSVijaya Kumar K 	{ "x9", 8, offsetof(struct pt_regs, regs[9])},
34bcf5763bSVijaya Kumar K 	{ "x10", 8, offsetof(struct pt_regs, regs[10])},
35bcf5763bSVijaya Kumar K 	{ "x11", 8, offsetof(struct pt_regs, regs[11])},
36bcf5763bSVijaya Kumar K 	{ "x12", 8, offsetof(struct pt_regs, regs[12])},
37bcf5763bSVijaya Kumar K 	{ "x13", 8, offsetof(struct pt_regs, regs[13])},
38bcf5763bSVijaya Kumar K 	{ "x14", 8, offsetof(struct pt_regs, regs[14])},
39bcf5763bSVijaya Kumar K 	{ "x15", 8, offsetof(struct pt_regs, regs[15])},
40bcf5763bSVijaya Kumar K 	{ "x16", 8, offsetof(struct pt_regs, regs[16])},
41bcf5763bSVijaya Kumar K 	{ "x17", 8, offsetof(struct pt_regs, regs[17])},
42bcf5763bSVijaya Kumar K 	{ "x18", 8, offsetof(struct pt_regs, regs[18])},
43bcf5763bSVijaya Kumar K 	{ "x19", 8, offsetof(struct pt_regs, regs[19])},
44bcf5763bSVijaya Kumar K 	{ "x20", 8, offsetof(struct pt_regs, regs[20])},
45bcf5763bSVijaya Kumar K 	{ "x21", 8, offsetof(struct pt_regs, regs[21])},
46bcf5763bSVijaya Kumar K 	{ "x22", 8, offsetof(struct pt_regs, regs[22])},
47bcf5763bSVijaya Kumar K 	{ "x23", 8, offsetof(struct pt_regs, regs[23])},
48bcf5763bSVijaya Kumar K 	{ "x24", 8, offsetof(struct pt_regs, regs[24])},
49bcf5763bSVijaya Kumar K 	{ "x25", 8, offsetof(struct pt_regs, regs[25])},
50bcf5763bSVijaya Kumar K 	{ "x26", 8, offsetof(struct pt_regs, regs[26])},
51bcf5763bSVijaya Kumar K 	{ "x27", 8, offsetof(struct pt_regs, regs[27])},
52bcf5763bSVijaya Kumar K 	{ "x28", 8, offsetof(struct pt_regs, regs[28])},
53bcf5763bSVijaya Kumar K 	{ "x29", 8, offsetof(struct pt_regs, regs[29])},
54bcf5763bSVijaya Kumar K 	{ "x30", 8, offsetof(struct pt_regs, regs[30])},
55bcf5763bSVijaya Kumar K 	{ "sp", 8, offsetof(struct pt_regs, sp)},
56bcf5763bSVijaya Kumar K 	{ "pc", 8, offsetof(struct pt_regs, pc)},
570d15ef67SDaniel Thompson 	/*
580d15ef67SDaniel Thompson 	 * struct pt_regs thinks PSTATE is 64-bits wide but gdb remote
590d15ef67SDaniel Thompson 	 * protocol disagrees. Therefore we must extract only the lower
600d15ef67SDaniel Thompson 	 * 32-bits. Look for the big comment in asm/kgdb.h for more
610d15ef67SDaniel Thompson 	 * detail.
620d15ef67SDaniel Thompson 	 */
630d15ef67SDaniel Thompson 	{ "pstate", 4, offsetof(struct pt_regs, pstate)
640d15ef67SDaniel Thompson #ifdef CONFIG_CPU_BIG_ENDIAN
650d15ef67SDaniel Thompson 							+ 4
660d15ef67SDaniel Thompson #endif
670d15ef67SDaniel Thompson 	},
68bcf5763bSVijaya Kumar K 	{ "v0", 16, -1 },
69bcf5763bSVijaya Kumar K 	{ "v1", 16, -1 },
70bcf5763bSVijaya Kumar K 	{ "v2", 16, -1 },
71bcf5763bSVijaya Kumar K 	{ "v3", 16, -1 },
72bcf5763bSVijaya Kumar K 	{ "v4", 16, -1 },
73bcf5763bSVijaya Kumar K 	{ "v5", 16, -1 },
74bcf5763bSVijaya Kumar K 	{ "v6", 16, -1 },
75bcf5763bSVijaya Kumar K 	{ "v7", 16, -1 },
76bcf5763bSVijaya Kumar K 	{ "v8", 16, -1 },
77bcf5763bSVijaya Kumar K 	{ "v9", 16, -1 },
78bcf5763bSVijaya Kumar K 	{ "v10", 16, -1 },
79bcf5763bSVijaya Kumar K 	{ "v11", 16, -1 },
80bcf5763bSVijaya Kumar K 	{ "v12", 16, -1 },
81bcf5763bSVijaya Kumar K 	{ "v13", 16, -1 },
82bcf5763bSVijaya Kumar K 	{ "v14", 16, -1 },
83bcf5763bSVijaya Kumar K 	{ "v15", 16, -1 },
84bcf5763bSVijaya Kumar K 	{ "v16", 16, -1 },
85bcf5763bSVijaya Kumar K 	{ "v17", 16, -1 },
86bcf5763bSVijaya Kumar K 	{ "v18", 16, -1 },
87bcf5763bSVijaya Kumar K 	{ "v19", 16, -1 },
88bcf5763bSVijaya Kumar K 	{ "v20", 16, -1 },
89bcf5763bSVijaya Kumar K 	{ "v21", 16, -1 },
90bcf5763bSVijaya Kumar K 	{ "v22", 16, -1 },
91bcf5763bSVijaya Kumar K 	{ "v23", 16, -1 },
92bcf5763bSVijaya Kumar K 	{ "v24", 16, -1 },
93bcf5763bSVijaya Kumar K 	{ "v25", 16, -1 },
94bcf5763bSVijaya Kumar K 	{ "v26", 16, -1 },
95bcf5763bSVijaya Kumar K 	{ "v27", 16, -1 },
96bcf5763bSVijaya Kumar K 	{ "v28", 16, -1 },
97bcf5763bSVijaya Kumar K 	{ "v29", 16, -1 },
98bcf5763bSVijaya Kumar K 	{ "v30", 16, -1 },
99bcf5763bSVijaya Kumar K 	{ "v31", 16, -1 },
100bcf5763bSVijaya Kumar K 	{ "fpsr", 4, -1 },
101bcf5763bSVijaya Kumar K 	{ "fpcr", 4, -1 },
102bcf5763bSVijaya Kumar K };
103bcf5763bSVijaya Kumar K 
dbg_get_reg(int regno,void * mem,struct pt_regs * regs)104bcf5763bSVijaya Kumar K char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
105bcf5763bSVijaya Kumar K {
106bcf5763bSVijaya Kumar K 	if (regno >= DBG_MAX_REG_NUM || regno < 0)
107bcf5763bSVijaya Kumar K 		return NULL;
108bcf5763bSVijaya Kumar K 
109bcf5763bSVijaya Kumar K 	if (dbg_reg_def[regno].offset != -1)
110bcf5763bSVijaya Kumar K 		memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
111bcf5763bSVijaya Kumar K 		       dbg_reg_def[regno].size);
112bcf5763bSVijaya Kumar K 	else
113bcf5763bSVijaya Kumar K 		memset(mem, 0, dbg_reg_def[regno].size);
114bcf5763bSVijaya Kumar K 	return dbg_reg_def[regno].name;
115bcf5763bSVijaya Kumar K }
116bcf5763bSVijaya Kumar K 
dbg_set_reg(int regno,void * mem,struct pt_regs * regs)117bcf5763bSVijaya Kumar K int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
118bcf5763bSVijaya Kumar K {
119bcf5763bSVijaya Kumar K 	if (regno >= DBG_MAX_REG_NUM || regno < 0)
120bcf5763bSVijaya Kumar K 		return -EINVAL;
121bcf5763bSVijaya Kumar K 
122bcf5763bSVijaya Kumar K 	if (dbg_reg_def[regno].offset != -1)
123bcf5763bSVijaya Kumar K 		memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
124bcf5763bSVijaya Kumar K 		       dbg_reg_def[regno].size);
125bcf5763bSVijaya Kumar K 	return 0;
126bcf5763bSVijaya Kumar K }
127bcf5763bSVijaya Kumar K 
128bcf5763bSVijaya Kumar K void
sleeping_thread_to_gdb_regs(unsigned long * gdb_regs,struct task_struct * task)129bcf5763bSVijaya Kumar K sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
130bcf5763bSVijaya Kumar K {
13124153c03SDouglas Anderson 	struct cpu_context *cpu_context = &task->thread.cpu_context;
132bcf5763bSVijaya Kumar K 
133bcf5763bSVijaya Kumar K 	/* Initialize to zero */
134bcf5763bSVijaya Kumar K 	memset((char *)gdb_regs, 0, NUMREGBYTES);
13524153c03SDouglas Anderson 
13624153c03SDouglas Anderson 	gdb_regs[19] = cpu_context->x19;
13724153c03SDouglas Anderson 	gdb_regs[20] = cpu_context->x20;
13824153c03SDouglas Anderson 	gdb_regs[21] = cpu_context->x21;
13924153c03SDouglas Anderson 	gdb_regs[22] = cpu_context->x22;
14024153c03SDouglas Anderson 	gdb_regs[23] = cpu_context->x23;
14124153c03SDouglas Anderson 	gdb_regs[24] = cpu_context->x24;
14224153c03SDouglas Anderson 	gdb_regs[25] = cpu_context->x25;
14324153c03SDouglas Anderson 	gdb_regs[26] = cpu_context->x26;
14424153c03SDouglas Anderson 	gdb_regs[27] = cpu_context->x27;
14524153c03SDouglas Anderson 	gdb_regs[28] = cpu_context->x28;
14624153c03SDouglas Anderson 	gdb_regs[29] = cpu_context->fp;
14724153c03SDouglas Anderson 
14824153c03SDouglas Anderson 	gdb_regs[31] = cpu_context->sp;
14924153c03SDouglas Anderson 	gdb_regs[32] = cpu_context->pc;
150bcf5763bSVijaya Kumar K }
151bcf5763bSVijaya Kumar K 
kgdb_arch_set_pc(struct pt_regs * regs,unsigned long pc)152bcf5763bSVijaya Kumar K void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
153bcf5763bSVijaya Kumar K {
154bcf5763bSVijaya Kumar K 	regs->pc = pc;
155bcf5763bSVijaya Kumar K }
156bcf5763bSVijaya Kumar K 
157bcf5763bSVijaya Kumar K static int compiled_break;
158bcf5763bSVijaya Kumar K 
kgdb_arch_update_addr(struct pt_regs * regs,char * remcom_in_buffer)15944679a4fSVijaya Kumar K static void kgdb_arch_update_addr(struct pt_regs *regs,
16044679a4fSVijaya Kumar K 				char *remcom_in_buffer)
16144679a4fSVijaya Kumar K {
16244679a4fSVijaya Kumar K 	unsigned long addr;
16344679a4fSVijaya Kumar K 	char *ptr;
16444679a4fSVijaya Kumar K 
16544679a4fSVijaya Kumar K 	ptr = &remcom_in_buffer[1];
16644679a4fSVijaya Kumar K 	if (kgdb_hex2long(&ptr, &addr))
16744679a4fSVijaya Kumar K 		kgdb_arch_set_pc(regs, addr);
16844679a4fSVijaya Kumar K 	else if (compiled_break == 1)
16944679a4fSVijaya Kumar K 		kgdb_arch_set_pc(regs, regs->pc + 4);
17044679a4fSVijaya Kumar K 
17144679a4fSVijaya Kumar K 	compiled_break = 0;
17244679a4fSVijaya Kumar K }
17344679a4fSVijaya Kumar K 
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)174bcf5763bSVijaya Kumar K int kgdb_arch_handle_exception(int exception_vector, int signo,
175bcf5763bSVijaya Kumar K 			       int err_code, char *remcom_in_buffer,
176bcf5763bSVijaya Kumar K 			       char *remcom_out_buffer,
177bcf5763bSVijaya Kumar K 			       struct pt_regs *linux_regs)
178bcf5763bSVijaya Kumar K {
179bcf5763bSVijaya Kumar K 	int err;
180bcf5763bSVijaya Kumar K 
181bcf5763bSVijaya Kumar K 	switch (remcom_in_buffer[0]) {
182bcf5763bSVijaya Kumar K 	case 'D':
183bcf5763bSVijaya Kumar K 	case 'k':
184bcf5763bSVijaya Kumar K 		/*
185bcf5763bSVijaya Kumar K 		 * Packet D (Detach), k (kill). No special handling
186bcf5763bSVijaya Kumar K 		 * is required here. Handle same as c packet.
187bcf5763bSVijaya Kumar K 		 */
188bcf5763bSVijaya Kumar K 	case 'c':
189bcf5763bSVijaya Kumar K 		/*
190bcf5763bSVijaya Kumar K 		 * Packet c (Continue) to continue executing.
191bcf5763bSVijaya Kumar K 		 * Set pc to required address.
192bcf5763bSVijaya Kumar K 		 * Try to read optional parameter and set pc.
193bcf5763bSVijaya Kumar K 		 * If this was a compiled breakpoint, we need to move
194bcf5763bSVijaya Kumar K 		 * to the next instruction else we will just breakpoint
195bcf5763bSVijaya Kumar K 		 * over and over again.
196bcf5763bSVijaya Kumar K 		 */
19744679a4fSVijaya Kumar K 		kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
19844679a4fSVijaya Kumar K 		atomic_set(&kgdb_cpu_doing_single_step, -1);
19944679a4fSVijaya Kumar K 		kgdb_single_step =  0;
200bcf5763bSVijaya Kumar K 
20144679a4fSVijaya Kumar K 		/*
20244679a4fSVijaya Kumar K 		 * Received continue command, disable single step
20344679a4fSVijaya Kumar K 		 */
20444679a4fSVijaya Kumar K 		if (kernel_active_single_step())
20544679a4fSVijaya Kumar K 			kernel_disable_single_step();
20644679a4fSVijaya Kumar K 
20744679a4fSVijaya Kumar K 		err = 0;
20844679a4fSVijaya Kumar K 		break;
20944679a4fSVijaya Kumar K 	case 's':
21044679a4fSVijaya Kumar K 		/*
21144679a4fSVijaya Kumar K 		 * Update step address value with address passed
21244679a4fSVijaya Kumar K 		 * with step packet.
21344679a4fSVijaya Kumar K 		 * On debug exception return PC is copied to ELR
21444679a4fSVijaya Kumar K 		 * So just update PC.
21544679a4fSVijaya Kumar K 		 * If no step address is passed, resume from the address
21644679a4fSVijaya Kumar K 		 * pointed by PC. Do not update PC
21744679a4fSVijaya Kumar K 		 */
21844679a4fSVijaya Kumar K 		kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
21944679a4fSVijaya Kumar K 		atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id());
22044679a4fSVijaya Kumar K 		kgdb_single_step =  1;
22144679a4fSVijaya Kumar K 
22244679a4fSVijaya Kumar K 		/*
22344679a4fSVijaya Kumar K 		 * Enable single step handling
22444679a4fSVijaya Kumar K 		 */
22544679a4fSVijaya Kumar K 		if (!kernel_active_single_step())
22644679a4fSVijaya Kumar K 			kernel_enable_single_step(linux_regs);
227*af6c0bd5SSumit Garg 		else
228*af6c0bd5SSumit Garg 			kernel_rewind_single_step(linux_regs);
229bcf5763bSVijaya Kumar K 		err = 0;
230bcf5763bSVijaya Kumar K 		break;
231bcf5763bSVijaya Kumar K 	default:
232bcf5763bSVijaya Kumar K 		err = -1;
233bcf5763bSVijaya Kumar K 	}
234bcf5763bSVijaya Kumar K 	return err;
235bcf5763bSVijaya Kumar K }
236bcf5763bSVijaya Kumar K 
kgdb_brk_fn(struct pt_regs * regs,unsigned long esr)2378d56e5c5SAlexandru Elisei static int kgdb_brk_fn(struct pt_regs *regs, unsigned long esr)
238bcf5763bSVijaya Kumar K {
239bcf5763bSVijaya Kumar K 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
2406bd28856SWill Deacon 	return DBG_HOOK_HANDLED;
241bcf5763bSVijaya Kumar K }
NOKPROBE_SYMBOL(kgdb_brk_fn)24244b53f67SPratyush Anand NOKPROBE_SYMBOL(kgdb_brk_fn)
243bcf5763bSVijaya Kumar K 
2448d56e5c5SAlexandru Elisei static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned long esr)
245bcf5763bSVijaya Kumar K {
246bcf5763bSVijaya Kumar K 	compiled_break = 1;
247bcf5763bSVijaya Kumar K 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
248bcf5763bSVijaya Kumar K 
2496bd28856SWill Deacon 	return DBG_HOOK_HANDLED;
250bcf5763bSVijaya Kumar K }
25144b53f67SPratyush Anand NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);
252bcf5763bSVijaya Kumar K 
kgdb_step_brk_fn(struct pt_regs * regs,unsigned long esr)2538d56e5c5SAlexandru Elisei static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned long esr)
25444679a4fSVijaya Kumar K {
255fb610f2aSWill Deacon 	if (!kgdb_single_step)
256b66c9870SPratyush Anand 		return DBG_HOOK_ERROR;
257b66c9870SPratyush Anand 
2588523c006SWei Li 	kgdb_handle_exception(0, SIGTRAP, 0, regs);
2596bd28856SWill Deacon 	return DBG_HOOK_HANDLED;
26044679a4fSVijaya Kumar K }
26144b53f67SPratyush Anand NOKPROBE_SYMBOL(kgdb_step_brk_fn);
26244679a4fSVijaya Kumar K 
263bcf5763bSVijaya Kumar K static struct break_hook kgdb_brkpt_hook = {
26426a04d84SWill Deacon 	.fn		= kgdb_brk_fn,
26526a04d84SWill Deacon 	.imm		= KGDB_DYN_DBG_BRK_IMM,
266bcf5763bSVijaya Kumar K };
267bcf5763bSVijaya Kumar K 
268bcf5763bSVijaya Kumar K static struct break_hook kgdb_compiled_brkpt_hook = {
26926a04d84SWill Deacon 	.fn		= kgdb_compiled_brk_fn,
27026a04d84SWill Deacon 	.imm		= KGDB_COMPILED_DBG_BRK_IMM,
271bcf5763bSVijaya Kumar K };
272bcf5763bSVijaya Kumar K 
27344679a4fSVijaya Kumar K static struct step_hook kgdb_step_hook = {
27444679a4fSVijaya Kumar K 	.fn		= kgdb_step_brk_fn
27544679a4fSVijaya Kumar K };
27644679a4fSVijaya Kumar K 
__kgdb_notify(struct die_args * args,unsigned long cmd)277bcf5763bSVijaya Kumar K static int __kgdb_notify(struct die_args *args, unsigned long cmd)
278bcf5763bSVijaya Kumar K {
279bcf5763bSVijaya Kumar K 	struct pt_regs *regs = args->regs;
280bcf5763bSVijaya Kumar K 
281bcf5763bSVijaya Kumar K 	if (kgdb_handle_exception(1, args->signr, cmd, regs))
282bcf5763bSVijaya Kumar K 		return NOTIFY_DONE;
283bcf5763bSVijaya Kumar K 	return NOTIFY_STOP;
284bcf5763bSVijaya Kumar K }
285bcf5763bSVijaya Kumar K 
286bcf5763bSVijaya Kumar K static int
kgdb_notify(struct notifier_block * self,unsigned long cmd,void * ptr)287bcf5763bSVijaya Kumar K kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
288bcf5763bSVijaya Kumar K {
289bcf5763bSVijaya Kumar K 	unsigned long flags;
290bcf5763bSVijaya Kumar K 	int ret;
291bcf5763bSVijaya Kumar K 
292bcf5763bSVijaya Kumar K 	local_irq_save(flags);
293bcf5763bSVijaya Kumar K 	ret = __kgdb_notify(ptr, cmd);
294bcf5763bSVijaya Kumar K 	local_irq_restore(flags);
295bcf5763bSVijaya Kumar K 
296bcf5763bSVijaya Kumar K 	return ret;
297bcf5763bSVijaya Kumar K }
298bcf5763bSVijaya Kumar K 
299bcf5763bSVijaya Kumar K static struct notifier_block kgdb_notifier = {
300bcf5763bSVijaya Kumar K 	.notifier_call	= kgdb_notify,
301bcf5763bSVijaya Kumar K 	/*
302bcf5763bSVijaya Kumar K 	 * Want to be lowest priority
303bcf5763bSVijaya Kumar K 	 */
304bcf5763bSVijaya Kumar K 	.priority	= -INT_MAX,
305bcf5763bSVijaya Kumar K };
306bcf5763bSVijaya Kumar K 
307bcf5763bSVijaya Kumar K /*
308ef769e32SAdam Buchbinder  * kgdb_arch_init - Perform any architecture specific initialization.
309ef769e32SAdam Buchbinder  * This function will handle the initialization of any architecture
310bcf5763bSVijaya Kumar K  * specific callbacks.
311bcf5763bSVijaya Kumar K  */
kgdb_arch_init(void)312bcf5763bSVijaya Kumar K int kgdb_arch_init(void)
313bcf5763bSVijaya Kumar K {
314bcf5763bSVijaya Kumar K 	int ret = register_die_notifier(&kgdb_notifier);
315bcf5763bSVijaya Kumar K 
316bcf5763bSVijaya Kumar K 	if (ret != 0)
317bcf5763bSVijaya Kumar K 		return ret;
318bcf5763bSVijaya Kumar K 
31926a04d84SWill Deacon 	register_kernel_break_hook(&kgdb_brkpt_hook);
32026a04d84SWill Deacon 	register_kernel_break_hook(&kgdb_compiled_brkpt_hook);
32126a04d84SWill Deacon 	register_kernel_step_hook(&kgdb_step_hook);
322bcf5763bSVijaya Kumar K 	return 0;
323bcf5763bSVijaya Kumar K }
324bcf5763bSVijaya Kumar K 
325bcf5763bSVijaya Kumar K /*
326bcf5763bSVijaya Kumar K  * kgdb_arch_exit - Perform any architecture specific uninitalization.
327bcf5763bSVijaya Kumar K  * This function will handle the uninitalization of any architecture
328bcf5763bSVijaya Kumar K  * specific callbacks, for dynamic registration and unregistration.
329bcf5763bSVijaya Kumar K  */
kgdb_arch_exit(void)330bcf5763bSVijaya Kumar K void kgdb_arch_exit(void)
331bcf5763bSVijaya Kumar K {
33226a04d84SWill Deacon 	unregister_kernel_break_hook(&kgdb_brkpt_hook);
33326a04d84SWill Deacon 	unregister_kernel_break_hook(&kgdb_compiled_brkpt_hook);
33426a04d84SWill Deacon 	unregister_kernel_step_hook(&kgdb_step_hook);
335bcf5763bSVijaya Kumar K 	unregister_die_notifier(&kgdb_notifier);
336bcf5763bSVijaya Kumar K }
337bcf5763bSVijaya Kumar K 
338cc028297SChristophe Leroy const struct kgdb_arch arch_kgdb_ops;
33967787b68SAKASHI Takahiro 
kgdb_arch_set_breakpoint(struct kgdb_bkpt * bpt)34067787b68SAKASHI Takahiro int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
34167787b68SAKASHI Takahiro {
34267787b68SAKASHI Takahiro 	int err;
34367787b68SAKASHI Takahiro 
34467787b68SAKASHI Takahiro 	BUILD_BUG_ON(AARCH64_INSN_SIZE != BREAK_INSTR_SIZE);
34567787b68SAKASHI Takahiro 
34667787b68SAKASHI Takahiro 	err = aarch64_insn_read((void *)bpt->bpt_addr, (u32 *)bpt->saved_instr);
34767787b68SAKASHI Takahiro 	if (err)
34867787b68SAKASHI Takahiro 		return err;
34967787b68SAKASHI Takahiro 
35067787b68SAKASHI Takahiro 	return aarch64_insn_write((void *)bpt->bpt_addr,
35167787b68SAKASHI Takahiro 			(u32)AARCH64_BREAK_KGDB_DYN_DBG);
352bcf5763bSVijaya Kumar K }
35367787b68SAKASHI Takahiro 
kgdb_arch_remove_breakpoint(struct kgdb_bkpt * bpt)35467787b68SAKASHI Takahiro int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
35567787b68SAKASHI Takahiro {
35667787b68SAKASHI Takahiro 	return aarch64_insn_write((void *)bpt->bpt_addr,
35767787b68SAKASHI Takahiro 			*(u32 *)bpt->saved_instr);
35867787b68SAKASHI Takahiro }
359