--- /dev/null
+/*
+ * PowerPC backend to the KGDB stub.
+ *
+ * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu)
+ * Copyright (C) 2003 Timesys Corporation.
+ * Copyright (C) 2004-2006 MontaVista Software, Inc.
+ * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com)
+ * PPC32 support restored by Vitaly Wool <vwool@ru.mvista.com> and
+ * Sergei Shtylyov <sshtylyov@ru.mvista.com>
+ * Copyright (C) 2007-2008 Wind River Systems, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program as licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/kgdb.h>
+#include <linux/smp.h>
+#include <linux/signal.h>
+#include <linux/ptrace.h>
+#include <asm/current.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+
+/*
+ * This table contains the mapping between PowerPC hardware trap types, and
+ * signals, which are primarily what GDB understands.  GDB and the kernel
+ * don't always agree on values, so we use constants taken from gdb-6.2.
+ */
+static struct hard_trap_info
+{
+       unsigned int tt;                /* Trap type code for powerpc */
+       unsigned char signo;            /* Signal that we map this trap into */
+} hard_trap_info[] = {
+       { 0x0100, 0x02 /* SIGINT */  },         /* system reset */
+       { 0x0200, 0x0b /* SIGSEGV */ },         /* machine check */
+       { 0x0300, 0x0b /* SIGSEGV */ },         /* data access */
+       { 0x0400, 0x0b /* SIGSEGV */ },         /* instruction access */
+       { 0x0500, 0x02 /* SIGINT */  },         /* external interrupt */
+       { 0x0600, 0x0a /* SIGBUS */  },         /* alignment */
+       { 0x0700, 0x05 /* SIGTRAP */ },         /* program check */
+       { 0x0800, 0x08 /* SIGFPE */  },         /* fp unavailable */
+       { 0x0900, 0x0e /* SIGALRM */ },         /* decrementer */
+       { 0x0c00, 0x14 /* SIGCHLD */ },         /* system call */
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+       { 0x2002, 0x05 /* SIGTRAP */ },         /* debug */
+#if defined(CONFIG_FSL_BOOKE)
+       { 0x2010, 0x08 /* SIGFPE */  },         /* spe unavailable */
+       { 0x2020, 0x08 /* SIGFPE */  },         /* spe unavailable */
+       { 0x2030, 0x08 /* SIGFPE */  },         /* spe fp data */
+       { 0x2040, 0x08 /* SIGFPE */  },         /* spe fp data */
+       { 0x2050, 0x08 /* SIGFPE */  },         /* spe fp round */
+       { 0x2060, 0x0e /* SIGILL */  },         /* performace monitor */
+       { 0x2900, 0x08 /* SIGFPE */  },         /* apu unavailable */
+       { 0x3100, 0x0e /* SIGALRM */ },         /* fixed interval timer */
+       { 0x3200, 0x02 /* SIGINT */  },         /* watchdog */
+#else /* ! CONFIG_FSL_BOOKE */
+       { 0x1000, 0x0e /* SIGALRM */ },         /* prog interval timer */
+       { 0x1010, 0x0e /* SIGALRM */ },         /* fixed interval timer */
+       { 0x1020, 0x02 /* SIGINT */  },         /* watchdog */
+       { 0x2010, 0x08 /* SIGFPE */  },         /* fp unavailable */
+       { 0x2020, 0x08 /* SIGFPE */  },         /* ap unavailable */
+#endif
+#else /* ! (defined(CONFIG_40x) || defined(CONFIG_BOOKE)) */
+       { 0x0d00, 0x05 /* SIGTRAP */ },         /* single-step */
+#if defined(CONFIG_8xx)
+       { 0x1000, 0x04 /* SIGILL */  },         /* software emulation */
+#else /* ! CONFIG_8xx */
+       { 0x0f00, 0x04 /* SIGILL */  },         /* performance monitor */
+       { 0x0f20, 0x08 /* SIGFPE */  },         /* altivec unavailable */
+       { 0x1300, 0x05 /* SIGTRAP */ },         /* instruction address break */
+#if defined(CONFIG_PPC64)
+       { 0x1200, 0x05 /* SIGILL */  },         /* system error */
+       { 0x1500, 0x04 /* SIGILL */  },         /* soft patch */
+       { 0x1600, 0x04 /* SIGILL */  },         /* maintenance */
+       { 0x1700, 0x08 /* SIGFPE */  },         /* altivec assist */
+       { 0x1800, 0x04 /* SIGILL */  },         /* thermal */
+#else /* ! CONFIG_PPC64 */
+       { 0x1400, 0x02 /* SIGINT */  },         /* SMI */
+       { 0x1600, 0x08 /* SIGFPE */  },         /* altivec assist */
+       { 0x1700, 0x04 /* SIGILL */  },         /* TAU */
+       { 0x2000, 0x05 /* SIGTRAP */ },         /* run mode */
+#endif
+#endif
+#endif
+       { 0x0000, 0x00 }                        /* Must be last */
+};
+
+static int computeSignal(unsigned int tt)
+{
+       struct hard_trap_info *ht;
+
+       for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+               if (ht->tt == tt)
+                       return ht->signo;
+
+       return SIGHUP;          /* default for things we don't know about */
+}
+
+static int kgdb_call_nmi_hook(struct pt_regs *regs)
+{
+       kgdb_nmicallback(raw_smp_processor_id(), regs);
+       return 0;
+}
+
+#ifdef CONFIG_SMP
+void kgdb_roundup_cpus(unsigned long flags)
+{
+       smp_send_debugger_break(MSG_ALL_BUT_SELF);
+}
+#endif
+
+/* KGDB functions to use existing PowerPC64 hooks. */
+static int kgdb_debugger(struct pt_regs *regs)
+{
+       return kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs);
+}
+
+static int kgdb_handle_breakpoint(struct pt_regs *regs)
+{
+       if (user_mode(regs))
+               return 0;
+
+       if (kgdb_handle_exception(0, SIGTRAP, 0, regs) != 0)
+               return 0;
+
+       if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr))
+               regs->nip += 4;
+
+       return 1;
+}
+
+static int kgdb_singlestep(struct pt_regs *regs)
+{
+       struct thread_info *thread_info, *exception_thread_info;
+
+       if (user_mode(regs))
+               return 0;
+
+       /*
+        * On Book E and perhaps other processsors, singlestep is handled on
+        * the critical exception stack.  This causes current_thread_info()
+        * to fail, since it it locates the thread_info by masking off
+        * the low bits of the current stack pointer.  We work around
+        * this issue by copying the thread_info from the kernel stack
+        * before calling kgdb_handle_exception, and copying it back
+        * afterwards.  On most processors the copy is avoided since
+        * exception_thread_info == thread_info.
+        */
+       thread_info = (struct thread_info *)(regs->gpr[1] & ~(THREAD_SIZE-1));
+       exception_thread_info = current_thread_info();
+
+       if (thread_info != exception_thread_info)
+               memcpy(exception_thread_info, thread_info, sizeof *thread_info);
+
+       kgdb_handle_exception(0, SIGTRAP, 0, regs);
+
+       if (thread_info != exception_thread_info)
+               memcpy(thread_info, exception_thread_info, sizeof *thread_info);
+
+       return 1;
+}
+
+static int kgdb_iabr_match(struct pt_regs *regs)
+{
+       if (user_mode(regs))
+               return 0;
+
+       if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0)
+               return 0;
+       return 1;
+}
+
+static int kgdb_dabr_match(struct pt_regs *regs)
+{
+       if (user_mode(regs))
+               return 0;
+
+       if (kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs) != 0)
+               return 0;
+       return 1;
+}
+
+#define PACK64(ptr, src) do { *(ptr++) = (src); } while (0)
+
+#define PACK32(ptr, src) do {          \
+       u32 *ptr32;                   \
+       ptr32 = (u32 *)ptr;           \
+       *(ptr32++) = (src);           \
+       ptr = (unsigned long *)ptr32; \
+       } while (0)
+
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+       unsigned long *ptr = gdb_regs;
+       int reg;
+
+       memset(gdb_regs, 0, NUMREGBYTES);
+
+       for (reg = 0; reg < 32; reg++)
+               PACK64(ptr, regs->gpr[reg]);
+
+#ifdef CONFIG_FSL_BOOKE
+#ifdef CONFIG_SPE
+       for (reg = 0; reg < 32; reg++)
+               PACK64(ptr, current->thread.evr[reg]);
+#else
+       ptr += 32;
+#endif
+#else
+       /* fp registers not used by kernel, leave zero */
+       ptr += 32 * 8 / sizeof(long);
+#endif
+
+       PACK64(ptr, regs->nip);
+       PACK64(ptr, regs->msr);
+       PACK32(ptr, regs->ccr);
+       PACK64(ptr, regs->link);
+       PACK64(ptr, regs->ctr);
+       PACK32(ptr, regs->xer);
+
+       BUG_ON((unsigned long)ptr >
+              (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+       struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp +
+                                                 STACK_FRAME_OVERHEAD);
+       unsigned long *ptr = gdb_regs;
+       int reg;
+
+       memset(gdb_regs, 0, NUMREGBYTES);
+
+       /* Regs GPR0-2 */
+       for (reg = 0; reg < 3; reg++)
+               PACK64(ptr, regs->gpr[reg]);
+
+       /* Regs GPR3-13 are caller saved, not in regs->gpr[] */
+       ptr += 11;
+
+       /* Regs GPR14-31 */
+       for (reg = 14; reg < 32; reg++)
+               PACK64(ptr, regs->gpr[reg]);
+
+#ifdef CONFIG_FSL_BOOKE
+#ifdef CONFIG_SPE
+       for (reg = 0; reg < 32; reg++)
+               PACK64(ptr, p->thread.evr[reg]);
+#else
+       ptr += 32;
+#endif
+#else
+       /* fp registers not used by kernel, leave zero */
+       ptr += 32 * 8 / sizeof(long);
+#endif
+
+       PACK64(ptr, regs->nip);
+       PACK64(ptr, regs->msr);
+       PACK32(ptr, regs->ccr);
+       PACK64(ptr, regs->link);
+       PACK64(ptr, regs->ctr);
+       PACK32(ptr, regs->xer);
+
+       BUG_ON((unsigned long)ptr >
+              (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
+}
+
+#define UNPACK64(dest, ptr) do { dest = *(ptr++); } while (0)
+
+#define UNPACK32(dest, ptr) do {       \
+       u32 *ptr32;                   \
+       ptr32 = (u32 *)ptr;           \
+       dest = *(ptr32++);            \
+       ptr = (unsigned long *)ptr32; \
+       } while (0)
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+       unsigned long *ptr = gdb_regs;
+       int reg;
+#ifdef CONFIG_SPE
+       union {
+               u32 v32[2];
+               u64 v64;
+       } acc;
+#endif
+
+       for (reg = 0; reg < 32; reg++)
+               UNPACK64(regs->gpr[reg], ptr);
+
+#ifdef CONFIG_FSL_BOOKE
+#ifdef CONFIG_SPE
+       for (reg = 0; reg < 32; reg++)
+               UNPACK64(current->thread.evr[reg], ptr);
+#else
+       ptr += 32;
+#endif
+#else
+       /* fp registers not used by kernel, leave zero */
+       ptr += 32 * 8 / sizeof(int);
+#endif
+
+       UNPACK64(regs->nip, ptr);
+       UNPACK64(regs->msr, ptr);
+       UNPACK32(regs->ccr, ptr);
+       UNPACK64(regs->link, ptr);
+       UNPACK64(regs->ctr, ptr);
+       UNPACK32(regs->xer, ptr);
+
+       BUG_ON((unsigned long)ptr >
+              (unsigned long)(((void *)gdb_regs) + NUMREGBYTES));
+}
+
+/*
+ * This function does PowerPC specific procesing for interfacing to gdb.
+ */
+int kgdb_arch_handle_exception(int vector, int signo, int err_code,
+                              char *remcom_in_buffer, char *remcom_out_buffer,
+                              struct pt_regs *linux_regs)
+{
+       char *ptr = &remcom_in_buffer[1];
+       unsigned long addr;
+
+       switch (remcom_in_buffer[0]) {
+               /*
+                * sAA..AA   Step one instruction from AA..AA
+                * This will return an error to gdb ..
+                */
+       case 's':
+       case 'c':
+               /* handle the optional parameter */
+               if (kgdb_hex2long(&ptr, &addr))
+                       linux_regs->nip = addr;
+
+               atomic_set(&kgdb_cpu_doing_single_step, -1);
+               /* set the trace bit if we're stepping */
+               if (remcom_in_buffer[0] == 's') {
+#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
+                       mtspr(SPRN_DBCR0,
+                             mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
+                       linux_regs->msr |= MSR_DE;
+#else
+                       linux_regs->msr |= MSR_SE;
+#endif
+                       kgdb_single_step = 1;
+                       if (kgdb_contthread)
+                               atomic_set(&kgdb_cpu_doing_single_step,
+                                          raw_smp_processor_id());
+               }
+               return 0;
+       }
+
+       return -1;
+}
+
+/*
+ * Global data
+ */
+struct kgdb_arch arch_kgdb_ops = {
+       .gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08},
+};
+
+static int kgdb_not_implemented(struct pt_regs *regs)
+{
+       return 0;
+}
+
+static void *old__debugger_ipi;
+static void *old__debugger;
+static void *old__debugger_bpt;
+static void *old__debugger_sstep;
+static void *old__debugger_iabr_match;
+static void *old__debugger_dabr_match;
+static void *old__debugger_fault_handler;
+
+int kgdb_arch_init(void)
+{
+       old__debugger_ipi = __debugger_ipi;
+       old__debugger = __debugger;
+       old__debugger_bpt = __debugger_bpt;
+       old__debugger_sstep = __debugger_sstep;
+       old__debugger_iabr_match = __debugger_iabr_match;
+       old__debugger_dabr_match = __debugger_dabr_match;
+       old__debugger_fault_handler = __debugger_fault_handler;
+
+       __debugger_ipi = kgdb_call_nmi_hook;
+       __debugger = kgdb_debugger;
+       __debugger_bpt = kgdb_handle_breakpoint;
+       __debugger_sstep = kgdb_singlestep;
+       __debugger_iabr_match = kgdb_iabr_match;
+       __debugger_dabr_match = kgdb_dabr_match;
+       __debugger_fault_handler = kgdb_not_implemented;
+
+       return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+       __debugger_ipi = old__debugger_ipi;
+       __debugger = old__debugger;
+       __debugger_bpt = old__debugger_bpt;
+       __debugger_sstep = old__debugger_sstep;
+       __debugger_iabr_match = old__debugger_iabr_match;
+       __debugger_dabr_match = old__debugger_dabr_match;
+       __debugger_fault_handler = old__debugger_fault_handler;
+}
 
 /*
- * kgdb.h: Defines and declarations for serial line source level
- *         remote debugging of the Linux kernel using gdb.
+ * include/asm-powerpc/kgdb.h
  *
+ * The PowerPC (32/64) specific defines / externs for KGDB.  Based on
+ * the previous 32bit and 64bit specific files, which had the following
+ * copyrights:
+ *
+ * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com)
+ * PPC Mods (C) 2004 Tom Rini (trini@mvista.com)
+ * PPC Mods (C) 2003 John Whitney (john.whitney@timesys.com)
  * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu)
  *
+ *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Author: Tom Rini <trini@kernel.crashing.org>
+ *
+ * 2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
  */
 #ifdef __KERNEL__
