xref: /openbmc/linux/arch/arm64/kernel/kgdb.c (revision fb610f2a)
1bcf5763bSVijaya Kumar K /*
2bcf5763bSVijaya Kumar K  * AArch64 KGDB support
3bcf5763bSVijaya Kumar K  *
4bcf5763bSVijaya Kumar K  * Based on arch/arm/kernel/kgdb.c
5bcf5763bSVijaya Kumar K  *
6bcf5763bSVijaya Kumar K  * Copyright (C) 2013 Cavium Inc.
7bcf5763bSVijaya Kumar K  * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
8bcf5763bSVijaya Kumar K  *
9bcf5763bSVijaya Kumar K  * This program is free software; you can redistribute it and/or modify
10bcf5763bSVijaya Kumar K  * it under the terms of the GNU General Public License version 2 as
11bcf5763bSVijaya Kumar K  * published by the Free Software Foundation.
12bcf5763bSVijaya Kumar K  *
13bcf5763bSVijaya Kumar K  * This program is distributed in the hope that it will be useful,
14bcf5763bSVijaya Kumar K  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15bcf5763bSVijaya Kumar K  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16bcf5763bSVijaya Kumar K  * GNU General Public License for more details.
17bcf5763bSVijaya Kumar K  *
18bcf5763bSVijaya Kumar K  * You should have received a copy of the GNU General Public License
19bcf5763bSVijaya Kumar K  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20bcf5763bSVijaya Kumar K  */
21bcf5763bSVijaya Kumar K 
2267787b68SAKASHI Takahiro #include <linux/bug.h>
23bcf5763bSVijaya Kumar K #include <linux/irq.h>
24bcf5763bSVijaya Kumar K #include <linux/kdebug.h>
25bcf5763bSVijaya Kumar K #include <linux/kgdb.h>
2644b53f67SPratyush Anand #include <linux/kprobes.h>
2768db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
2868db0cf1SIngo Molnar 
2967787b68SAKASHI Takahiro #include <asm/debug-monitors.h>
3067787b68SAKASHI Takahiro #include <asm/insn.h>
31bcf5763bSVijaya Kumar K #include <asm/traps.h>
32bcf5763bSVijaya Kumar K 
33bcf5763bSVijaya Kumar K struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
34bcf5763bSVijaya Kumar K 	{ "x0", 8, offsetof(struct pt_regs, regs[0])},
35bcf5763bSVijaya Kumar K 	{ "x1", 8, offsetof(struct pt_regs, regs[1])},
36bcf5763bSVijaya Kumar K 	{ "x2", 8, offsetof(struct pt_regs, regs[2])},
37bcf5763bSVijaya Kumar K 	{ "x3", 8, offsetof(struct pt_regs, regs[3])},
38bcf5763bSVijaya Kumar K 	{ "x4", 8, offsetof(struct pt_regs, regs[4])},
39bcf5763bSVijaya Kumar K 	{ "x5", 8, offsetof(struct pt_regs, regs[5])},
40bcf5763bSVijaya Kumar K 	{ "x6", 8, offsetof(struct pt_regs, regs[6])},
41bcf5763bSVijaya Kumar K 	{ "x7", 8, offsetof(struct pt_regs, regs[7])},
42bcf5763bSVijaya Kumar K 	{ "x8", 8, offsetof(struct pt_regs, regs[8])},
43bcf5763bSVijaya Kumar K 	{ "x9", 8, offsetof(struct pt_regs, regs[9])},
44bcf5763bSVijaya Kumar K 	{ "x10", 8, offsetof(struct pt_regs, regs[10])},
45bcf5763bSVijaya Kumar K 	{ "x11", 8, offsetof(struct pt_regs, regs[11])},
46bcf5763bSVijaya Kumar K 	{ "x12", 8, offsetof(struct pt_regs, regs[12])},
47bcf5763bSVijaya Kumar K 	{ "x13", 8, offsetof(struct pt_regs, regs[13])},
48bcf5763bSVijaya Kumar K 	{ "x14", 8, offsetof(struct pt_regs, regs[14])},
49bcf5763bSVijaya Kumar K 	{ "x15", 8, offsetof(struct pt_regs, regs[15])},
50bcf5763bSVijaya Kumar K 	{ "x16", 8, offsetof(struct pt_regs, regs[16])},
51bcf5763bSVijaya Kumar K 	{ "x17", 8, offsetof(struct pt_regs, regs[17])},
52bcf5763bSVijaya Kumar K 	{ "x18", 8, offsetof(struct pt_regs, regs[18])},
53bcf5763bSVijaya Kumar K 	{ "x19", 8, offsetof(struct pt_regs, regs[19])},
54bcf5763bSVijaya Kumar K 	{ "x20", 8, offsetof(struct pt_regs, regs[20])},
55bcf5763bSVijaya Kumar K 	{ "x21", 8, offsetof(struct pt_regs, regs[21])},
56bcf5763bSVijaya Kumar K 	{ "x22", 8, offsetof(struct pt_regs, regs[22])},
57bcf5763bSVijaya Kumar K 	{ "x23", 8, offsetof(struct pt_regs, regs[23])},
58bcf5763bSVijaya Kumar K 	{ "x24", 8, offsetof(struct pt_regs, regs[24])},
59bcf5763bSVijaya Kumar K 	{ "x25", 8, offsetof(struct pt_regs, regs[25])},
60bcf5763bSVijaya Kumar K 	{ "x26", 8, offsetof(struct pt_regs, regs[26])},
61bcf5763bSVijaya Kumar K 	{ "x27", 8, offsetof(struct pt_regs, regs[27])},
62bcf5763bSVijaya Kumar K 	{ "x28", 8, offsetof(struct pt_regs, regs[28])},
63bcf5763bSVijaya Kumar K 	{ "x29", 8, offsetof(struct pt_regs, regs[29])},
64bcf5763bSVijaya Kumar K 	{ "x30", 8, offsetof(struct pt_regs, regs[30])},
65bcf5763bSVijaya Kumar K 	{ "sp", 8, offsetof(struct pt_regs, sp)},
66bcf5763bSVijaya Kumar K 	{ "pc", 8, offsetof(struct pt_regs, pc)},
670d15ef67SDaniel Thompson 	/*
680d15ef67SDaniel Thompson 	 * struct pt_regs thinks PSTATE is 64-bits wide but gdb remote
690d15ef67SDaniel Thompson 	 * protocol disagrees. Therefore we must extract only the lower
700d15ef67SDaniel Thompson 	 * 32-bits. Look for the big comment in asm/kgdb.h for more
710d15ef67SDaniel Thompson 	 * detail.
720d15ef67SDaniel Thompson 	 */
730d15ef67SDaniel Thompson 	{ "pstate", 4, offsetof(struct pt_regs, pstate)
740d15ef67SDaniel Thompson #ifdef CONFIG_CPU_BIG_ENDIAN
750d15ef67SDaniel Thompson 							+ 4
760d15ef67SDaniel Thompson #endif
770d15ef67SDaniel Thompson 	},
78bcf5763bSVijaya Kumar K 	{ "v0", 16, -1 },
79bcf5763bSVijaya Kumar K 	{ "v1", 16, -1 },
80bcf5763bSVijaya Kumar K 	{ "v2", 16, -1 },
81bcf5763bSVijaya Kumar K 	{ "v3", 16, -1 },
82bcf5763bSVijaya Kumar K 	{ "v4", 16, -1 },
83bcf5763bSVijaya Kumar K 	{ "v5", 16, -1 },
84bcf5763bSVijaya Kumar K 	{ "v6", 16, -1 },
85bcf5763bSVijaya Kumar K 	{ "v7", 16, -1 },
86bcf5763bSVijaya Kumar K 	{ "v8", 16, -1 },
87bcf5763bSVijaya Kumar K 	{ "v9", 16, -1 },
88bcf5763bSVijaya Kumar K 	{ "v10", 16, -1 },
89bcf5763bSVijaya Kumar K 	{ "v11", 16, -1 },
90bcf5763bSVijaya Kumar K 	{ "v12", 16, -1 },
91bcf5763bSVijaya Kumar K 	{ "v13", 16, -1 },
92bcf5763bSVijaya Kumar K 	{ "v14", 16, -1 },
93bcf5763bSVijaya Kumar K 	{ "v15", 16, -1 },
94bcf5763bSVijaya Kumar K 	{ "v16", 16, -1 },
95bcf5763bSVijaya Kumar K 	{ "v17", 16, -1 },
96bcf5763bSVijaya Kumar K 	{ "v18", 16, -1 },
97bcf5763bSVijaya Kumar K 	{ "v19", 16, -1 },
98bcf5763bSVijaya Kumar K 	{ "v20", 16, -1 },
99bcf5763bSVijaya Kumar K 	{ "v21", 16, -1 },
100bcf5763bSVijaya Kumar K 	{ "v22", 16, -1 },
101bcf5763bSVijaya Kumar K 	{ "v23", 16, -1 },
102bcf5763bSVijaya Kumar K 	{ "v24", 16, -1 },
103bcf5763bSVijaya Kumar K 	{ "v25", 16, -1 },
104bcf5763bSVijaya Kumar K 	{ "v26", 16, -1 },
105bcf5763bSVijaya Kumar K 	{ "v27", 16, -1 },
106bcf5763bSVijaya Kumar K 	{ "v28", 16, -1 },
107bcf5763bSVijaya Kumar K 	{ "v29", 16, -1 },
108bcf5763bSVijaya Kumar K 	{ "v30", 16, -1 },
109bcf5763bSVijaya Kumar K 	{ "v31", 16, -1 },
110bcf5763bSVijaya Kumar K 	{ "fpsr", 4, -1 },
111bcf5763bSVijaya Kumar K 	{ "fpcr", 4, -1 },
112bcf5763bSVijaya Kumar K };
113bcf5763bSVijaya Kumar K 
114bcf5763bSVijaya Kumar K char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
115bcf5763bSVijaya Kumar K {
116bcf5763bSVijaya Kumar K 	if (regno >= DBG_MAX_REG_NUM || regno < 0)
117bcf5763bSVijaya Kumar K 		return NULL;
118bcf5763bSVijaya Kumar K 
119bcf5763bSVijaya Kumar K 	if (dbg_reg_def[regno].offset != -1)
120bcf5763bSVijaya Kumar K 		memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
121bcf5763bSVijaya Kumar K 		       dbg_reg_def[regno].size);
122bcf5763bSVijaya Kumar K 	else
123bcf5763bSVijaya Kumar K 		memset(mem, 0, dbg_reg_def[regno].size);
124bcf5763bSVijaya Kumar K 	return dbg_reg_def[regno].name;
125bcf5763bSVijaya Kumar K }
126bcf5763bSVijaya Kumar K 
127bcf5763bSVijaya Kumar K int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
128bcf5763bSVijaya Kumar K {
129bcf5763bSVijaya Kumar K 	if (regno >= DBG_MAX_REG_NUM || regno < 0)
130bcf5763bSVijaya Kumar K 		return -EINVAL;
131bcf5763bSVijaya Kumar K 
132bcf5763bSVijaya Kumar K 	if (dbg_reg_def[regno].offset != -1)
133bcf5763bSVijaya Kumar K 		memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
134bcf5763bSVijaya Kumar K 		       dbg_reg_def[regno].size);
135bcf5763bSVijaya Kumar K 	return 0;
136bcf5763bSVijaya Kumar K }
137bcf5763bSVijaya Kumar K 
138bcf5763bSVijaya Kumar K void
139bcf5763bSVijaya Kumar K sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
140bcf5763bSVijaya Kumar K {
14124153c03SDouglas Anderson 	struct cpu_context *cpu_context = &task->thread.cpu_context;
142bcf5763bSVijaya Kumar K 
143bcf5763bSVijaya Kumar K 	/* Initialize to zero */
144bcf5763bSVijaya Kumar K 	memset((char *)gdb_regs, 0, NUMREGBYTES);
14524153c03SDouglas Anderson 
14624153c03SDouglas Anderson 	gdb_regs[19] = cpu_context->x19;
14724153c03SDouglas Anderson 	gdb_regs[20] = cpu_context->x20;
14824153c03SDouglas Anderson 	gdb_regs[21] = cpu_context->x21;
14924153c03SDouglas Anderson 	gdb_regs[22] = cpu_context->x22;
15024153c03SDouglas Anderson 	gdb_regs[23] = cpu_context->x23;
15124153c03SDouglas Anderson 	gdb_regs[24] = cpu_context->x24;
15224153c03SDouglas Anderson 	gdb_regs[25] = cpu_context->x25;
15324153c03SDouglas Anderson 	gdb_regs[26] = cpu_context->x26;
15424153c03SDouglas Anderson 	gdb_regs[27] = cpu_context->x27;
15524153c03SDouglas Anderson 	gdb_regs[28] = cpu_context->x28;
15624153c03SDouglas Anderson 	gdb_regs[29] = cpu_context->fp;
15724153c03SDouglas Anderson 
15824153c03SDouglas Anderson 	gdb_regs[31] = cpu_context->sp;
15924153c03SDouglas Anderson 	gdb_regs[32] = cpu_context->pc;
160bcf5763bSVijaya Kumar K }
161bcf5763bSVijaya Kumar K 
162bcf5763bSVijaya Kumar K void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
163bcf5763bSVijaya Kumar K {
164bcf5763bSVijaya Kumar K 	regs->pc = pc;
165bcf5763bSVijaya Kumar K }
166bcf5763bSVijaya Kumar K 
167bcf5763bSVijaya Kumar K static int compiled_break;
168bcf5763bSVijaya Kumar K 
16944679a4fSVijaya Kumar K static void kgdb_arch_update_addr(struct pt_regs *regs,
17044679a4fSVijaya Kumar K 				char *remcom_in_buffer)
17144679a4fSVijaya Kumar K {
17244679a4fSVijaya Kumar K 	unsigned long addr;
17344679a4fSVijaya Kumar K 	char *ptr;
17444679a4fSVijaya Kumar K 
17544679a4fSVijaya Kumar K 	ptr = &remcom_in_buffer[1];
17644679a4fSVijaya Kumar K 	if (kgdb_hex2long(&ptr, &addr))
17744679a4fSVijaya Kumar K 		kgdb_arch_set_pc(regs, addr);
17844679a4fSVijaya Kumar K 	else if (compiled_break == 1)
17944679a4fSVijaya Kumar K 		kgdb_arch_set_pc(regs, regs->pc + 4);
18044679a4fSVijaya Kumar K 
18144679a4fSVijaya Kumar K 	compiled_break = 0;
18244679a4fSVijaya Kumar K }
18344679a4fSVijaya Kumar K 
184bcf5763bSVijaya Kumar K int kgdb_arch_handle_exception(int exception_vector, int signo,
185bcf5763bSVijaya Kumar K 			       int err_code, char *remcom_in_buffer,
186bcf5763bSVijaya Kumar K 			       char *remcom_out_buffer,
187bcf5763bSVijaya Kumar K 			       struct pt_regs *linux_regs)
188bcf5763bSVijaya Kumar K {
189bcf5763bSVijaya Kumar K 	int err;
190bcf5763bSVijaya Kumar K 
191bcf5763bSVijaya Kumar K 	switch (remcom_in_buffer[0]) {
192bcf5763bSVijaya Kumar K 	case 'D':
193bcf5763bSVijaya Kumar K 	case 'k':
194bcf5763bSVijaya Kumar K 		/*
195bcf5763bSVijaya Kumar K 		 * Packet D (Detach), k (kill). No special handling
196bcf5763bSVijaya Kumar K 		 * is required here. Handle same as c packet.
197bcf5763bSVijaya Kumar K 		 */
198bcf5763bSVijaya Kumar K 	case 'c':
199bcf5763bSVijaya Kumar K 		/*
200bcf5763bSVijaya Kumar K 		 * Packet c (Continue) to continue executing.
201bcf5763bSVijaya Kumar K 		 * Set pc to required address.
202bcf5763bSVijaya Kumar K 		 * Try to read optional parameter and set pc.
203bcf5763bSVijaya Kumar K 		 * If this was a compiled breakpoint, we need to move
204bcf5763bSVijaya Kumar K 		 * to the next instruction else we will just breakpoint
205bcf5763bSVijaya Kumar K 		 * over and over again.
206bcf5763bSVijaya Kumar K 		 */
20744679a4fSVijaya Kumar K 		kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
20844679a4fSVijaya Kumar K 		atomic_set(&kgdb_cpu_doing_single_step, -1);
20944679a4fSVijaya Kumar K 		kgdb_single_step =  0;
210bcf5763bSVijaya Kumar K 
21144679a4fSVijaya Kumar K 		/*
21244679a4fSVijaya Kumar K 		 * Received continue command, disable single step
21344679a4fSVijaya Kumar K 		 */
21444679a4fSVijaya Kumar K 		if (kernel_active_single_step())
21544679a4fSVijaya Kumar K 			kernel_disable_single_step();
21644679a4fSVijaya Kumar K 
21744679a4fSVijaya Kumar K 		err = 0;
21844679a4fSVijaya Kumar K 		break;
21944679a4fSVijaya Kumar K 	case 's':
22044679a4fSVijaya Kumar K 		/*
22144679a4fSVijaya Kumar K 		 * Update step address value with address passed
22244679a4fSVijaya Kumar K 		 * with step packet.
22344679a4fSVijaya Kumar K 		 * On debug exception return PC is copied to ELR
22444679a4fSVijaya Kumar K 		 * So just update PC.
22544679a4fSVijaya Kumar K 		 * If no step address is passed, resume from the address
22644679a4fSVijaya Kumar K 		 * pointed by PC. Do not update PC
22744679a4fSVijaya Kumar K 		 */
22844679a4fSVijaya Kumar K 		kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
22944679a4fSVijaya Kumar K 		atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id());
23044679a4fSVijaya Kumar K 		kgdb_single_step =  1;
23144679a4fSVijaya Kumar K 
23244679a4fSVijaya Kumar K 		/*
23344679a4fSVijaya Kumar K 		 * Enable single step handling
23444679a4fSVijaya Kumar K 		 */
23544679a4fSVijaya Kumar K 		if (!kernel_active_single_step())
23644679a4fSVijaya Kumar K 			kernel_enable_single_step(linux_regs);
237bcf5763bSVijaya Kumar K 		err = 0;
238bcf5763bSVijaya Kumar K 		break;
239bcf5763bSVijaya Kumar K 	default:
240bcf5763bSVijaya Kumar K 		err = -1;
241bcf5763bSVijaya Kumar K 	}
242bcf5763bSVijaya Kumar K 	return err;
243bcf5763bSVijaya Kumar K }
244bcf5763bSVijaya Kumar K 
245bcf5763bSVijaya Kumar K static int kgdb_brk_fn(struct pt_regs *regs, unsigned int esr)
246bcf5763bSVijaya Kumar K {
247bcf5763bSVijaya Kumar K 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
2486bd28856SWill Deacon 	return DBG_HOOK_HANDLED;
249bcf5763bSVijaya Kumar K }
25044b53f67SPratyush Anand NOKPROBE_SYMBOL(kgdb_brk_fn)
251bcf5763bSVijaya Kumar K 
252bcf5763bSVijaya Kumar K static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int esr)
253bcf5763bSVijaya Kumar K {
254bcf5763bSVijaya Kumar K 	compiled_break = 1;
255bcf5763bSVijaya Kumar K 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
256bcf5763bSVijaya Kumar K 
2576bd28856SWill Deacon 	return DBG_HOOK_HANDLED;
258bcf5763bSVijaya Kumar K }
25944b53f67SPratyush Anand NOKPROBE_SYMBOL(kgdb_compiled_brk_fn);
260bcf5763bSVijaya Kumar K 
26144679a4fSVijaya Kumar K static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr)
26244679a4fSVijaya Kumar K {
263fb610f2aSWill Deacon 	if (!kgdb_single_step)
264b66c9870SPratyush Anand 		return DBG_HOOK_ERROR;
265b66c9870SPratyush Anand 
26644679a4fSVijaya Kumar K 	kgdb_handle_exception(1, SIGTRAP, 0, regs);
2676bd28856SWill Deacon 	return DBG_HOOK_HANDLED;
26844679a4fSVijaya Kumar K }
26944b53f67SPratyush Anand NOKPROBE_SYMBOL(kgdb_step_brk_fn);
27044679a4fSVijaya Kumar K 
271bcf5763bSVijaya Kumar K static struct break_hook kgdb_brkpt_hook = {
27226a04d84SWill Deacon 	.fn		= kgdb_brk_fn,
27326a04d84SWill Deacon 	.imm		= KGDB_DYN_DBG_BRK_IMM,
274bcf5763bSVijaya Kumar K };
275bcf5763bSVijaya Kumar K 
276bcf5763bSVijaya Kumar K static struct break_hook kgdb_compiled_brkpt_hook = {
27726a04d84SWill Deacon 	.fn		= kgdb_compiled_brk_fn,
27826a04d84SWill Deacon 	.imm		= KGDB_COMPILED_DBG_BRK_IMM,
279bcf5763bSVijaya Kumar K };
280bcf5763bSVijaya Kumar K 
28144679a4fSVijaya Kumar K static struct step_hook kgdb_step_hook = {
28244679a4fSVijaya Kumar K 	.fn		= kgdb_step_brk_fn
28344679a4fSVijaya Kumar K };
28444679a4fSVijaya Kumar K 
285bcf5763bSVijaya Kumar K static int __kgdb_notify(struct die_args *args, unsigned long cmd)
286bcf5763bSVijaya Kumar K {
287bcf5763bSVijaya Kumar K 	struct pt_regs *regs = args->regs;
288bcf5763bSVijaya Kumar K 
289bcf5763bSVijaya Kumar K 	if (kgdb_handle_exception(1, args->signr, cmd, regs))
290bcf5763bSVijaya Kumar K 		return NOTIFY_DONE;
291bcf5763bSVijaya Kumar K 	return NOTIFY_STOP;
292bcf5763bSVijaya Kumar K }
293bcf5763bSVijaya Kumar K 
294bcf5763bSVijaya Kumar K static int
295bcf5763bSVijaya Kumar K kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
296bcf5763bSVijaya Kumar K {
297bcf5763bSVijaya Kumar K 	unsigned long flags;
298bcf5763bSVijaya Kumar K 	int ret;
299bcf5763bSVijaya Kumar K 
300bcf5763bSVijaya Kumar K 	local_irq_save(flags);
301bcf5763bSVijaya Kumar K 	ret = __kgdb_notify(ptr, cmd);
302bcf5763bSVijaya Kumar K 	local_irq_restore(flags);
303bcf5763bSVijaya Kumar K 
304bcf5763bSVijaya Kumar K 	return ret;
305bcf5763bSVijaya Kumar K }
306bcf5763bSVijaya Kumar K 
307bcf5763bSVijaya Kumar K static struct notifier_block kgdb_notifier = {
308bcf5763bSVijaya Kumar K 	.notifier_call	= kgdb_notify,
309bcf5763bSVijaya Kumar K 	/*
310bcf5763bSVijaya Kumar K 	 * Want to be lowest priority
311bcf5763bSVijaya Kumar K 	 */
312bcf5763bSVijaya Kumar K 	.priority	= -INT_MAX,
313bcf5763bSVijaya Kumar K };
314bcf5763bSVijaya Kumar K 
315bcf5763bSVijaya Kumar K /*
316ef769e32SAdam Buchbinder  * kgdb_arch_init - Perform any architecture specific initialization.
317ef769e32SAdam Buchbinder  * This function will handle the initialization of any architecture
318bcf5763bSVijaya Kumar K  * specific callbacks.
319bcf5763bSVijaya Kumar K  */
320bcf5763bSVijaya Kumar K int kgdb_arch_init(void)
321bcf5763bSVijaya Kumar K {
322bcf5763bSVijaya Kumar K 	int ret = register_die_notifier(&kgdb_notifier);
323bcf5763bSVijaya Kumar K 
324bcf5763bSVijaya Kumar K 	if (ret != 0)
325bcf5763bSVijaya Kumar K 		return ret;
326bcf5763bSVijaya Kumar K 
32726a04d84SWill Deacon 	register_kernel_break_hook(&kgdb_brkpt_hook);
32826a04d84SWill Deacon 	register_kernel_break_hook(&kgdb_compiled_brkpt_hook);
32926a04d84SWill Deacon 	register_kernel_step_hook(&kgdb_step_hook);
330bcf5763bSVijaya Kumar K 	return 0;
331bcf5763bSVijaya Kumar K }
332bcf5763bSVijaya Kumar K 
333bcf5763bSVijaya Kumar K /*
334bcf5763bSVijaya Kumar K  * kgdb_arch_exit - Perform any architecture specific uninitalization.
335bcf5763bSVijaya Kumar K  * This function will handle the uninitalization of any architecture
336bcf5763bSVijaya Kumar K  * specific callbacks, for dynamic registration and unregistration.
337bcf5763bSVijaya Kumar K  */
338bcf5763bSVijaya Kumar K void kgdb_arch_exit(void)
339bcf5763bSVijaya Kumar K {
34026a04d84SWill Deacon 	unregister_kernel_break_hook(&kgdb_brkpt_hook);
34126a04d84SWill Deacon 	unregister_kernel_break_hook(&kgdb_compiled_brkpt_hook);
34226a04d84SWill Deacon 	unregister_kernel_step_hook(&kgdb_step_hook);
343bcf5763bSVijaya Kumar K 	unregister_die_notifier(&kgdb_notifier);
344bcf5763bSVijaya Kumar K }
345bcf5763bSVijaya Kumar K 
346cc028297SChristophe Leroy const struct kgdb_arch arch_kgdb_ops;
34767787b68SAKASHI Takahiro 
34867787b68SAKASHI Takahiro int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
34967787b68SAKASHI Takahiro {
35067787b68SAKASHI Takahiro 	int err;
35167787b68SAKASHI Takahiro 
35267787b68SAKASHI Takahiro 	BUILD_BUG_ON(AARCH64_INSN_SIZE != BREAK_INSTR_SIZE);
35367787b68SAKASHI Takahiro 
35467787b68SAKASHI Takahiro 	err = aarch64_insn_read((void *)bpt->bpt_addr, (u32 *)bpt->saved_instr);
35567787b68SAKASHI Takahiro 	if (err)
35667787b68SAKASHI Takahiro 		return err;
35767787b68SAKASHI Takahiro 
35867787b68SAKASHI Takahiro 	return aarch64_insn_write((void *)bpt->bpt_addr,
35967787b68SAKASHI Takahiro 			(u32)AARCH64_BREAK_KGDB_DYN_DBG);
360bcf5763bSVijaya Kumar K }
36167787b68SAKASHI Takahiro 
36267787b68SAKASHI Takahiro int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
36367787b68SAKASHI Takahiro {
36467787b68SAKASHI Takahiro 	return aarch64_insn_write((void *)bpt->bpt_addr,
36567787b68SAKASHI Takahiro 			*(u32 *)bpt->saved_instr);
36667787b68SAKASHI Takahiro }
367