xref: /openbmc/linux/arch/powerpc/kernel/kgdb.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1577b61ceSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
217ce452fSJason Wessel /*
317ce452fSJason Wessel  * PowerPC backend to the KGDB stub.
417ce452fSJason Wessel  *
517ce452fSJason Wessel  * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu)
617ce452fSJason Wessel  * Copyright (C) 2003 Timesys Corporation.
717ce452fSJason Wessel  * Copyright (C) 2004-2006 MontaVista Software, Inc.
817ce452fSJason Wessel  * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com)
917ce452fSJason Wessel  * PPC32 support restored by Vitaly Wool <vwool@ru.mvista.com> and
1017ce452fSJason Wessel  * Sergei Shtylyov <sshtylyov@ru.mvista.com>
1117ce452fSJason Wessel  * Copyright (C) 2007-2008 Wind River Systems, Inc.
1217ce452fSJason Wessel  */
1317ce452fSJason Wessel 
1417ce452fSJason Wessel #include <linux/kernel.h>
1517ce452fSJason Wessel #include <linux/kgdb.h>
1617ce452fSJason Wessel #include <linux/smp.h>
1717ce452fSJason Wessel #include <linux/signal.h>
1817ce452fSJason Wessel #include <linux/ptrace.h>
19ba797b28SJason Wessel #include <linux/kdebug.h>
2017ce452fSJason Wessel #include <asm/current.h>
2117ce452fSJason Wessel #include <asm/processor.h>
2217ce452fSJason Wessel #include <asm/machdep.h>
23cad3c834SStephen Rothwell #include <asm/debug.h>
24fb978ca2SChristophe Leroy #include <asm/code-patching.h>
255f630401STiejun Chen #include <linux/slab.h>
2675346251SJordan Niethe #include <asm/inst.h>
2717ce452fSJason Wessel 
2817ce452fSJason Wessel /*
2917ce452fSJason Wessel  * This table contains the mapping between PowerPC hardware trap types, and
3017ce452fSJason Wessel  * signals, which are primarily what GDB understands.  GDB and the kernel
3117ce452fSJason Wessel  * don't always agree on values, so we use constants taken from gdb-6.2.
3217ce452fSJason Wessel  */
3317ce452fSJason Wessel static struct hard_trap_info
3417ce452fSJason Wessel {
3517ce452fSJason Wessel 	unsigned int tt;		/* Trap type code for powerpc */
3617ce452fSJason Wessel 	unsigned char signo;		/* Signal that we map this trap into */
3717ce452fSJason Wessel } hard_trap_info[] = {
3817ce452fSJason Wessel 	{ 0x0100, 0x02 /* SIGINT */  },		/* system reset */
3917ce452fSJason Wessel 	{ 0x0200, 0x0b /* SIGSEGV */ },		/* machine check */
4017ce452fSJason Wessel 	{ 0x0300, 0x0b /* SIGSEGV */ },		/* data access */
4117ce452fSJason Wessel 	{ 0x0400, 0x0b /* SIGSEGV */ },		/* instruction access */
4217ce452fSJason Wessel 	{ 0x0500, 0x02 /* SIGINT */  },		/* external interrupt */
4317ce452fSJason Wessel 	{ 0x0600, 0x0a /* SIGBUS */  },		/* alignment */
4417ce452fSJason Wessel 	{ 0x0700, 0x05 /* SIGTRAP */ },		/* program check */
4517ce452fSJason Wessel 	{ 0x0800, 0x08 /* SIGFPE */  },		/* fp unavailable */
4617ce452fSJason Wessel 	{ 0x0900, 0x0e /* SIGALRM */ },		/* decrementer */
4717ce452fSJason Wessel 	{ 0x0c00, 0x14 /* SIGCHLD */ },		/* system call */
48047a6fd4SChristophe Leroy #ifdef CONFIG_BOOKE_OR_40x
4917ce452fSJason Wessel 	{ 0x2002, 0x05 /* SIGTRAP */ },		/* debug */
50dfc3095cSChristophe Leroy #if defined(CONFIG_PPC_85xx)
5117ce452fSJason Wessel 	{ 0x2010, 0x08 /* SIGFPE */  },		/* spe unavailable */
5217ce452fSJason Wessel 	{ 0x2020, 0x08 /* SIGFPE */  },		/* spe unavailable */
5317ce452fSJason Wessel 	{ 0x2030, 0x08 /* SIGFPE */  },		/* spe fp data */
5417ce452fSJason Wessel 	{ 0x2040, 0x08 /* SIGFPE */  },		/* spe fp data */
5517ce452fSJason Wessel 	{ 0x2050, 0x08 /* SIGFPE */  },		/* spe fp round */
56af901ca1SAndré Goddard Rosa 	{ 0x2060, 0x0e /* SIGILL */  },		/* performance monitor */
5717ce452fSJason Wessel 	{ 0x2900, 0x08 /* SIGFPE */  },		/* apu unavailable */
5817ce452fSJason Wessel 	{ 0x3100, 0x0e /* SIGALRM */ },		/* fixed interval timer */
5917ce452fSJason Wessel 	{ 0x3200, 0x02 /* SIGINT */  }, 	/* watchdog */
60dfc3095cSChristophe Leroy #else /* ! CONFIG_PPC_85xx */
6117ce452fSJason Wessel 	{ 0x1000, 0x0e /* SIGALRM */ },		/* prog interval timer */
6217ce452fSJason Wessel 	{ 0x1010, 0x0e /* SIGALRM */ },		/* fixed interval timer */
6317ce452fSJason Wessel 	{ 0x1020, 0x02 /* SIGINT */  }, 	/* watchdog */
6417ce452fSJason Wessel 	{ 0x2010, 0x08 /* SIGFPE */  },		/* fp unavailable */
6517ce452fSJason Wessel 	{ 0x2020, 0x08 /* SIGFPE */  },		/* ap unavailable */
6617ce452fSJason Wessel #endif
67047a6fd4SChristophe Leroy #else /* !CONFIG_BOOKE_OR_40x */
6817ce452fSJason Wessel 	{ 0x0d00, 0x05 /* SIGTRAP */ },		/* single-step */
69968159c0SChristophe Leroy #if defined(CONFIG_PPC_8xx)
7017ce452fSJason Wessel 	{ 0x1000, 0x04 /* SIGILL */  },		/* software emulation */
71968159c0SChristophe Leroy #else /* ! CONFIG_PPC_8xx */
7217ce452fSJason Wessel 	{ 0x0f00, 0x04 /* SIGILL */  },		/* performance monitor */
7317ce452fSJason Wessel 	{ 0x0f20, 0x08 /* SIGFPE */  },		/* altivec unavailable */
7417ce452fSJason Wessel 	{ 0x1300, 0x05 /* SIGTRAP */ }, 	/* instruction address break */
7517ce452fSJason Wessel #if defined(CONFIG_PPC64)
7617ce452fSJason Wessel 	{ 0x1200, 0x05 /* SIGILL */  },		/* system error */
7717ce452fSJason Wessel 	{ 0x1500, 0x04 /* SIGILL */  },		/* soft patch */
7817ce452fSJason Wessel 	{ 0x1600, 0x04 /* SIGILL */  },		/* maintenance */
7917ce452fSJason Wessel 	{ 0x1700, 0x08 /* SIGFPE */  },		/* altivec assist */
8017ce452fSJason Wessel 	{ 0x1800, 0x04 /* SIGILL */  },		/* thermal */
8117ce452fSJason Wessel #else /* ! CONFIG_PPC64 */
8217ce452fSJason Wessel 	{ 0x1400, 0x02 /* SIGINT */  },		/* SMI */
8317ce452fSJason Wessel 	{ 0x1600, 0x08 /* SIGFPE */  },		/* altivec assist */
8417ce452fSJason Wessel 	{ 0x1700, 0x04 /* SIGILL */  },		/* TAU */
8517ce452fSJason Wessel 	{ 0x2000, 0x05 /* SIGTRAP */ },		/* run mode */
8617ce452fSJason Wessel #endif
8717ce452fSJason Wessel #endif
8817ce452fSJason Wessel #endif
8917ce452fSJason Wessel 	{ 0x0000, 0x00 }			/* Must be last */
9017ce452fSJason Wessel };
9117ce452fSJason Wessel 
computeSignal(unsigned int tt)9217ce452fSJason Wessel static int computeSignal(unsigned int tt)
9317ce452fSJason Wessel {
9417ce452fSJason Wessel 	struct hard_trap_info *ht;
9517ce452fSJason Wessel 
9617ce452fSJason Wessel 	for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
9717ce452fSJason Wessel 		if (ht->tt == tt)
9817ce452fSJason Wessel 			return ht->signo;
9917ce452fSJason Wessel 
10017ce452fSJason Wessel 	return SIGHUP;		/* default for things we don't know about */
10117ce452fSJason Wessel }
10217ce452fSJason Wessel 
103949616cfSTiejun Chen /**
104949616cfSTiejun Chen  *
105949616cfSTiejun Chen  *	kgdb_skipexception - Bail out of KGDB when we've been triggered.
106949616cfSTiejun Chen  *	@exception: Exception vector number
107949616cfSTiejun Chen  *	@regs: Current &struct pt_regs.
108949616cfSTiejun Chen  *
109949616cfSTiejun Chen  *	On some architectures we need to skip a breakpoint exception when
110949616cfSTiejun Chen  *	it occurs after a breakpoint has been removed.
111949616cfSTiejun Chen  *
112949616cfSTiejun Chen  */
kgdb_skipexception(int exception,struct pt_regs * regs)113949616cfSTiejun Chen int kgdb_skipexception(int exception, struct pt_regs *regs)
114949616cfSTiejun Chen {
115949616cfSTiejun Chen 	return kgdb_isremovedbreak(regs->nip);
116949616cfSTiejun Chen }
117949616cfSTiejun Chen 
kgdb_debugger_ipi(struct pt_regs * regs)1183cd99ac3SDouglas Anderson static int kgdb_debugger_ipi(struct pt_regs *regs)
11917ce452fSJason Wessel {
12017ce452fSJason Wessel 	kgdb_nmicallback(raw_smp_processor_id(), regs);
12117ce452fSJason Wessel 	return 0;
12217ce452fSJason Wessel }
12317ce452fSJason Wessel 
12417ce452fSJason Wessel #ifdef CONFIG_SMP
kgdb_roundup_cpus(void)1259ef7fa50SDouglas Anderson void kgdb_roundup_cpus(void)
12617ce452fSJason Wessel {
127e0476371SMilton Miller 	smp_send_debugger_break();
12817ce452fSJason Wessel }
12917ce452fSJason Wessel #endif
13017ce452fSJason Wessel 
13117ce452fSJason Wessel /* KGDB functions to use existing PowerPC64 hooks. */
kgdb_debugger(struct pt_regs * regs)13217ce452fSJason Wessel static int kgdb_debugger(struct pt_regs *regs)
13317ce452fSJason Wessel {
134ba797b28SJason Wessel 	return !kgdb_handle_exception(1, computeSignal(TRAP(regs)),
135ba797b28SJason Wessel 				      DIE_OOPS, regs);
13617ce452fSJason Wessel }
13717ce452fSJason Wessel 
kgdb_handle_breakpoint(struct pt_regs * regs)13817ce452fSJason Wessel static int kgdb_handle_breakpoint(struct pt_regs *regs)
13917ce452fSJason Wessel {
14017ce452fSJason Wessel 	if (user_mode(regs))
14117ce452fSJason Wessel 		return 0;
14217ce452fSJason Wessel 
143ba797b28SJason Wessel 	if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0)
14417ce452fSJason Wessel 		return 0;
14517ce452fSJason Wessel 
146fb978ca2SChristophe Leroy 	if (*(u32 *)regs->nip == BREAK_INSTR)
14759dc5bfcSNicholas Piggin 		regs_add_return_ip(regs, BREAK_INSTR_SIZE);
14817ce452fSJason Wessel 
14917ce452fSJason Wessel 	return 1;
15017ce452fSJason Wessel }
15117ce452fSJason Wessel 
kgdb_singlestep(struct pt_regs * regs)15217ce452fSJason Wessel static int kgdb_singlestep(struct pt_regs *regs)
15317ce452fSJason Wessel {
15417ce452fSJason Wessel 	if (user_mode(regs))
15517ce452fSJason Wessel 		return 0;
15617ce452fSJason Wessel 
15717ce452fSJason Wessel 	kgdb_handle_exception(0, SIGTRAP, 0, regs);
15817ce452fSJason Wessel 
15917ce452fSJason Wessel 	return 1;
16017ce452fSJason Wessel }
16117ce452fSJason Wessel 
kgdb_iabr_match(struct pt_regs * regs)16217ce452fSJason Wessel static int kgdb_iabr_match(struct pt_regs *regs)
16317ce452fSJason Wessel {
16417ce452fSJason Wessel 	if (user_mode(regs))
16517ce452fSJason Wessel 		return 0;
16617ce452fSJason Wessel 
16717ce452fSJason Wessel 	if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0)
16817ce452fSJason Wessel 		return 0;
16917ce452fSJason Wessel 	return 1;
17017ce452fSJason Wessel }
17117ce452fSJason Wessel 
kgdb_break_match(struct pt_regs * regs)1729422de3eSMichael Neuling static int kgdb_break_match(struct pt_regs *regs)
17317ce452fSJason Wessel {
17417ce452fSJason Wessel 	if (user_mode(regs))
17517ce452fSJason Wessel 		return 0;
17617ce452fSJason Wessel 
17717ce452fSJason Wessel 	if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0)
17817ce452fSJason Wessel 		return 0;
17917ce452fSJason Wessel 	return 1;
18017ce452fSJason Wessel }
18117ce452fSJason Wessel 
18217ce452fSJason Wessel #define PACK64(ptr, src) do { *(ptr++) = (src); } while (0)
18317ce452fSJason Wessel 
18417ce452fSJason Wessel #define PACK32(ptr, src) do {          \
18517ce452fSJason Wessel 	u32 *ptr32;                   \
18617ce452fSJason Wessel 	ptr32 = (u32 *)ptr;           \
18717ce452fSJason Wessel 	*(ptr32++) = (src);           \
18817ce452fSJason Wessel 	ptr = (unsigned long *)ptr32; \
18917ce452fSJason Wessel 	} while (0)
19017ce452fSJason Wessel 
sleeping_thread_to_gdb_regs(unsigned long * gdb_regs,struct task_struct * p)19117ce452fSJason Wessel void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
19217ce452fSJason Wessel {
19317ce452fSJason Wessel 	struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp +
194*c03be0a3SNicholas Piggin 						  STACK_INT_FRAME_REGS);
19517ce452fSJason Wessel 	unsigned long *ptr = gdb_regs;
19617ce452fSJason Wessel 	int reg;
19717ce452fSJason Wessel 
19817ce452fSJason Wessel 	memset(gdb_regs, 0, NUMREGBYTES);
19917ce452fSJason Wessel 
20017ce452fSJason Wessel 	/* Regs GPR0-2 */
20117ce452fSJason Wessel 	for (reg = 0; reg < 3; reg++)
20217ce452fSJason Wessel 		PACK64(ptr, regs->gpr[reg]);
20317ce452fSJason Wessel 
20417ce452fSJason Wessel 	/* Regs GPR3-13 are caller saved, not in regs->gpr[] */
20517ce452fSJason Wessel 	ptr += 11;
20617ce452fSJason Wessel 
20717ce452fSJason Wessel 	/* Regs GPR14-31 */
20817ce452fSJason Wessel 	for (reg = 14; reg < 32; reg++)
20917ce452fSJason Wessel 		PACK64(ptr, regs->gpr[reg]);
21017ce452fSJason Wessel 
211dfc3095cSChristophe Leroy #ifdef CONFIG_PPC_85xx
21217ce452fSJason Wessel #ifdef CONFIG_SPE
21317ce452fSJason Wessel 	for (reg = 0; reg < 32; reg++)
21417ce452fSJason Wessel 		PACK64(ptr, p->thread.evr[reg]);
21517ce452fSJason Wessel #else
21617ce452fSJason Wessel 	ptr += 32;
21717ce452fSJason Wessel #endif
21817ce452fSJason Wessel #else
21917ce452fSJason Wessel 	/* fp registers not used by kernel, leave zero */
22017ce452fSJason Wessel 	ptr += 32 * 8 / sizeof(long);
22117ce452fSJason Wessel #endif
22217ce452fSJason Wessel 
22317ce452fSJason Wessel 	PACK64(ptr, regs->nip);
22417ce452fSJason Wessel 	PACK64(ptr, regs->msr);
22517ce452fSJason Wessel 	PACK32(ptr, regs->ccr);
22617ce452fSJason Wessel 	PACK64(ptr, regs->link);
22717ce452fSJason Wessel 	PACK64(ptr, regs->ctr);
22817ce452fSJason Wessel 	PACK32(ptr, regs->xer);
22917ce452fSJason Wessel 
23017ce452fSJason Wessel 	BUG_ON((unsigned long)ptr >
23117ce452fSJason Wessel 	       (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
23217ce452fSJason Wessel }
23317ce452fSJason Wessel 
234ff10b88bSDongdong Deng #define GDB_SIZEOF_REG sizeof(unsigned long)
235ff10b88bSDongdong Deng #define GDB_SIZEOF_REG_U32 sizeof(u32)
23617ce452fSJason Wessel 
237dfc3095cSChristophe Leroy #ifdef CONFIG_PPC_85xx
238ff10b88bSDongdong Deng #define GDB_SIZEOF_FLOAT_REG sizeof(unsigned long)
23917ce452fSJason Wessel #else
240ff10b88bSDongdong Deng #define GDB_SIZEOF_FLOAT_REG sizeof(u64)
24117ce452fSJason Wessel #endif
242ff10b88bSDongdong Deng 
243ff10b88bSDongdong Deng struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
244ff10b88bSDongdong Deng {
245ff10b88bSDongdong Deng 	{ "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[0]) },
246ff10b88bSDongdong Deng 	{ "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[1]) },
247ff10b88bSDongdong Deng 	{ "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[2]) },
248ff10b88bSDongdong Deng 	{ "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[3]) },
249ff10b88bSDongdong Deng 	{ "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[4]) },
250ff10b88bSDongdong Deng 	{ "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[5]) },
251ff10b88bSDongdong Deng 	{ "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[6]) },
252ff10b88bSDongdong Deng 	{ "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[7]) },
253ff10b88bSDongdong Deng 	{ "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[8]) },
254ff10b88bSDongdong Deng 	{ "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[9]) },
255ff10b88bSDongdong Deng 	{ "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[10]) },
256ff10b88bSDongdong Deng 	{ "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[11]) },
257ff10b88bSDongdong Deng 	{ "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[12]) },
258ff10b88bSDongdong Deng 	{ "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[13]) },
259ff10b88bSDongdong Deng 	{ "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[14]) },
260ff10b88bSDongdong Deng 	{ "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[15]) },
261ff10b88bSDongdong Deng 	{ "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[16]) },
262ff10b88bSDongdong Deng 	{ "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[17]) },
263ff10b88bSDongdong Deng 	{ "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[18]) },
264ff10b88bSDongdong Deng 	{ "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[19]) },
265ff10b88bSDongdong Deng 	{ "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[20]) },
266ff10b88bSDongdong Deng 	{ "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[21]) },
267ff10b88bSDongdong Deng 	{ "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[22]) },
268ff10b88bSDongdong Deng 	{ "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[23]) },
269ff10b88bSDongdong Deng 	{ "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[24]) },
270ff10b88bSDongdong Deng 	{ "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[25]) },
271ff10b88bSDongdong Deng 	{ "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[26]) },
272ff10b88bSDongdong Deng 	{ "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[27]) },
273ff10b88bSDongdong Deng 	{ "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[28]) },
274ff10b88bSDongdong Deng 	{ "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[29]) },
275ff10b88bSDongdong Deng 	{ "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[30]) },
276ff10b88bSDongdong Deng 	{ "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[31]) },
277ff10b88bSDongdong Deng 
278ff10b88bSDongdong Deng 	{ "f0", GDB_SIZEOF_FLOAT_REG, 0 },
279ff10b88bSDongdong Deng 	{ "f1", GDB_SIZEOF_FLOAT_REG, 1 },
280ff10b88bSDongdong Deng 	{ "f2", GDB_SIZEOF_FLOAT_REG, 2 },
281ff10b88bSDongdong Deng 	{ "f3", GDB_SIZEOF_FLOAT_REG, 3 },
282ff10b88bSDongdong Deng 	{ "f4", GDB_SIZEOF_FLOAT_REG, 4 },
283ff10b88bSDongdong Deng 	{ "f5", GDB_SIZEOF_FLOAT_REG, 5 },
284ff10b88bSDongdong Deng 	{ "f6", GDB_SIZEOF_FLOAT_REG, 6 },
285ff10b88bSDongdong Deng 	{ "f7", GDB_SIZEOF_FLOAT_REG, 7 },
286ff10b88bSDongdong Deng 	{ "f8", GDB_SIZEOF_FLOAT_REG, 8 },
287ff10b88bSDongdong Deng 	{ "f9", GDB_SIZEOF_FLOAT_REG, 9 },
288ff10b88bSDongdong Deng 	{ "f10", GDB_SIZEOF_FLOAT_REG, 10 },
289ff10b88bSDongdong Deng 	{ "f11", GDB_SIZEOF_FLOAT_REG, 11 },
290ff10b88bSDongdong Deng 	{ "f12", GDB_SIZEOF_FLOAT_REG, 12 },
291ff10b88bSDongdong Deng 	{ "f13", GDB_SIZEOF_FLOAT_REG, 13 },
292ff10b88bSDongdong Deng 	{ "f14", GDB_SIZEOF_FLOAT_REG, 14 },
293ff10b88bSDongdong Deng 	{ "f15", GDB_SIZEOF_FLOAT_REG, 15 },
294ff10b88bSDongdong Deng 	{ "f16", GDB_SIZEOF_FLOAT_REG, 16 },
295ff10b88bSDongdong Deng 	{ "f17", GDB_SIZEOF_FLOAT_REG, 17 },
296ff10b88bSDongdong Deng 	{ "f18", GDB_SIZEOF_FLOAT_REG, 18 },
297ff10b88bSDongdong Deng 	{ "f19", GDB_SIZEOF_FLOAT_REG, 19 },
298ff10b88bSDongdong Deng 	{ "f20", GDB_SIZEOF_FLOAT_REG, 20 },
299ff10b88bSDongdong Deng 	{ "f21", GDB_SIZEOF_FLOAT_REG, 21 },
300ff10b88bSDongdong Deng 	{ "f22", GDB_SIZEOF_FLOAT_REG, 22 },
301ff10b88bSDongdong Deng 	{ "f23", GDB_SIZEOF_FLOAT_REG, 23 },
302ff10b88bSDongdong Deng 	{ "f24", GDB_SIZEOF_FLOAT_REG, 24 },
303ff10b88bSDongdong Deng 	{ "f25", GDB_SIZEOF_FLOAT_REG, 25 },
304ff10b88bSDongdong Deng 	{ "f26", GDB_SIZEOF_FLOAT_REG, 26 },
305ff10b88bSDongdong Deng 	{ "f27", GDB_SIZEOF_FLOAT_REG, 27 },
306ff10b88bSDongdong Deng 	{ "f28", GDB_SIZEOF_FLOAT_REG, 28 },
307ff10b88bSDongdong Deng 	{ "f29", GDB_SIZEOF_FLOAT_REG, 29 },
308ff10b88bSDongdong Deng 	{ "f30", GDB_SIZEOF_FLOAT_REG, 30 },
309ff10b88bSDongdong Deng 	{ "f31", GDB_SIZEOF_FLOAT_REG, 31 },
310ff10b88bSDongdong Deng 
311ff10b88bSDongdong Deng 	{ "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, nip) },
312ff10b88bSDongdong Deng 	{ "msr", GDB_SIZEOF_REG, offsetof(struct pt_regs, msr) },
313ff10b88bSDongdong Deng 	{ "cr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ccr) },
314ff10b88bSDongdong Deng 	{ "lr", GDB_SIZEOF_REG, offsetof(struct pt_regs, link) },
315ff10b88bSDongdong Deng 	{ "ctr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ctr) },
316ff10b88bSDongdong Deng 	{ "xer", GDB_SIZEOF_REG, offsetof(struct pt_regs, xer) },
317ff10b88bSDongdong Deng };
318ff10b88bSDongdong Deng 
dbg_get_reg(int regno,void * mem,struct pt_regs * regs)319ff10b88bSDongdong Deng char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
320ff10b88bSDongdong Deng {
321ff10b88bSDongdong Deng 	if (regno >= DBG_MAX_REG_NUM || regno < 0)
322ff10b88bSDongdong Deng 		return NULL;
323ff10b88bSDongdong Deng 
324ff10b88bSDongdong Deng 	if (regno < 32 || regno >= 64)
325ff10b88bSDongdong Deng 		/* First 0 -> 31 gpr registers*/
326ff10b88bSDongdong Deng 		/* pc, msr, ls... registers 64 -> 69 */
327ff10b88bSDongdong Deng 		memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
328ff10b88bSDongdong Deng 				dbg_reg_def[regno].size);
329ff10b88bSDongdong Deng 
330ff10b88bSDongdong Deng 	if (regno >= 32 && regno < 64) {
331ff10b88bSDongdong Deng 		/* FP registers 32 -> 63 */
332dfc3095cSChristophe Leroy #if defined(CONFIG_PPC_85xx) && defined(CONFIG_SPE)
333ff10b88bSDongdong Deng 		if (current)
334e3839ed8SDongdong Deng 			memcpy(mem, &current->thread.evr[regno-32],
335ff10b88bSDongdong Deng 					dbg_reg_def[regno].size);
33617ce452fSJason Wessel #else
33717ce452fSJason Wessel 		/* fp registers not used by kernel, leave zero */
338ff10b88bSDongdong Deng 		memset(mem, 0, dbg_reg_def[regno].size);
33917ce452fSJason Wessel #endif
340ff10b88bSDongdong Deng 	}
34117ce452fSJason Wessel 
342ff10b88bSDongdong Deng 	return dbg_reg_def[regno].name;
343ff10b88bSDongdong Deng }
34417ce452fSJason Wessel 
dbg_set_reg(int regno,void * mem,struct pt_regs * regs)345ff10b88bSDongdong Deng int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
346ff10b88bSDongdong Deng {
347ff10b88bSDongdong Deng 	if (regno >= DBG_MAX_REG_NUM || regno < 0)
348ff10b88bSDongdong Deng 		return -EINVAL;
349ff10b88bSDongdong Deng 
350ff10b88bSDongdong Deng 	if (regno < 32 || regno >= 64)
351ff10b88bSDongdong Deng 		/* First 0 -> 31 gpr registers*/
352ff10b88bSDongdong Deng 		/* pc, msr, ls... registers 64 -> 69 */
353ff10b88bSDongdong Deng 		memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
354ff10b88bSDongdong Deng 				dbg_reg_def[regno].size);
355ff10b88bSDongdong Deng 
356ff10b88bSDongdong Deng 	if (regno >= 32 && regno < 64) {
357ff10b88bSDongdong Deng 		/* FP registers 32 -> 63 */
358dfc3095cSChristophe Leroy #if defined(CONFIG_PPC_85xx) && defined(CONFIG_SPE)
359e3839ed8SDongdong Deng 		memcpy(&current->thread.evr[regno-32], mem,
360ff10b88bSDongdong Deng 				dbg_reg_def[regno].size);
361ff10b88bSDongdong Deng #else
362ff10b88bSDongdong Deng 		/* fp registers not used by kernel, leave zero */
363ff10b88bSDongdong Deng 		return 0;
364ff10b88bSDongdong Deng #endif
365ff10b88bSDongdong Deng 	}
366ff10b88bSDongdong Deng 
367ff10b88bSDongdong Deng 	return 0;
36817ce452fSJason Wessel }
36917ce452fSJason Wessel 
kgdb_arch_set_pc(struct pt_regs * regs,unsigned long pc)370dcc78711SJason Wessel void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
371dcc78711SJason Wessel {
37259dc5bfcSNicholas Piggin 	regs_set_return_ip(regs, pc);
373dcc78711SJason Wessel }
374dcc78711SJason Wessel 
37517ce452fSJason Wessel /*
37689f7d292SBhaskar Chowdhury  * This function does PowerPC specific processing for interfacing to gdb.
37717ce452fSJason Wessel  */
kgdb_arch_handle_exception(int vector,int signo,int err_code,char * remcom_in_buffer,char * remcom_out_buffer,struct pt_regs * linux_regs)37817ce452fSJason Wessel int kgdb_arch_handle_exception(int vector, int signo, int err_code,
37917ce452fSJason Wessel 			       char *remcom_in_buffer, char *remcom_out_buffer,
38017ce452fSJason Wessel 			       struct pt_regs *linux_regs)
38117ce452fSJason Wessel {
38217ce452fSJason Wessel 	char *ptr = &remcom_in_buffer[1];
38317ce452fSJason Wessel 	unsigned long addr;
38417ce452fSJason Wessel 
38517ce452fSJason Wessel 	switch (remcom_in_buffer[0]) {
38617ce452fSJason Wessel 		/*
38717ce452fSJason Wessel 		 * sAA..AA   Step one instruction from AA..AA
38817ce452fSJason Wessel 		 * This will return an error to gdb ..
38917ce452fSJason Wessel 		 */
39017ce452fSJason Wessel 	case 's':
39117ce452fSJason Wessel 	case 'c':
39217ce452fSJason Wessel 		/* handle the optional parameter */
39317ce452fSJason Wessel 		if (kgdb_hex2long(&ptr, &addr))
39459dc5bfcSNicholas Piggin 			regs_set_return_ip(linux_regs, addr);
39517ce452fSJason Wessel 
39617ce452fSJason Wessel 		atomic_set(&kgdb_cpu_doing_single_step, -1);
39717ce452fSJason Wessel 		/* set the trace bit if we're stepping */
39817ce452fSJason Wessel 		if (remcom_in_buffer[0] == 's') {
399172ae2e7SDave Kleikamp #ifdef CONFIG_PPC_ADV_DEBUG_REGS
40017ce452fSJason Wessel 			mtspr(SPRN_DBCR0,
40117ce452fSJason Wessel 			      mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
40259dc5bfcSNicholas Piggin 			regs_set_return_msr(linux_regs, linux_regs->msr | MSR_DE);
40317ce452fSJason Wessel #else
40459dc5bfcSNicholas Piggin 			regs_set_return_msr(linux_regs, linux_regs->msr | MSR_SE);
40517ce452fSJason Wessel #endif
40617ce452fSJason Wessel 			atomic_set(&kgdb_cpu_doing_single_step,
40717ce452fSJason Wessel 				   raw_smp_processor_id());
40817ce452fSJason Wessel 		}
40917ce452fSJason Wessel 		return 0;
41017ce452fSJason Wessel 	}
41117ce452fSJason Wessel 
41217ce452fSJason Wessel 	return -1;
41317ce452fSJason Wessel }
41417ce452fSJason Wessel 
kgdb_arch_set_breakpoint(struct kgdb_bkpt * bpt)415fb978ca2SChristophe Leroy int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
416fb978ca2SChristophe Leroy {
41769d4d6e5SChristophe Leroy 	u32 instr, *addr = (u32 *)bpt->bpt_addr;
418fb978ca2SChristophe Leroy 	int err;
419fb978ca2SChristophe Leroy 
42069d4d6e5SChristophe Leroy 	err = get_kernel_nofault(instr, addr);
421fb978ca2SChristophe Leroy 	if (err)
422fb978ca2SChristophe Leroy 		return err;
423fb978ca2SChristophe Leroy 
42475346251SJordan Niethe 	err = patch_instruction(addr, ppc_inst(BREAK_INSTR));
425fb978ca2SChristophe Leroy 	if (err)
426fb978ca2SChristophe Leroy 		return -EFAULT;
427fb978ca2SChristophe Leroy 
42869d4d6e5SChristophe Leroy 	*(u32 *)bpt->saved_instr = instr;
429fb978ca2SChristophe Leroy 
430fb978ca2SChristophe Leroy 	return 0;
431fb978ca2SChristophe Leroy }
432fb978ca2SChristophe Leroy 
kgdb_arch_remove_breakpoint(struct kgdb_bkpt * bpt)433fb978ca2SChristophe Leroy int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
434fb978ca2SChristophe Leroy {
435fb978ca2SChristophe Leroy 	int err;
436fb978ca2SChristophe Leroy 	unsigned int instr = *(unsigned int *)bpt->saved_instr;
43769d4d6e5SChristophe Leroy 	u32 *addr = (u32 *)bpt->bpt_addr;
438fb978ca2SChristophe Leroy 
43975346251SJordan Niethe 	err = patch_instruction(addr, ppc_inst(instr));
440fb978ca2SChristophe Leroy 	if (err)
441fb978ca2SChristophe Leroy 		return -EFAULT;
442fb978ca2SChristophe Leroy 
443fb978ca2SChristophe Leroy 	return 0;
444fb978ca2SChristophe Leroy }
445fb978ca2SChristophe Leroy 
44617ce452fSJason Wessel /*
44717ce452fSJason Wessel  * Global data
44817ce452fSJason Wessel  */
449cc028297SChristophe Leroy const struct kgdb_arch arch_kgdb_ops;
45017ce452fSJason Wessel 
kgdb_not_implemented(struct pt_regs * regs)45117ce452fSJason Wessel static int kgdb_not_implemented(struct pt_regs *regs)
45217ce452fSJason Wessel {
45317ce452fSJason Wessel 	return 0;
45417ce452fSJason Wessel }
45517ce452fSJason Wessel 
45617ce452fSJason Wessel static void *old__debugger_ipi;
45717ce452fSJason Wessel static void *old__debugger;
45817ce452fSJason Wessel static void *old__debugger_bpt;
45917ce452fSJason Wessel static void *old__debugger_sstep;
46017ce452fSJason Wessel static void *old__debugger_iabr_match;
4619422de3eSMichael Neuling static void *old__debugger_break_match;
46217ce452fSJason Wessel static void *old__debugger_fault_handler;
46317ce452fSJason Wessel 
kgdb_arch_init(void)46417ce452fSJason Wessel int kgdb_arch_init(void)
46517ce452fSJason Wessel {
46617ce452fSJason Wessel 	old__debugger_ipi = __debugger_ipi;
46717ce452fSJason Wessel 	old__debugger = __debugger;
46817ce452fSJason Wessel 	old__debugger_bpt = __debugger_bpt;
46917ce452fSJason Wessel 	old__debugger_sstep = __debugger_sstep;
47017ce452fSJason Wessel 	old__debugger_iabr_match = __debugger_iabr_match;
4719422de3eSMichael Neuling 	old__debugger_break_match = __debugger_break_match;
47217ce452fSJason Wessel 	old__debugger_fault_handler = __debugger_fault_handler;
47317ce452fSJason Wessel 
4743cd99ac3SDouglas Anderson 	__debugger_ipi = kgdb_debugger_ipi;
47517ce452fSJason Wessel 	__debugger = kgdb_debugger;
47617ce452fSJason Wessel 	__debugger_bpt = kgdb_handle_breakpoint;
47717ce452fSJason Wessel 	__debugger_sstep = kgdb_singlestep;
47817ce452fSJason Wessel 	__debugger_iabr_match = kgdb_iabr_match;
4799422de3eSMichael Neuling 	__debugger_break_match = kgdb_break_match;
48017ce452fSJason Wessel 	__debugger_fault_handler = kgdb_not_implemented;
48117ce452fSJason Wessel 
48217ce452fSJason Wessel 	return 0;
48317ce452fSJason Wessel }
48417ce452fSJason Wessel 
kgdb_arch_exit(void)48517ce452fSJason Wessel void kgdb_arch_exit(void)
48617ce452fSJason Wessel {
48717ce452fSJason Wessel 	__debugger_ipi = old__debugger_ipi;
48817ce452fSJason Wessel 	__debugger = old__debugger;
48917ce452fSJason Wessel 	__debugger_bpt = old__debugger_bpt;
49017ce452fSJason Wessel 	__debugger_sstep = old__debugger_sstep;
49117ce452fSJason Wessel 	__debugger_iabr_match = old__debugger_iabr_match;
492fa592464SMichael Neuling 	__debugger_break_match = old__debugger_break_match;
49317ce452fSJason Wessel 	__debugger_fault_handler = old__debugger_fault_handler;
49417ce452fSJason Wessel }
495