-#ifndef _PPC_KGDB_H
-#define _PPC_KGDB_H
+#ifndef __POWERPC_KGDB_H__
+#define __POWERPC_KGDB_H__
 
 #ifndef __ASSEMBLY__
 
-/* Things specific to the gen550 backend. */
-struct uart_port;
-
-extern void gen550_progress(char *, unsigned short);
-extern void gen550_kgdb_map_scc(void);
-extern void gen550_init(int, struct uart_port *);
-
-/* Things specific to the pmac backend. */
-extern void zs_kgdb_hook(int tty_num);
-
-/* To init the kgdb engine. (called by serial hook)*/
-extern void set_debug_traps(void);
-
-/* To enter the debugger explicitly. */
-extern void breakpoint(void);
-
-/* For taking exceptions
- * these are defined in traps.c
- */
-extern int (*debugger)(struct pt_regs *regs);
-extern int (*debugger_bpt)(struct pt_regs *regs);
-extern int (*debugger_sstep)(struct pt_regs *regs);
-extern int (*debugger_iabr_match)(struct pt_regs *regs);
-extern int (*debugger_dabr_match)(struct pt_regs *regs);
-extern void (*debugger_fault_handler)(struct pt_regs *regs);
-
-/* What we bring to the party */
-int kgdb_bpt(struct pt_regs *regs);
-int kgdb_sstep(struct pt_regs *regs);
-void kgdb(struct pt_regs *regs);
-int kgdb_iabr_match(struct pt_regs *regs);
-int kgdb_dabr_match(struct pt_regs *regs);
+#define BREAK_INSTR_SIZE       4
+#define BUFMAX                 ((NUMREGBYTES * 2) + 512)
+#define OUTBUFMAX              ((NUMREGBYTES * 2) + 512)
+static inline void arch_kgdb_breakpoint(void)
+{
+       asm(".long 0x7d821008"); /* twge r2, r2 */
+}
+#define CACHE_FLUSH_IS_SAFE    1
 
