xref: /openbmc/linux/arch/arm64/kernel/kgdb.c (revision caab277b)
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>
20bcf5763bSVijaya Kumar K #include <asm/traps.h>
21bcf5763bSVijaya Kumar K 
22bcf5763bSVijaya Kumar K struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
23bcf5763bSVijaya Kumar K 	{ "x0", 8, offsetof(struct pt_regs, regs[0])},
24bcf5763bSVijaya Kumar K 	{ "x1", 8, offsetof(struct pt_regs, regs[1])},
25bcf5763bSVijaya Kumar K 	{ "x2", 8, offsetof(struct pt_regs, regs[2])},
26bcf5763bSVijaya Kumar K 	{ "x3", 8, offsetof(struct pt_regs, regs[3])},
27bcf5763bSVijaya Kumar K 	{ "x4", 8, offsetof(struct pt_regs, regs[4])},
28bcf5763bSVijaya Kumar K 	{ "x5", 8, offsetof(struct pt_regs, regs[5])},
29bcf5763bSVijaya Kumar K 	{ "x6", 8, offsetof(struct pt_regs, regs[6])},
30bcf5763bSVijaya Kumar K 	{ "x7", 8, offsetof(struct pt_regs, regs[7])},
31bcf5763bSVijaya Kumar K 	{ "x8", 8, offsetof(struct pt_regs, regs[8])},
32bcf5763bSVijaya Kumar K 	{ "x9", 8, offsetof(struct pt_regs, regs[9])},
33bcf5763bSVijaya Kumar K 	{ "x10", 8, offsetof(struct pt_regs, regs[10])},
34bcf5763bSVijaya Kumar K 	{ "x11", 8, offsetof(struct pt_regs, regs[11])},
35bcf5763bSVijaya Kumar K 	{ "x12", 8, offsetof(struct pt_regs, regs[12])},
36bcf5763bSVijaya Kumar K 	{ "x13", 8, offsetof(struct pt_regs, regs[13])},
37bcf5763bSVijaya Kumar K 	{ "x14", 8, offsetof(struct pt_regs, regs[14])},
38bcf5763bSVijaya Kumar K 	{ "x15", 8, offsetof(struct pt_regs, regs[15])},
39bcf5763bSVijaya Kumar K 	{ "x16", 8, offsetof(struct pt_regs, regs[16])},
40bcf5763bSVijaya Kumar K 	{ "x17", 8, offsetof(struct pt_regs, regs[17])},
41bcf5763bSVijaya Kumar K 	{ "x18", 8, offsetof(struct pt_regs, regs[18])},
42bcf5763bSVijaya Kumar K 	{ "x19", 8, offsetof(struct pt_regs, regs[19])},
43bcf5763bSVijaya Kumar K 	{ "x20", 8, offsetof(struct pt_regs, regs[20])},
44bcf5763bSVijaya Kumar K 	{ "x21", 8, offsetof(struct pt_regs, regs[21])},
45bcf5763bSVijaya Kumar K 	{ "x22", 8, offsetof(struct pt_regs, regs[22])},
46bcf5763bSVijaya Kumar K 	{ "x23", 8, offsetof(struct pt_regs, regs[23])},
47bcf5763bSVijaya Kumar K 	{ "x24", 8, offsetof(struct pt_regs, regs[24])},
48bcf5763bSVijaya Kumar K 	{ "x25", 8, offsetof(struct pt_regs, regs[25])},
49bcf5763bSVijaya Kumar K 	{ "x26", 8, offsetof(struct pt_regs, regs[26])},
50bcf5763bSVijaya Kumar K 	{ "x27", 8, offsetof(struct pt_regs, regs[27])},
51bcf5763bSVijaya Kumar K 	{ "x28", 8, offsetof(struct pt_regs, regs[28])},
52bcf5763bSVijaya Kumar K 	{ "x29", 8, offsetof(struct pt_regs, regs[29])},
53bcf5763bSVijaya Kumar K 	{ "x30", 8, offsetof(struct pt_regs, regs[30])},
54bcf5763bSVijaya Kumar K 	{ "sp", 8, offsetof(struct pt_regs, sp)},
55bcf5763bSVijaya Kumar K 	{ "pc", 8, offsetof(struct pt_regs, pc)},
560d15ef67SDaniel Thompson 	/*
570d15ef67SDaniel Thompson 	 * struct pt_regs thinks PSTATE is 64-bits wide but gdb remote
580d15ef67SDaniel Thompson 	 * protocol disagrees. Therefore we must extract only the lower
590d15ef67SDaniel Thompson 	 * 32-bits. Look for the big comment in asm/kgdb.h for more
600d15ef67SDaniel Thompson 	 * detail.
610d15ef67SDaniel Thompson 	 */
620d15ef67SDaniel Thompson 	{ "pstate", 4, offsetof(struct pt_regs, pstate)
630d15ef67SDaniel Thompson #ifdef CONFIG_CPU_BIG_ENDIAN
640d15ef67SDaniel Thompson 							+ 4
650d15ef67SDaniel Thompson #endif
660d15ef67SDaniel Thompson 	},
67bcf5763bSVijaya Kumar K 	{ "v0", 16, -1 },
68bcf5763bSVijaya Kumar K 	{ "v1", 16, -1 },
69bcf5763bSVijaya Kumar K 	{ "v2", 16, -1 },
70bcf5763bSVijaya Kumar K 	{ "v3", 16, -1 },
71bcf5763bSVijaya Kumar K 	{ "v4", 16, -1 },
72bcf5763bSVijaya Kumar K 	{ "v5", 16, -1 },
73bcf5763bSVijaya Kumar K 	{ "v6", 16, -1 },
74bcf5763bSVijaya Kumar K 	{ "v7", 16, -1 },
75bcf5763bSVijaya Kumar K 	{ "v8", 16, -1 },
76bcf5763bSVijaya Kumar K 	{ "v9", 16, -1 },
77bcf5763bSVijaya Kumar K 	{ "v10", 16, -1 },
78bcf5763bSVijaya Kumar K 	{ "v11", 16, -1 },
79bcf5763bSVijaya Kumar K 	{ "v12", 16, -1 },
80bcf5763bSVijaya Kumar K 	{ "v13", 16, -1 },
81bcf5763bSVijaya Kumar K 	{ "v14", 16, -1 },
82bcf5763bSVijaya Kumar K 	{ "v15", 16, -1 },
83bcf5763bSVijaya Kumar K 	{ "v16", 16, -1 },
84bcf5763bSVijaya Kumar K 	{ "v17", 16, -1 },
85bcf5763bSVijaya Kumar K 	{ "v18", 16, -1 },
86bcf5763bSVijaya Kumar K 	{ "v19", 16, -1 },
87bcf5763bSVijaya Kumar K 	{ "v20", 16, -1 },
88bcf5763bSVijaya Kumar K 	{ "v21", 16, -1 },
89bcf5763bSVijaya Kumar K 	{ "v22", 16, -1 },
90bcf5763bSVijaya Kumar K 	{ "v23", 16, -1 },
91bcf5763bSVijaya Kumar K 	{ "v24", 16, -1 },
92bcf5763bSVijaya Kumar K 	{ "v25", 16, -1 },
93bcf5763bSVijaya Kumar K 	{ "v26", 16, -1 },
94bcf5763bSVijaya Kumar K 	{ "v27", 16, -1 },
95bcf5763bSVijaya Kumar K 	{ "v28", 16, -1 },
96bcf5763bSVijaya Kumar K 	{ "v29", 16, -1 },
97bcf5763bSVijaya Kumar K 	{ "v30", 16, -1 },
98bcf5763bSVijaya Kumar K 	{ "v31", 16, -1 },
99bcf5763bSVijaya Kumar K 	{ "fpsr", 4, -1 },
100bcf5763bSVijaya Kumar K 	{ "fpcr", 4, -1 },
101bcf5763bSVijaya Kumar K };
102bcf5763bSVijaya Kumar K 
103bcf5763bSVijaya Kumar K char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
104bcf5763bSVijaya Kumar K {
105bcf5763bSVijaya Kumar K 	if (regno >= DBG_MAX_REG_NUM || regno < 0)
106bcf5763bSVijaya Kumar K 		return NULL;
107bcf5763bSVijaya Kumar K 
108bcf5763bSVijaya Kumar K 	if (dbg_reg_def[regno].offset != -1)
109bcf5763bSVijaya Kumar K 		memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
110bcf5763bSVijaya Kumar K 		       dbg_reg_def[regno].size);
111bcf5763bSVijaya Kumar K 	else
112bcf5763bSVijaya Kumar K 		memset(mem, 0, dbg_reg_def[regno].size);
113bcf5763bSVijaya Kumar K 	return dbg_reg_def[regno].name;
114bcf5763bSVijaya Kumar K }
115bcf5763bSVijaya Kumar K 
116bcf5763bSVijaya Kumar K int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
117bcf5763bSVijaya Kumar K {
118bcf5763bSVijaya Kumar K 	if (regno >= DBG_MAX_REG_NUM || regno < 0)
119bcf5763bSVijaya Kumar K 		return -EINVAL;
120bcf5763bSVijaya Kumar K 
121bcf5763bSVijaya Kumar K 	if (dbg_reg_def[regno].offset != -1)
122bcf5763bSVijaya Kumar K 		memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
123bcf5763bSVijaya Kumar K 		       dbg_reg_def[regno].size);
124bcf5763bSVijaya Kumar K 	return 0;
125bcf5763bSVijaya Kumar K }
126bcf5763bSVijaya Kumar K 
127bcf5763bSVijaya Kumar K void
128bcf5763bSVijaya Kumar K sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
129bcf5763bSVijaya Kumar K {
13024153c03SDouglas Anderson 	struct cpu_context *cpu_context = &task->thread.cpu_context;
131bcf5763bSVijaya Kumar K 
132bcf5763bSVijaya Kumar K 	/* Initialize to zero */
133bcf5763bSVijaya Kumar K 	memset((char *)gdb_regs, 0, NUMREGBYTES);
13424153c03SDouglas Anderson 
13524153c03SDouglas Anderson 	gdb_regs[19] = cpu_context->x19;
13624153c03SDouglas Anderson 	gdb_regs[20] = cpu_context->x20;
13724153c03SDouglas Anderson 	gdb_regs[21] = cpu_context->x21;
13824153c03SDouglas Anderson 	gdb_regs[22] = cpu_context->x22;
13924153c03SDouglas Anderson 	gdb_regs[23] = cpu_context->x23;
14024153c03SDouglas Anderson 	gdb_regs[24] = cpu_context->x24;
14124153c03SDouglas Anderson 	gdb_regs[25] = cpu_context->x25;
14224153c03SDouglas Anderson 	gdb_regs[26] = cpu_context->x26;
14324153c03SDouglas Anderson 	gdb_regs[27] = cpu_context->x27;
14424153c03SDouglas Anderson 	gdb_regs[28] = cpu_context->x28;
14524153c03SDouglas Anderson 	gdb_regs[29] = cpu_context->fp;
14624153c03SDouglas Anderson 
14724153c03SDouglas Anderson 	gdb_regs[31] = cpu_context->sp;
14824153c03SDouglas Anderson 	gdb_regs[32] = cpu_context->pc;
149bcf5763bSVijaya Kumar K }
150bcf5763bSVijaya Kumar K 
151bcf5763bSVijaya Kumar K void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
152bcf5763bSVijaya Kumar K {
153bcf5763bSVijaya Kumar K 	regs->pc = pc;
154bcf5763bSVijaya Kumar K }
155bcf5763bSVijaya Kumar K 
156bcf5763bSVijaya Kumar K static int compiled_break;
157bcf5763bSVijaya Kumar K 
15844679a4fSVijaya Kumar K static void kgdb_arch_update_addr(struct pt_regs *regs,
15944679a4fSVijaya Kumar K 				char *remcom_in_buffer)
16044679a4fSVijaya Kumar K {
16144679a4fSVijaya Kumar K 	unsigned long addr;
16244679a4fSVijaya Kumar K 	char *ptr;
16344679a4fSVijaya Kumar K 
16444679a4fSVijaya Kumar K 	ptr = &remcom_in_buffer[1];
16544679a4fSVijaya Kumar K 	if (kgdb_hex2long(&ptr, &addr))
16644679a4fSVijaya Kumar K 		kgdb_arch_set_pc(regs, addr);
16744679a4fSVijaya Kumar K 	else if (compiled_break == 1)
16844679a4fSVijaya Kumar K 		kgdb_arch_set_pc(regs, regs->pc + 4);
16944679a4fSVijaya Kumar K 
17044679a4fSVijaya Kumar K 	compiled_break = 0;
17144679a4fSVijaya Kumar K }
17244679a4fSVijaya Kumar K 
173bcf5763bSVijaya Kumar K int kgdb_arch_handle_exception(int exception_vector, int signo,
174bcf5763bSVijaya Kumar K 			       int err_code, char *remcom_in_buffer,
175bcf5763bSVijaya Kumar K 			       char *remcom_out_buffer,
176bcf5763bSVijaya Kumar K 			       struct pt_regs *linux_regs)
177bcf5763bSVijaya Kumar K {
178bcf5763bSVijaya Kumar K 	int err;
179bcf5763bSVijaya Kumar K 
180bcf5763bSVijaya Kumar K 	switch (remcom_in_buffer[0]) {
181bcf5763bSVijaya Kumar K 	case 'D':
182bcf5763bSVijaya Kumar K 	case 'k':
183bcf5763bSVijaya Kumar K 		/*
184bcf5763bSVijaya Kumar K 		 * Packet D (Detach), k (kill). No special handling
185bcf5763bSVijaya Kumar K 		 * is required here. Handle same as c packet.
186bcf5763bSVijaya Kumar K 		 */
187bcf5763bSVijaya Kumar K 	case 'c':
188bcf5763bSVijaya Kumar K 		/*
189bcf5763bSVijaya Kumar K 		 * Packet c (Continue) to continue executing.
190bcf5763bSVijaya Kumar K 		 * Set pc to required address.
191bcf5763bSVijaya Kumar K 		 * Try to read optional parameter and set pc.
192bcf5763bSVijaya Kumar K 		 * If this was a compiled breakpoint, we need to move
193bcf5763bSVijaya Kumar K 		 * to the next instruction else we will just breakpoint
194bcf5763bSVijaya Kumar K 		 * over and over again.
195bcf5763bSVijaya Kumar K 		 */
19644679a4fSVijaya Kumar K 		kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
19744679a4fSVijaya Kumar K 		atomic_set(&kgdb_cpu_doing_single_step, -1);
19844679a4fSVijaya Kumar K 		kgdb_single_step =  0;
199bcf5763bSVijaya Kumar K 
20044679a4fSVijaya Kumar K 		/*
20144679a4fSVijaya Kumar K 		 * Received continue command, disable single step
20244679a4fSVijaya Kumar K 		 */
20344679a4fSVijaya Kumar K 		if (kernel_active_single_step())
20444679a4fSVijaya Kumar K 			kernel_disable_single_step();
20544679a4fSVijaya Kumar K 
20644679a4fSVijaya Kumar K 		err = 0;
20744679a4fSVijaya Kumar K 		break;
20844679a4fSVijaya Kumar K 	case 's':
20944679a4fSVijaya Kumar K 		/*
21044679a4fSVijaya Kumar K 		 * Update step address value with address passed
21144679a4fSVijaya Kumar K 		 * with step packet.
21244679a4fSVijaya Kumar K 		 * On debug exception return PC is copied to ELR
21344679a4fSVijaya Kumar K 		 * So just update PC.
21444679a4fSVijaya Kumar K 		 * If no step address is passed, resume from the address
21544679a4fSVijaya Kumar K 		 * pointed by PC. Do not update PC
21644679a4fSVijaya Kumar K 		 */
21744679a4fSVijaya Kumar K 		kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
21844679a4fSVijaya Kumar K 		atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id());
21944679a4fSVijaya Kumar K 		kgdb_single_step =  1;
22044679a4fSVijaya Kumar K 
22144679a4fSVijaya Kumar K 		/*
22244679a4fSVijaya Kumar K 		 * Enable single step handling
22344679a4fSVijaya Kumar K 		 */
22444679a4fSVijaya Kumar K 		if (!kernel_active_single_step())
22544679a4fSVijaya Kumar K 			kernel_enable_single_step(linux_regs);
226bcf5763bSVijaya Kumar K 		err = 0;
227bcf5763bSVijaya Kumar K 		break;
228bcf5763bSVijaya Kumar K 	default:
229bcf5763bSVijaya Kumar K 		err = -1;
230bcf5763bSVijaya Kumar K 	}
231bcf5763bSVijaya Kumar K 	return err;
232bcf5763bSVijaya Kumar K }
233bcf5763bSVijaya Kumar K 
234bcf5763bSVijaya Kumar K static int kgdb_brk_fn(struct pt_regs *regs, unsigned int esr)
235bcf5763bSVijaya Kumar K {
236bcf5763bSVijaya Kumar K 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
2376bd28856SWill Deacon 	return DBG_HOOK_HANDLED;
238bcf5763bSVijaya Kumar K }
23944b53f67SPratyush Anand NOKPROBE_SYMBOL(kgdb_brk_fn)
240bcf5763bSVijaya Kumar K 
241bcf5763bSVijaya Kumar K static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr)
242bcf5763bSVijaya Kumar K {
243bcf5763bSVijaya Kumar K 	compiled_break = 1;
244bcf5763bSVijaya Kumar K 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
245bcf5763bSVijaya Kumar K 
2466bd28856SWill Deacon 	return DBG_HOOK_HANDLED;
247bcf5763bSVijaya Kumar K }
24844b53f67SPratyush Anand NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);
249bcf5763bSVijaya Kumar K 
25044679a4fSVijaya Kumar K static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
25144679a4fSVijaya Kumar K {
252fb610f2aSWill Deacon 	if (!kgdb_single_step)
253b66c9870SPratyush Anand 		return DBG_HOOK_ERROR;
254b66c9870SPratyush Anand 
25544679a4fSVijaya Kumar K 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
2566bd28856SWill Deacon 	return DBG_HOOK_HANDLED;
25744679a4fSVijaya Kumar K }
25844b53f67SPratyush Anand NOKPROBE_SYMBOL(kgdb_step_brk_fn);
25944679a4fSVijaya Kumar K 
260bcf5763bSVijaya Kumar K static struct break_hook kgdb_brkpt_hook = {
26126a04d84SWill Deacon 	.fn		= kgdb_brk_fn,
26226a04d84SWill Deacon 	.imm		= KGDB_DYN_DBG_BRK_IMM,
263bcf5763bSVijaya Kumar K };
264bcf5763bSVijaya Kumar K 
265bcf5763bSVijaya Kumar K static struct break_hook kgdb_compiled_brkpt_hook = {
26626a04d84SWill Deacon 	.fn		= kgdb_compiled_brk_fn,
26726a04d84SWill Deacon 	.imm		= KGDB_COMPILED_DBG_BRK_IMM,
268bcf5763bSVijaya Kumar K };
269bcf5763bSVijaya Kumar K 
27044679a4fSVijaya Kumar K static struct step_hook kgdb_step_hook = {
27144679a4fSVijaya Kumar K 	.fn		= kgdb_step_brk_fn
27244679a4fSVijaya Kumar K };
27344679a4fSVijaya Kumar K 
274bcf5763bSVijaya Kumar K static int __kgdb_notify(struct die_args *args, unsigned long cmd)
275bcf5763bSVijaya Kumar K {
276bcf5763bSVijaya Kumar K 	struct pt_regs *regs = args->regs;
277bcf5763bSVijaya Kumar K 
278bcf5763bSVijaya Kumar K 	if (kgdb_handle_exception(1, args->signr, cmd, regs))
279bcf5763bSVijaya Kumar K 		return NOTIFY_DONE;
280bcf5763bSVijaya Kumar K 	return NOTIFY_STOP;
281bcf5763bSVijaya Kumar K }
282bcf5763bSVijaya Kumar K 
283bcf5763bSVijaya Kumar K static int
284bcf5763bSVijaya Kumar K kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
285bcf5763bSVijaya Kumar K {
286bcf5763bSVijaya Kumar K 	unsigned long flags;
287bcf5763bSVijaya Kumar K 	int ret;
288bcf5763bSVijaya Kumar K 
289bcf5763bSVijaya Kumar K 	local_irq_save(flags);
290bcf5763bSVijaya Kumar K 	ret = __kgdb_notify(ptr, cmd);
291bcf5763bSVijaya Kumar K 	local_irq_restore(flags);
292bcf5763bSVijaya Kumar K 
293bcf5763bSVijaya Kumar K 	return ret;
294bcf5763bSVijaya Kumar K }
295bcf5763bSVijaya Kumar K 
296bcf5763bSVijaya Kumar K static struct notifier_block kgdb_notifier = {
297bcf5763bSVijaya Kumar K 	.notifier_call	= kgdb_notify,
298bcf5763bSVijaya Kumar K 	/*
299bcf5763bSVijaya Kumar K 	 * Want to be lowest priority
300bcf5763bSVijaya Kumar K 	 */
301bcf5763bSVijaya Kumar K 	.priority	= -INT_MAX,
302bcf5763bSVijaya Kumar K };
303bcf5763bSVijaya Kumar K 
304bcf5763bSVijaya Kumar K /*
305ef769e32SAdam Buchbinder  * kgdb_arch_init - Perform any architecture specific initialization.
306ef769e32SAdam Buchbinder  * This function will handle the initialization of any architecture
307bcf5763bSVijaya Kumar K  * specific callbacks.
308bcf5763bSVijaya Kumar K  */
309bcf5763bSVijaya Kumar K int kgdb_arch_init(void)
310bcf5763bSVijaya Kumar K {
311bcf5763bSVijaya Kumar K 	int ret = register_die_notifier(&kgdb_notifier);
312bcf5763bSVijaya Kumar K 
313bcf5763bSVijaya Kumar K 	if (ret != 0)
314bcf5763bSVijaya Kumar K 		return ret;
315bcf5763bSVijaya Kumar K 
31626a04d84SWill Deacon 	register_kernel_break_hook(&kgdb_brkpt_hook);
31726a04d84SWill Deacon 	register_kernel_break_hook(&kgdb_compiled_brkpt_hook);
31826a04d84SWill Deacon 	register_kernel_step_hook(&kgdb_step_hook);
319bcf5763bSVijaya Kumar K 	return 0;
320bcf5763bSVijaya Kumar K }
321bcf5763bSVijaya Kumar K 
322bcf5763bSVijaya Kumar K /*
323bcf5763bSVijaya Kumar K  * kgdb_arch_exit - Perform any architecture specific uninitalization.
324bcf5763bSVijaya Kumar K  * This function will handle the uninitalization of any architecture
325bcf5763bSVijaya Kumar K  * specific callbacks, for dynamic registration and unregistration.
326bcf5763bSVijaya Kumar K  */
327bcf5763bSVijaya Kumar K void kgdb_arch_exit(void)
328bcf5763bSVijaya Kumar K {
32926a04d84SWill Deacon 	unregister_kernel_break_hook(&kgdb_brkpt_hook);
33026a04d84SWill Deacon 	unregister_kernel_break_hook(&kgdb_compiled_brkpt_hook);
33126a04d84SWill Deacon 	unregister_kernel_step_hook(&kgdb_step_hook);
332bcf5763bSVijaya Kumar K 	unregister_die_notifier(&kgdb_notifier);
333bcf5763bSVijaya Kumar K }
334bcf5763bSVijaya Kumar K 
335cc028297SChristophe Leroy const struct kgdb_arch arch_kgdb_ops;
33667787b68SAKASHI Takahiro 
33767787b68SAKASHI Takahiro int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
33867787b68SAKASHI Takahiro {
33967787b68SAKASHI Takahiro 	int err;
34067787b68SAKASHI Takahiro 
34167787b68SAKASHI Takahiro 	BUILD_BUG_ON(AARCH64_INSN_SIZE != BREAK_INSTR_SIZE);
34267787b68SAKASHI Takahiro 
34367787b68SAKASHI Takahiro 	err = aarch64_insn_read((void *)bpt->bpt_addr, (u32 *)bpt->saved_instr);
34467787b68SAKASHI Takahiro 	if (err)
34567787b68SAKASHI Takahiro 		return err;
34667787b68SAKASHI Takahiro 
34767787b68SAKASHI Takahiro 	return aarch64_insn_write((void *)bpt->bpt_addr,
34867787b68SAKASHI Takahiro 			(u32)AARCH64_BREAK_KGDB_DYN_DBG);
349bcf5763bSVijaya Kumar K }
35067787b68SAKASHI Takahiro 
35167787b68SAKASHI Takahiro int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
35267787b68SAKASHI Takahiro {
35367787b68SAKASHI Takahiro 	return aarch64_insn_write((void *)bpt->bpt_addr,
35467787b68SAKASHI Takahiro 			*(u32 *)bpt->saved_instr);
35567787b68SAKASHI Takahiro }
356