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, ¤t->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(¤t->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