+/* The number bytes of registers we have to save depends on a few
+ * things.  For 64bit we default to not including vector registers and
+ * vector state registers. */
+#ifdef CONFIG_PPC64
 /*
- * external low-level support routines (ie macserial.c)
+ * 64 bit (8 byte) registers:
+ *   32 gpr, 32 fpr, nip, msr, link, ctr
+ * 32 bit (4 byte) registers:
+ *   ccr, xer, fpscr
  */
-extern void kgdb_interruptible(int); /* control interrupts from serial */
-extern void putDebugChar(char);   /* write a single character      */
-extern char getDebugChar(void);   /* read and return a single char */
-
+#define NUMREGBYTES            ((68 * 8) + (3 * 4))
+#define NUMCRITREGBYTES                184
+#else /* CONFIG_PPC32 */
+/* On non-E500 family PPC32 we determine the size by picking the last
+ * register we need, but on E500 we skip sections so we list what we
+ * need to store, and add it up. */
+#ifndef CONFIG_E500
+#define MAXREG                 (PT_FPSCR+1)
+#else
+/* 32 GPRs (8 bytes), nip, msr, ccr, link, ctr, xer, acc (8 bytes), spefscr*/
+#define MAXREG                 ((32*2)+6+2+1)
+#endif
+#define NUMREGBYTES            (MAXREG * sizeof(int))
+/* CR/LR, R1, R2, R13-R31 inclusive. */
+#define NUMCRITREGBYTES                (23 * sizeof(int))
+#endif /* 32/64 */
 #endif /* !(__ASSEMBLY__) */
-#endif /* !(_PPC_KGDB_H) */
+#endif /* !__POWERPC_KGDB_H__ */
 #endif /* __KERNEL__ */