Hi Jason:

I'm sending a new ia64-lite.patch which has been litely tested on SMP
ia64 machine. I haven't tested ia64.patch features but applied it when
testing ia64-lite.patch. I'm assuming your plan for the upstream push
doesn't contain the core patches.

I'll attempt to find time later this week to test the features in ia64.patch.

The only significant change in ia64-lite.patch is acquisition of the
pt_regs information while in an irq.

thanks,

bob

This is support of the IA64 arch for KGDB, and is primarily the work of
Bob Picco.

Signed-off-by: Milind Dumbare <[EMAIL PROTECTED]>
Signed-off-by: Bob Picco <[EMAIL PROTECTED]>

 arch/ia64/kernel/Makefile   |    1 
 arch/ia64/kernel/kgdb-jmp.S |  238 +++++++++
 arch/ia64/kernel/kgdb.c     | 1134 ++++++++++++++++++++++++++++++++++++++++++++
 arch/ia64/kernel/smp.c      |   17 
 arch/ia64/kernel/traps.c    |    6 
 arch/ia64/mm/extable.c      |    6 
 arch/ia64/mm/fault.c        |    4 
 include/asm-ia64/kdebug.h   |    1 
 include/asm-ia64/kgdb.h     |   36 +
 lib/Kconfig.debug           |    2 
 10 files changed, 1443 insertions(+), 2 deletions(-)

Index: linux-2.6.21-rc3-kgdb/arch/ia64/mm/extable.c
===================================================================
--- linux-2.6.21-rc3-kgdb.orig/arch/ia64/mm/extable.c   2007-03-16 
14:36:48.000000000 -0500
+++ linux-2.6.21-rc3-kgdb/arch/ia64/mm/extable.c        2007-03-16 
14:40:29.000000000 -0500
@@ -6,6 +6,7 @@
  */
 
 #include <linux/sort.h>
+#include <linux/kgdb.h>
 
 #include <asm/uaccess.h>
 #include <asm/module.h>
@@ -73,6 +74,11 @@ search_extable (const struct exception_t
                 else
                         last = mid - 1;
         }
+#ifdef CONFIG_KGDB
+       if (atomic_read(&debugger_active) && kgdb_may_fault)
+               kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+               /* Not reached. */
+#endif
         return NULL;
 }
 
Index: linux-2.6.21-rc3-kgdb/arch/ia64/mm/fault.c
===================================================================
--- linux-2.6.21-rc3-kgdb.orig/arch/ia64/mm/fault.c     2007-03-16 
14:37:02.000000000 -0500
+++ linux-2.6.21-rc3-kgdb/arch/ia64/mm/fault.c  2007-03-16 14:40:29.000000000 
-0500
@@ -268,6 +268,10 @@ ia64_do_page_fault (unsigned long addres
         */
        bust_spinlocks(1);
 
+       if (notify_die(DIE_PAGE_FAULT_NO_CONTEXT, "no context", regs,
+                       isr, 14, SIGSEGV) == NOTIFY_STOP)
+               return;
+
        if (address < PAGE_SIZE)
                printk(KERN_ALERT "Unable to handle kernel NULL pointer 
dereference (address %016lx)\n", address);
        else
Index: linux-2.6.21-rc3-kgdb/arch/ia64/kernel/kgdb-jmp.S
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.21-rc3-kgdb/arch/ia64/kernel/kgdb-jmp.S   2007-03-16 
14:40:29.000000000 -0500
@@ -0,0 +1,238 @@
+/* setjmp() and longjmp() assembler support for kdb on ia64.
+
+   This code was copied from glibc CVS as of 2001-06-27 and modified where
+   necessary to fit the kernel.
+   Keith Owens <[EMAIL PROTECTED]> 2001-06-27
+ */
+
+/* Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+   Contributed by David Mosberger-Tang <[EMAIL PROTECTED]>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If
+   not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <asm/asmmacro.h>
+GLOBAL_ENTRY(kgdb_fault_setjmp)
+       .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
+       alloc loc1=ar.pfs,2,2,2,0
+       mov r16=ar.unat
+       ;;
+       mov r17=ar.fpsr
+       mov r2=in0
+       add r3=8,in0
+       ;;
+.mem.offset 0,0;
+       st8.spill.nta [r2]=sp,16        // r12 (sp)
+.mem.offset 8,0;
+       st8.spill.nta [r3]=gp,16        // r1 (gp)
+       ;;
+       st8.nta [r2]=r16,16             // save caller's unat
+       st8.nta [r3]=r17,16             // save fpsr
+       add r8=0xa0,in0
+       ;;
+.mem.offset 160,0;
+       st8.spill.nta [r2]=r4,16        // r4
+.mem.offset 168,0;
+       st8.spill.nta [r3]=r5,16        // r5
+       add r9=0xb0,in0
+       ;;
+       stf.spill.nta [r8]=f2,32
+       stf.spill.nta [r9]=f3,32
+       mov loc0=rp
+       .body
+       ;;
+       stf.spill.nta [r8]=f4,32
+       stf.spill.nta [r9]=f5,32
+       mov r17=b1
+       ;;
+       stf.spill.nta [r8]=f16,32
+       stf.spill.nta [r9]=f17,32
+       mov r18=b2
+       ;;
+       stf.spill.nta [r8]=f18,32
+       stf.spill.nta [r9]=f19,32
+       mov r19=b3
+       ;;
+       stf.spill.nta [r8]=f20,32
+       stf.spill.nta [r9]=f21,32
+       mov r20=b4
+       ;;
+       stf.spill.nta [r8]=f22,32
+       stf.spill.nta [r9]=f23,32
+       mov r21=b5
+       ;;
+       stf.spill.nta [r8]=f24,32
+       stf.spill.nta [r9]=f25,32
+       mov r22=ar.lc
+       ;;
+       stf.spill.nta [r8]=f26,32
+       stf.spill.nta [r9]=f27,32
+       mov r24=pr
+       ;;
+       stf.spill.nta [r8]=f28,32
+       stf.spill.nta [r9]=f29,32
+       ;;
+       stf.spill.nta [r8]=f30
+       stf.spill.nta [r9]=f31
+
+.mem.offset 0,0;
+       st8.spill.nta [r2]=r6,16        // r6
+.mem.offset 8,0;
+       st8.spill.nta [r3]=r7,16        // r7
+       ;;
+       mov r23=ar.bsp
+       mov r25=ar.unat
+       st8.nta [r2]=loc0,16            // b0
+       st8.nta [r3]=r17,16             // b1
+       ;;
+       st8.nta [r2]=r18,16             // b2
+       st8.nta [r3]=r19,16             // b3
+       ;;
+       st8.nta [r2]=r20,16             // b4
+       st8.nta [r3]=r21,16             // b5
+       ;;
+       st8.nta [r2]=loc1,16            // ar.pfs
+       st8.nta [r3]=r22,16             // ar.lc
+       ;;
+       st8.nta [r2]=r24,16             // pr
+       st8.nta [r3]=r23,16             // ar.bsp
+       ;;
+       st8.nta [r2]=r25                // ar.unat
+       st8.nta [r3]=in0                // &__jmp_buf
+       mov r8=0
+       mov rp=loc0
+       mov ar.pfs=loc1
+       br.ret.sptk.few rp
+END(kdba_setjmp)
+#define        pPos    p6      /* is rotate count positive? */
+#define        pNeg    p7      /* is rotate count negative? */
+GLOBAL_ENTRY(kgdb_fault_longjmp)
+       alloc r8=ar.pfs,2,1,0,0
+       mov r27=ar.rsc
+       add r2=0x98,in0         // r2 <- &jmpbuf.orig_jmp_buf_addr
+       ;;
+       ld8 r8=[r2],-16         // r8 <- orig_jmp_buf_addr
+       mov r10=ar.bsp
+       and r11=~0x3,r27        // clear ar.rsc.mode
+       ;;
+       flushrs                 // flush dirty regs to backing store (must be 
first in insn grp)
+       ld8 r23=[r2],8          // r23 <- jmpbuf.ar_bsp
+       sub r8=r8,in0           // r8 <- &orig_jmpbuf - &jmpbuf
+       ;;
+       ld8 r25=[r2]            // r25 <- jmpbuf.ar_unat
+       extr.u r8=r8,3,6        // r8 <- (&orig_jmpbuf - &jmpbuf)/8 & 0x3f
+       ;;
+       cmp.lt pNeg,pPos=r8,r0
+       mov r2=in0
+       ;;
+(pPos) mov r16=r8
+(pNeg) add r16=64,r8
+(pPos) sub r17=64,r8
+(pNeg) sub r17=r0,r8
+       ;;
+       mov ar.rsc=r11          // put RSE in enforced lazy mode
+       shr.u r8=r25,r16
+       add r3=8,in0            // r3 <- &jmpbuf.r1
+       shl r9=r25,r17
+       ;;
+       or r25=r8,r9
+       ;;
+       mov r26=ar.rnat
+       mov ar.unat=r25         // setup ar.unat (NaT bits for r1, r4-r7, and 
r12)
+       ;;
+       ld8.fill.nta sp=[r2],16 // r12 (sp)
+       ld8.fill.nta gp=[r3],16         // r1 (gp)
+       dep r11=-1,r23,3,6      // r11 <- ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+       ;;
+       ld8.nta r16=[r2],16             // caller's unat
+       ld8.nta r17=[r3],16             // fpsr
+       ;;
+       ld8.fill.nta r4=[r2],16 // r4
+       ld8.fill.nta r5=[r3],16         // r5 (gp)
+       cmp.geu p8,p0=r10,r11   // p8 <- (ar.bsp >= jmpbuf.ar_bsp)
+       ;;
+       ld8.fill.nta r6=[r2],16 // r6
+       ld8.fill.nta r7=[r3],16         // r7
+       ;;
+       mov ar.unat=r16                 // restore caller's unat
+       mov ar.fpsr=r17                 // restore fpsr
+       ;;
+       ld8.nta r16=[r2],16             // b0
+       ld8.nta r17=[r3],16             // b1
+       ;;
+(p8)   ld8 r26=[r11]           // r26 <- *ia64_rse_rnat_addr(jmpbuf.ar_bsp)
+       mov ar.bspstore=r23     // restore ar.bspstore
+       ;;
+       ld8.nta r18=[r2],16             // b2
+       ld8.nta r19=[r3],16             // b3
+       ;;
+       ld8.nta r20=[r2],16             // b4
+       ld8.nta r21=[r3],16             // b5
+       ;;
+       ld8.nta r11=[r2],16             // ar.pfs
+       ld8.nta r22=[r3],56             // ar.lc
+       ;;
+       ld8.nta r24=[r2],32             // pr
+       mov b0=r16
+       ;;
+       ldf.fill.nta f2=[r2],32
+       ldf.fill.nta f3=[r3],32
+       mov b1=r17
+       ;;
+       ldf.fill.nta f4=[r2],32
+       ldf.fill.nta f5=[r3],32
+       mov b2=r18
+       ;;
+       ldf.fill.nta f16=[r2],32
+       ldf.fill.nta f17=[r3],32
+       mov b3=r19
+       ;;
+       ldf.fill.nta f18=[r2],32
+       ldf.fill.nta f19=[r3],32
+       mov b4=r20
+       ;;
+       ldf.fill.nta f20=[r2],32
+       ldf.fill.nta f21=[r3],32
+       mov b5=r21
+       ;;
+       ldf.fill.nta f22=[r2],32
+       ldf.fill.nta f23=[r3],32
+       mov ar.lc=r22
+       ;;
+       ldf.fill.nta f24=[r2],32
+       ldf.fill.nta f25=[r3],32
+       cmp.eq p8,p9=0,in1
+       ;;
+       ldf.fill.nta f26=[r2],32
+       ldf.fill.nta f27=[r3],32
+       mov ar.pfs=r11
+       ;;
+       ldf.fill.nta f28=[r2],32
+       ldf.fill.nta f29=[r3],32
+       ;;
+       ldf.fill.nta f30=[r2]
+       ldf.fill.nta f31=[r3]
+(p8)   mov r8=1
+
+       mov ar.rnat=r26         // restore ar.rnat
+       ;;
+       mov ar.rsc=r27          // restore ar.rsc
+(p9)   mov r8=in1
+
+       invala                  // virt. -> phys. regnum mapping may change
+       mov pr=r24,-1
+       br.ret.sptk.few rp
+END(kgdb_fault_longjmp)
Index: linux-2.6.21-rc3-kgdb/arch/ia64/kernel/kgdb.c
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.21-rc3-kgdb/arch/ia64/kernel/kgdb.c       2007-03-18 
11:18:39.000000000 -0500
@@ -0,0 +1,1134 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+/*
+ * Copyright (C) 2000-2001 VERITAS Software Corporation.
+ * (c) Copyright 2005 Hewlett-Packard Development Company, L.P.
+ *     Bob Picco <[EMAIL PROTECTED]>
+ */
+/*
+ *  Contributor:     Lake Stevens Instrument Division$
+ *  Written by:      Glenn Engel $
+ *  Updated by:             Amit Kale<[EMAIL PROTECTED]>
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <[EMAIL 
PROTECTED]>
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>                /* for linux pt_regs struct */
+#include <asm/unwind.h>
+#include <asm/rse.h>
+#include <linux/kgdb.h>
+#include <linux/init.h>
+#include <asm/cacheflush.h>
+#include <asm/kdebug.h>
+
+#define NUM_REGS 590
+#define REGISTER_BYTES (NUM_REGS*8+128*8)
+#define REGISTER_BYTE(N) (((N) * 8)                                    \
+       + ((N) <= IA64_FR0_REGNUM ?                                     \
+       0 : 8 * (((N) > IA64_FR127_REGNUM) ? 128 : (N) - IA64_FR0_REGNUM)))
+#define REGISTER_SIZE(N)                                               \
+       (((N) >= IA64_FR0_REGNUM && (N) <= IA64_FR127_REGNUM) ? 16 : 8)
+#define IA64_GR0_REGNUM         0
+#define IA64_FR0_REGNUM         128
+#define IA64_FR127_REGNUM       (IA64_FR0_REGNUM+127)
+#define IA64_PR0_REGNUM         256
+#define IA64_BR0_REGNUM         320
+#define IA64_VFP_REGNUM         328
+#define IA64_PR_REGNUM          330
+#define IA64_IP_REGNUM          331
+#define IA64_PSR_REGNUM         332
+#define IA64_CFM_REGNUM         333
+#define IA64_AR0_REGNUM         334
+#define IA64_NAT0_REGNUM        462
+#define IA64_NAT31_REGNUM       (IA64_NAT0_REGNUM+31)
+#define IA64_NAT32_REGNUM       (IA64_NAT0_REGNUM+32)
+#define IA64_RSC_REGNUM                (IA64_AR0_REGNUM+16)
+#define IA64_BSP_REGNUM                (IA64_AR0_REGNUM+17)
+#define IA64_BSPSTORE_REGNUM   (IA64_AR0_REGNUM+18)
+#define IA64_RNAT_REGNUM       (IA64_AR0_REGNUM+19)
+#define IA64_FCR_REGNUM                (IA64_AR0_REGNUM+21)
+#define IA64_EFLAG_REGNUM      (IA64_AR0_REGNUM+24)
+#define IA64_CSD_REGNUM                (IA64_AR0_REGNUM+25)
+#define IA64_SSD_REGNUM                (IA64_AR0_REGNUM+26)
+#define IA64_CFLG_REGNUM       (IA64_AR0_REGNUM+27)
+#define IA64_FSR_REGNUM                (IA64_AR0_REGNUM+28)
+#define IA64_FIR_REGNUM                (IA64_AR0_REGNUM+29)
+#define IA64_FDR_REGNUM                (IA64_AR0_REGNUM+30)
+#define IA64_CCV_REGNUM                (IA64_AR0_REGNUM+32)
+#define IA64_UNAT_REGNUM       (IA64_AR0_REGNUM+36)
+#define IA64_FPSR_REGNUM       (IA64_AR0_REGNUM+40)
+#define IA64_ITC_REGNUM                (IA64_AR0_REGNUM+44)
+#define IA64_PFS_REGNUM                (IA64_AR0_REGNUM+64)
+#define IA64_LC_REGNUM         (IA64_AR0_REGNUM+65)
+#define IA64_EC_REGNUM         (IA64_AR0_REGNUM+66)
+
+#define        REGISTER_INDEX(N)       (REGISTER_BYTE(N) / sizeof (unsigned 
long))
+#define BREAK_INSTR_ALIGN      (~0xfULL)
+
+#define        ptoff(V)        ((unsigned int) &((struct pt_regs *)0x0)->V)
+struct reg_to_ptreg_index {
+       unsigned int reg;
+       unsigned int ptregoff;
+};
+
+static struct reg_to_ptreg_index gr_reg_to_ptreg_index[] = {
+       {IA64_GR0_REGNUM + 1, ptoff(r1)},
+       {IA64_GR0_REGNUM + 2, ptoff(r2)},
+       {IA64_GR0_REGNUM + 3, ptoff(r3)},
+       {IA64_GR0_REGNUM + 8, ptoff(r8)},
+       {IA64_GR0_REGNUM + 9, ptoff(r9)},
+       {IA64_GR0_REGNUM + 10, ptoff(r10)},
+       {IA64_GR0_REGNUM + 11, ptoff(r11)},
+       {IA64_GR0_REGNUM + 12, ptoff(r12)},
+       {IA64_GR0_REGNUM + 13, ptoff(r13)},
+       {IA64_GR0_REGNUM + 14, ptoff(r14)},
+       {IA64_GR0_REGNUM + 15, ptoff(r15)},
+       {IA64_GR0_REGNUM + 16, ptoff(r16)},
+       {IA64_GR0_REGNUM + 17, ptoff(r17)},
+       {IA64_GR0_REGNUM + 18, ptoff(r18)},
+       {IA64_GR0_REGNUM + 19, ptoff(r19)},
+       {IA64_GR0_REGNUM + 20, ptoff(r20)},
+       {IA64_GR0_REGNUM + 21, ptoff(r21)},
+       {IA64_GR0_REGNUM + 22, ptoff(r22)},
+       {IA64_GR0_REGNUM + 23, ptoff(r23)},
+       {IA64_GR0_REGNUM + 24, ptoff(r24)},
+       {IA64_GR0_REGNUM + 25, ptoff(r25)},
+       {IA64_GR0_REGNUM + 26, ptoff(r26)},
+       {IA64_GR0_REGNUM + 27, ptoff(r27)},
+       {IA64_GR0_REGNUM + 28, ptoff(r28)},
+       {IA64_GR0_REGNUM + 29, ptoff(r29)},
+       {IA64_GR0_REGNUM + 30, ptoff(r30)},
+       {IA64_GR0_REGNUM + 31, ptoff(r31)},
+};
+
+static struct reg_to_ptreg_index br_reg_to_ptreg_index[] = {
+       {IA64_BR0_REGNUM, ptoff(b0)},
+       {IA64_BR0_REGNUM + 6, ptoff(b6)},
+       {IA64_BR0_REGNUM + 7, ptoff(b7)},
+};
+
+static struct reg_to_ptreg_index ar_reg_to_ptreg_index[] = {
+       {IA64_PFS_REGNUM, ptoff(ar_pfs)},
+       {IA64_UNAT_REGNUM, ptoff(ar_unat)},
+       {IA64_RNAT_REGNUM, ptoff(ar_rnat)},
+       {IA64_BSPSTORE_REGNUM, ptoff(ar_bspstore)},
+       {IA64_RSC_REGNUM, ptoff(ar_rsc)},
+       {IA64_CSD_REGNUM, ptoff(ar_csd)},
+       {IA64_SSD_REGNUM, ptoff(ar_ssd)},
+       {IA64_FPSR_REGNUM, ptoff(ar_fpsr)},
+       {IA64_CCV_REGNUM, ptoff(ar_ccv)},
+};
+
+extern atomic_t cpu_doing_single_step;
+
+static int kgdb_gr_reg(int regnum, struct unw_frame_info *info,
+       unsigned long *reg, int rw)
+{
+       char nat;
+
+       if ((regnum >= IA64_GR0_REGNUM && regnum <= (IA64_GR0_REGNUM + 1)) ||
+               (regnum >= (IA64_GR0_REGNUM + 4) &&
+               regnum <= (IA64_GR0_REGNUM + 7)))
+               return !unw_access_gr(info, regnum - IA64_GR0_REGNUM,
+               reg, &nat, rw);
+       else
+               return 0;
+}
+static int kgdb_gr_ptreg(int regnum, struct pt_regs * ptregs,
+       struct unw_frame_info *info, unsigned long *reg, int rw)
+{
+       int i, result = 1;
+       char nat;
+
+       if (!((regnum >= (IA64_GR0_REGNUM + 2) &&
+               regnum <= (IA64_GR0_REGNUM + 3)) ||
+               (regnum >= (IA64_GR0_REGNUM + 8) &&
+               regnum <= (IA64_GR0_REGNUM + 15)) ||
+               (regnum >= (IA64_GR0_REGNUM + 16) &&
+               regnum <= (IA64_GR0_REGNUM + 31))))
+               return 0;
+       else if (rw && ptregs) {
+               for (i = 0; i < ARRAY_SIZE(gr_reg_to_ptreg_index); i++)
+                       if (gr_reg_to_ptreg_index[i].reg == regnum) {
+                               *((unsigned long *)(((void *)ptregs) +
+                               gr_reg_to_ptreg_index[i].ptregoff)) = *reg;
+                               break;
+                       }
+       } else if (!rw && ptregs) {
+               for (i = 0; i < ARRAY_SIZE(gr_reg_to_ptreg_index); i++)
+                       if (gr_reg_to_ptreg_index[i].reg == regnum) {
+                               *reg = *((unsigned long *)
+                               (((void *)ptregs) +
+                                gr_reg_to_ptreg_index[i].ptregoff));
+                               break;
+                       }
+       } else
+               result = !unw_access_gr(info, regnum - IA64_GR0_REGNUM,
+                                       reg, &nat, rw);
+       return result;
+}
+
+static int kgdb_br_reg(int regnum, struct pt_regs * ptregs,
+       struct unw_frame_info *info, unsigned long *reg, int rw)
+{
+       int i, result = 1;
+
+       if (!(regnum >= IA64_BR0_REGNUM && regnum <= (IA64_BR0_REGNUM + 7)))
+               return 0;
+
+       switch (regnum) {
+       case IA64_BR0_REGNUM:
+       case IA64_BR0_REGNUM + 6:
+       case IA64_BR0_REGNUM + 7:
+               if (rw) {
+                       for (i = 0; i < ARRAY_SIZE(br_reg_to_ptreg_index); i++)
+                               if (br_reg_to_ptreg_index[i].reg == regnum) {
+                                       *((unsigned long *)
+                                       (((void *)ptregs) +
+                                       br_reg_to_ptreg_index[i].ptregoff)) =
+                                       *reg;
+                                       break;
+                               }
+               } else
+                       for (i = 0; i < ARRAY_SIZE(br_reg_to_ptreg_index); i++)
+                               if (br_reg_to_ptreg_index[i].reg == regnum) {
+                                               *reg = *((unsigned long *)
+                                               (((void *)ptregs) +
+                                               br_reg_to_ptreg_index[i].
+                                               ptregoff));
+                                               break;
+                               }
+               break;
+       case IA64_BR0_REGNUM + 1:
+       case IA64_BR0_REGNUM + 2:
+       case IA64_BR0_REGNUM + 3:
+       case IA64_BR0_REGNUM + 4:
+       case IA64_BR0_REGNUM + 5:
+               result = !unw_access_br(info, regnum - IA64_BR0_REGNUM,
+                               reg, rw);
+               break;
+       }
+
+       return result;
+}
+
+static int kgdb_fr_reg(int regnum, char *inbuffer, struct pt_regs * ptregs,
+       struct unw_frame_info *info, unsigned long *reg,
+       struct ia64_fpreg *freg, int rw)
+{
+       int result = 1;
+
+       if (!(regnum >= IA64_FR0_REGNUM && regnum <= (IA64_FR0_REGNUM + 127)))
+               return 0;
+
+       switch (regnum) {
+       case IA64_FR0_REGNUM + 6:
+       case IA64_FR0_REGNUM + 7:
+       case IA64_FR0_REGNUM + 8:
+       case IA64_FR0_REGNUM + 9:
+       case IA64_FR0_REGNUM + 10:
+       case IA64_FR0_REGNUM + 11:
+       case IA64_FR0_REGNUM + 12:
+               if (rw) {
+                       char *ptr = inbuffer;
+
+                       freg->u.bits[0] = *reg;
+                       kgdb_hex2long(&ptr, &freg->u.bits[1]);
+                       *(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM + 6))) =
+                               *freg;
+                       break;
+               } else if (!ptregs)
+                       result = !unw_access_fr(info, regnum - IA64_FR0_REGNUM,
+                               freg, rw);
+               else
+                       *freg =
+                       *(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM + 6)));
+               break;
+       default:
+               if (!rw)
+                       result = !unw_access_fr(info, regnum - IA64_FR0_REGNUM,
+                               freg, rw);
+               else
+                       result = 0;
+               break;
+       }
+
+       return result;
+}
+
+static int kgdb_ar_reg(int regnum, struct pt_regs * ptregs,
+       struct unw_frame_info *info, unsigned long *reg, int rw)
+{
+       int result = 0, i;
+
+       if (!(regnum >= IA64_AR0_REGNUM && regnum <= IA64_EC_REGNUM))
+               return 0;
+
+       if (rw && ptregs) {
+               for (i = 0; i < ARRAY_SIZE(ar_reg_to_ptreg_index); i++)
+                       if (ar_reg_to_ptreg_index[i].reg == regnum) {
+                               *((unsigned long *) (((void *)ptregs) +
+                               ar_reg_to_ptreg_index[i].ptregoff)) =
+                                       *reg;
+                               result = 1;
+                               break;
+                       }
+       } else if (ptregs) {
+               for (i = 0; i < ARRAY_SIZE(ar_reg_to_ptreg_index); i++)
+                       if (ar_reg_to_ptreg_index[i].reg == regnum) {
+                               *reg = *((unsigned long *) (((void *)ptregs) +
+                                       ar_reg_to_ptreg_index[i].ptregoff));
+                                       result = 1;
+                               break;
+                       }
+       }
+
+       if (result)
+               return result;
+
+       result = 1;
+
+       switch (regnum) {
+       case IA64_CSD_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_CSD, reg, rw);
+               break;
+       case IA64_SSD_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_SSD, reg, rw);
+               break;
+       case IA64_UNAT_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw);
+               break;
+               case IA64_RNAT_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw);
+               break;
+       case IA64_BSPSTORE_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw);
+               break;
+       case IA64_PFS_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_RNAT, reg, rw);
+               break;
+       case IA64_LC_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_LC, reg, rw);
+               break;
+       case IA64_EC_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_EC, reg, rw);
+               break;
+       case IA64_FPSR_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_FPSR, reg, rw);
+               break;
+       case IA64_RSC_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_RSC, reg, rw);
+               break;
+       case IA64_CCV_REGNUM:
+               result = !unw_access_ar(info, UNW_AR_CCV, reg, rw);
+               break;
+       default:
+               result = 0;
+       }
+
+       return result;
+}
+
+void kgdb_get_reg(char *outbuffer, int regnum, struct unw_frame_info *info,
+       struct pt_regs *ptregs)
+{
+       unsigned long reg, size = 0, *mem = &reg;
+       struct ia64_fpreg freg;
+
+       if (kgdb_gr_reg(regnum, info, &reg, 0) ||
+               kgdb_gr_ptreg(regnum, ptregs, info, &reg, 0) ||
+               kgdb_br_reg(regnum, ptregs, info, &reg, 0) ||
+               kgdb_ar_reg(regnum, ptregs, info, &reg, 0))
+                       size = sizeof(reg);
+       else if (kgdb_fr_reg(regnum, NULL, ptregs, info, &reg, &freg, 0)) {
+               size = sizeof(freg);
+               mem = (unsigned long *)&freg;
+       } else if (regnum == IA64_IP_REGNUM) {
+               if (!ptregs) {
+                       unw_get_ip(info, &reg);
+                       size = sizeof(reg);
+               } else {
+                       reg = ptregs->cr_iip;
+                       size = sizeof(reg);
+               }
+       } else if (regnum == IA64_CFM_REGNUM) {
+               if (!ptregs)
+                       unw_get_cfm(info, &reg);
+               else
+                       reg = ptregs->cr_ifs;
+               size = sizeof(reg);
+       } else if (regnum == IA64_PSR_REGNUM) {
+               if (!ptregs && kgdb_usethread)
+                       ptregs = (struct pt_regs *)
+                       ((unsigned long)kgdb_usethread +
+                       IA64_STK_OFFSET) - 1;
+               if (ptregs)
+                       reg = ptregs->cr_ipsr;
+               size = sizeof(reg);
+       } else if (regnum == IA64_PR_REGNUM) {
+               if (ptregs)
+                       reg = ptregs->pr;
+               else
+                       unw_access_pr(info, &reg, 0);
+               size = sizeof(reg);
+       } else if (regnum == IA64_BSP_REGNUM) {
+               unw_get_bsp(info, &reg);
+               size = sizeof(reg);
+       }
+
+       if (size) {
+               kgdb_mem2hex((char *) mem, outbuffer, size);
+               outbuffer[size*2] = 0;
+       }
+       else
+               strcpy(outbuffer, "E0");
+
+       return;
+}
+
+void kgdb_put_reg(char *inbuffer, char *outbuffer, int regnum,
+                 struct unw_frame_info *info, struct pt_regs *ptregs)
+{
+       unsigned long reg;
+       struct ia64_fpreg freg;
+       char *ptr = inbuffer;
+
+       kgdb_hex2long(&ptr, &reg);
+       strcpy(outbuffer, "OK");
+
+       if (kgdb_gr_reg(regnum, info, &reg, 1) ||
+               kgdb_gr_ptreg(regnum, ptregs, info, &reg, 1) ||
+               kgdb_br_reg(regnum, ptregs, info, &reg, 1) ||
+               kgdb_fr_reg(regnum, inbuffer, ptregs, info, &reg, &freg, 1) ||
+               kgdb_ar_reg(regnum, ptregs, info, &reg, 1)) ;
+       else if (regnum == IA64_IP_REGNUM)
+               ptregs->cr_iip = reg;
+       else if (regnum == IA64_CFM_REGNUM)
+               ptregs->cr_ifs = reg;
+       else if (regnum == IA64_PSR_REGNUM)
+               ptregs->cr_ipsr = reg;
+       else if (regnum == IA64_PR_REGNUM)
+               ptregs->pr = reg;
+       else
+               strcpy(outbuffer, "E01");
+       return;
+}
+
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct 
*p)
+{
+}
+
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+
+}
+
+#define        MAX_HW_BREAKPOINT       (20)
+long hw_break_total_dbr, hw_break_total_ibr;
+#define        HW_BREAKPOINT   (hw_break_total_dbr + hw_break_total_ibr)
+#define        WATCH_INSTRUCTION       0x0
+#define WATCH_WRITE            0x1
+#define        WATCH_READ              0x2
+#define        WATCH_ACCESS            0x3
+
+#define        HWCAP_DBR       ((1 << WATCH_WRITE) | (1 << WATCH_READ))
+#define        HWCAP_IBR       (1 << WATCH_INSTRUCTION)
+struct hw_breakpoint {
+       unsigned enabled;
+       unsigned long capable;
+       unsigned long type;
+       unsigned long mask;
+       unsigned long addr;
+} *breakinfo;
+
+static struct hw_breakpoint hwbreaks[MAX_HW_BREAKPOINT];
+
+enum instruction_type { A, I, M, F, B, L, X, u };
+
+static enum instruction_type bundle_encoding[32][3] = {
+       {M, I, I},              /* 00 */
+       {M, I, I},              /* 01 */
+       {M, I, I},              /* 02 */
+       {M, I, I},              /* 03 */
+       {M, L, X},              /* 04 */
+       {M, L, X},              /* 05 */
+       {u, u, u},              /* 06 */
+       {u, u, u},              /* 07 */
+       {M, M, I},              /* 08 */
+       {M, M, I},              /* 09 */
+       {M, M, I},              /* 0A */
+       {M, M, I},              /* 0B */
+       {M, F, I},              /* 0C */
+       {M, F, I},              /* 0D */
+       {M, M, F},              /* 0E */
+       {M, M, F},              /* 0F */
+       {M, I, B},              /* 10 */
+       {M, I, B},              /* 11 */
+       {M, B, B},              /* 12 */
+       {M, B, B},              /* 13 */
+       {u, u, u},              /* 14 */
+       {u, u, u},              /* 15 */
+       {B, B, B},              /* 16 */
+       {B, B, B},              /* 17 */
+       {M, M, B},              /* 18 */
+       {M, M, B},              /* 19 */
+       {u, u, u},              /* 1A */
+       {u, u, u},              /* 1B */
+       {M, F, B},              /* 1C */
+       {M, F, B},              /* 1D */
+       {u, u, u},              /* 1E */
+       {u, u, u},              /* 1F */
+};
+
+int kgdb_validate_break_address(unsigned long addr)
+{
+       int error;
+       char tmp_variable[BREAK_INSTR_SIZE];
+       error = kgdb_get_mem((char *)(addr & BREAK_INSTR_ALIGN), tmp_variable,
+               BREAK_INSTR_SIZE);
+       return error;
+}
+
+int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
+{
+       extern unsigned long _start[];
+       unsigned long slot = addr & BREAK_INSTR_ALIGN, bundle_addr;
+       unsigned long template;
+       struct bundle {
+               struct {
+                       unsigned long long template:5;
+                       unsigned long long slot0:41;
+                       unsigned long long slot1_p0:64 - 46;
+               } quad0;
+               struct {
+                       unsigned long long slot1_p1:41 - (64 - 46);
+                       unsigned long long slot2:41;
+               } quad1;
+       } bundle;
+       int ret;
+
+       bundle_addr = addr & ~0xFULL;
+
+       if (bundle_addr == (unsigned long)_start)
+               return 0;
+
+       ret = kgdb_get_mem((char *)bundle_addr, (char *)&bundle,
+                          BREAK_INSTR_SIZE);
+       if (ret < 0)
+               return ret;
+
+       if (slot > 2)
+               slot = 0;
+
+       memcpy(saved_instr, &bundle, BREAK_INSTR_SIZE);
+       template = bundle.quad0.template;
+
+       if (slot == 1 && bundle_encoding[template][1] == L)
+               slot = 2;
+
+       switch (slot) {
+       case 0:
+               bundle.quad0.slot0 = BREAKNUM;
+               break;
+       case 1:
+               bundle.quad0.slot1_p0 = BREAKNUM;
+               bundle.quad1.slot1_p1 = (BREAKNUM >> (64 - 46));
+               break;
+       case 2:
+               bundle.quad1.slot2 = BREAKNUM;
+               break;
+       }
+
+       return kgdb_set_mem((char *)bundle_addr, (char *)&bundle,
+                           BREAK_INSTR_SIZE);
+}
+
+int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
+{
+       extern unsigned long _start[];
+
+       addr = addr & BREAK_INSTR_ALIGN;
+       if (addr == (unsigned long)_start)
+               return 0;
+       return kgdb_set_mem((char *)addr, (char *)bundle, BREAK_INSTR_SIZE);
+}
+
+static int hw_breakpoint_init;
+
+void do_init_hw_break(void)
+{
+       s64 status;
+       int i;
+
+       hw_breakpoint_init = 1;
+
+#ifdef CONFIG_IA64_HP_SIM
+       hw_break_total_ibr = 8;
+       hw_break_total_dbr = 8;
+       status = 0;
+#else
+       status = ia64_pal_debug_info(&hw_break_total_ibr, &hw_break_total_dbr);
+#endif
+
+       if (status) {
+               printk(KERN_INFO "do_init_hw_break: pal call failed %d\n",
+                      (int)status);
+               return;
+       }
+
+       if (HW_BREAKPOINT > MAX_HW_BREAKPOINT) {
+               printk(KERN_INFO "do_init_hw_break: %d exceeds max %d\n",
+                      (int)HW_BREAKPOINT, (int)MAX_HW_BREAKPOINT);
+
+               while ((HW_BREAKPOINT > MAX_HW_BREAKPOINT)
+                      && hw_break_total_ibr != 1)
+                       hw_break_total_ibr--;
+               while (HW_BREAKPOINT > MAX_HW_BREAKPOINT)
+                       hw_break_total_dbr--;
+       }
+
+       breakinfo = hwbreaks;
+
+       memset(breakinfo, 0, HW_BREAKPOINT * sizeof(struct hw_breakpoint));
+
+       for (i = 0; i < hw_break_total_dbr; i++)
+               breakinfo[i].capable = HWCAP_DBR;
+
+       for (; i < HW_BREAKPOINT; i++)
+               breakinfo[i].capable = HWCAP_IBR;
+
+       return;
+}
+
+void kgdb_correct_hw_break(void)
+{
+       int breakno;
+
+       if (!breakinfo)
+               return;
+
+       for (breakno = 0; breakno < HW_BREAKPOINT; breakno++) {
+               if (breakinfo[breakno].enabled) {
+                       if (breakinfo[breakno].capable & HWCAP_IBR) {
+                               int ibreakno = breakno - hw_break_total_dbr;
+                               ia64_set_ibr(ibreakno << 1,
+                                            breakinfo[breakno].addr);
+                               ia64_set_ibr((ibreakno << 1) + 1,
+                                            (~breakinfo[breakno].mask &
+                                             ((1UL << 56UL) - 1)) |
+                                             (1UL << 56UL) | (1UL << 63UL));
+                       } else {
+                               ia64_set_dbr(breakno << 1,
+                                            breakinfo[breakno].addr);
+                               ia64_set_dbr((breakno << 1) + 1,
+                                            (~breakinfo[breakno].
+                                             mask & ((1UL << 56UL) - 1)) |
+                                            (1UL << 56UL) |
+                                            (breakinfo[breakno].type << 62UL));
+                       }
+               } else {
+                       if (breakinfo[breakno].capable & HWCAP_IBR)
+                               ia64_set_ibr(((breakno -
+                                              hw_break_total_dbr) << 1) + 1,
+                                            0);
+                       else
+                               ia64_set_dbr((breakno << 1) + 1, 0);
+               }
+       }
+
+       return;
+}
+
+int hardware_breakpoint(unsigned long addr, int length, int type, int action)
+{
+       int breakno, found, watch;
+       unsigned long mask;
+       extern unsigned long _start[];
+
+       if (!hw_breakpoint_init)
+               do_init_hw_break();
+
+       if (!breakinfo)
+               return 0;
+       else if (addr == (unsigned long)_start)
+               return 1;
+
+       if (type == WATCH_ACCESS)
+               mask = HWCAP_DBR;
+       else
+               mask = 1UL << type;
+
+       for (watch = 0, found = 0, breakno = 0; breakno < HW_BREAKPOINT;
+            breakno++) {
+               if (action) {
+                       if (breakinfo[breakno].enabled
+                           || !(breakinfo[breakno].capable & mask))
+                               continue;
+                       breakinfo[breakno].enabled = 1;
+                       breakinfo[breakno].type = type;
+                       breakinfo[breakno].mask = length - 1;
+                       breakinfo[breakno].addr = addr;
+                       watch = breakno;
+               } else if (breakinfo[breakno].enabled &&
+                          ((length < 0 && breakinfo[breakno].addr == addr) ||
+                           ((breakinfo[breakno].capable & mask) &&
+                            (breakinfo[breakno].mask == (length - 1)) &&
+                            (breakinfo[breakno].addr == addr)))) {
+                       breakinfo[breakno].enabled = 0;
+                       breakinfo[breakno].type = 0UL;
+               } else
+                       continue;
+               found++;
+               if (type != WATCH_ACCESS)
+                       break;
+               else if (found == 2)
+                       break;
+               else
+                       mask = HWCAP_IBR;
+       }
+
+       if (type == WATCH_ACCESS && found == 1) {
+               breakinfo[watch].enabled = 0;
+               found = 0;
+       }
+
+       mb();
+       return found;
+}
+
+int kgdb_arch_set_hw_breakpoint(unsigned long addr, int len,
+                               enum kgdb_bptype type)
+{
+       return hardware_breakpoint(addr, len, type - '1', 1);
+}
+
+int kgdb_arch_remove_hw_breakpoint(unsigned long addr, int len,
+                                  enum kgdb_bptype type)
+{
+       return hardware_breakpoint(addr, len, type - '1', 0);
+}
+
+int kgdb_remove_hw_break(unsigned long addr)
+{
+       return hardware_breakpoint(addr, 8, WATCH_INSTRUCTION, 0);
+
+}
+
+void kgdb_remove_all_hw_break(void)
+{
+       int i;
+
+       for (i = 0; i < HW_BREAKPOINT; i++)
+               memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint));
+}
+
+int kgdb_set_hw_break(unsigned long addr)
+{
+       return hardware_breakpoint(addr, 8, WATCH_INSTRUCTION, 1);
+}
+
+void kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+       unsigned long hw_breakpoint_status;
+
+       hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR);
+       if (hw_breakpoint_status & IA64_PSR_DB)
+               ia64_setreg(_IA64_REG_PSR_L,
+                           hw_breakpoint_status ^ IA64_PSR_DB);
+}
+
+volatile static struct smp_unw {
+       struct unw_frame_info *unw;
+       struct task_struct *task;
+} smp_unw[NR_CPUS];
+
+static int inline kgdb_get_blocked_state(struct task_struct *p,
+                                        struct unw_frame_info *unw)
+{
+       unsigned long ip;
+       int count = 0;
+
+       unw_init_from_blocked_task(unw, p);
+       ip = 0UL;
+       do {
+               if (unw_unwind(unw) < 0)
+                       return -1;
+               unw_get_ip(unw, &ip);
+               if (!in_sched_functions(ip))
+                       break;
+       } while (count++ < 16);
+
+       if (!ip)
+               return -1;
+       else
+               return 0;
+}
+
+static void inline kgdb_wait(struct pt_regs *regs)
+{
+       unsigned long hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR);
+
+       if (hw_breakpoint_status & IA64_PSR_DB)
+               ia64_setreg(_IA64_REG_PSR_L,
+                           hw_breakpoint_status ^ IA64_PSR_DB);
+       kgdb_nmihook(smp_processor_id(), regs);
+       if (hw_breakpoint_status & IA64_PSR_DB)
+               ia64_setreg(_IA64_REG_PSR_L, hw_breakpoint_status);
+
+       return;
+}
+
+static void inline normalize(struct unw_frame_info *running,
+                            struct pt_regs *regs)
+{
+       unsigned long sp;
+
+       do {
+               unw_get_sp(running, &sp);
+               if ((sp + 0x10) >= (unsigned long)regs)
+                       break;
+       } while (unw_unwind(running) >= 0);
+
+       return;
+}
+
+static void kgdb_init_running(struct unw_frame_info *unw, void *data)
+{
+       struct pt_regs *regs;
+
+       regs = data;
+       normalize(unw, regs);
+       smp_unw[smp_processor_id()].unw = unw;
+       kgdb_wait(regs);
+}
+
+#ifdef CONFIG_SMP
+void kgdb_wait_ipi(struct pt_regs *regs)
+{
+       struct unw_frame_info unw;
+
+       smp_unw[smp_processor_id()].task = current;
+
+       if (user_mode(regs)) {
+               smp_unw[smp_processor_id()].unw = (struct unw_frame_info *)1;
+               kgdb_wait(regs);
+       } else {
+               if (current->state == TASK_RUNNING)
+                       unw_init_running(kgdb_init_running, regs);
+               else {
+                       if (kgdb_get_blocked_state(current, &unw))
+                               smp_unw[smp_processor_id()].unw =
+                                   (struct unw_frame_info *)1;
+                       else
+                               smp_unw[smp_processor_id()].unw = &unw;
+                       kgdb_wait(regs);
+               }
+       }
+
+       smp_unw[smp_processor_id()].unw = NULL;
+       return;
+}
+#endif
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+       if (num_online_cpus() > 1)
+               smp_send_nmi_allbutself();
+}
+
+static volatile int kgdb_hwbreak_sstep[NR_CPUS];
+
+static int kgdb_notify(struct notifier_block *self, unsigned long cmd,
+       void *ptr)
+{
+       struct die_args *args = ptr;
+       struct pt_regs *regs = args->regs;
+       unsigned long err = args->err;
+
+       switch (cmd) {
+       default:
+               return NOTIFY_DONE;
+       case DIE_PAGE_FAULT_NO_CONTEXT:
+               if (atomic_read(&debugger_active) && kgdb_may_fault) {
+                       kgdb_fault_longjmp(kgdb_fault_jmp_regs);
+                       return NOTIFY_STOP;
+               }
+               break;
+       case DIE_BREAK:
+               if (user_mode(regs) || err == 0x80001)
+                       return NOTIFY_DONE;
+               break;
+       case DIE_FAULT:
+               if (user_mode(regs))
+                       return NOTIFY_DONE;
+               else if (err == 36 && kgdb_hwbreak_sstep[smp_processor_id()]) {
+                       kgdb_hwbreak_sstep[smp_processor_id()] = 0;
+                       regs->cr_ipsr &= ~IA64_PSR_SS;
+                       return NOTIFY_STOP;
+               }
+       case DIE_MCA_MONARCH_PROCESS:
+       case DIE_INIT_MONARCH_PROCESS:
+               break;
+       }
+
+       kgdb_handle_exception(args->trapnr, args->signr, args->err, regs);
+       return NOTIFY_STOP;
+}
+
+static struct notifier_block kgdb_notifier = {
+       .notifier_call = kgdb_notify,
+};
+
+int kgdb_arch_init(void)
+{
+       atomic_notifier_chain_register(&ia64die_chain, &kgdb_notifier);
+       return 0;
+}
+
+static void do_kgdb_handle_exception(struct unw_frame_info *, void *data);
+
+struct kgdb_state {
+       int e_vector;
+       int signo;
+       unsigned long err_code;
+       struct pt_regs *regs;
+       struct unw_frame_info *unw;
+       char *inbuf;
+       char *outbuf;
+       int unwind;
+       int ret;
+};
+
+static void inline kgdb_pc(struct pt_regs *regs, unsigned long pc)
+{
+       regs->cr_iip = pc & ~0xf;
+       ia64_psr(regs)->ri = pc & 0x3;
+       return;
+}
+
+int kgdb_arch_handle_exception(int e_vector, int signo,
+                              int err_code, char *remcom_in_buffer,
+                              char *remcom_out_buffer,
+                              struct pt_regs *linux_regs)
+{
+       struct kgdb_state info;
+
+       info.e_vector = e_vector;
+       info.signo = signo;
+       info.err_code = err_code;
+       info.unw = (void *)0;
+       info.inbuf = remcom_in_buffer;
+       info.outbuf = remcom_out_buffer;
+       info.unwind = 0;
+       info.ret = -1;
+
+       if (remcom_in_buffer[0] == 'c' || remcom_in_buffer[0] == 's') {
+               info.regs = linux_regs;
+               do_kgdb_handle_exception(NULL, &info);
+       } else if (kgdb_usethread == current) {
+               info.regs = linux_regs;
+               info.unwind = 1;
+               unw_init_running(do_kgdb_handle_exception, &info);
+       } else if (kgdb_usethread->state != TASK_RUNNING) {
+               struct unw_frame_info unw_info;
+
+               if (kgdb_get_blocked_state(kgdb_usethread, &unw_info)) {
+                       info.ret = 1;
+                       goto bad;
+               }
+               info.regs = NULL;
+               do_kgdb_handle_exception(&unw_info, &info);
+       } else {
+               int i;
+
+               for (i = 0; i < NR_CPUS; i++)
+                       if (smp_unw[i].task == kgdb_usethread && smp_unw[i].unw
+                           && smp_unw[i].unw != (struct unw_frame_info *)1) {
+                               info.regs = NULL;
+                               do_kgdb_handle_exception(smp_unw[i].unw, &info);
+                               break;
+                       } else {
+                               info.ret = 1;
+                               goto bad;
+                       }
+       }
+
+      bad:
+       if (info.ret != -1 && remcom_in_buffer[0] == 'p') {
+               unsigned long bad = 0xbad4badbadbadbadUL;
+
+               printk("kgdb_arch_handle_exception: p packet bad (%s)\n",
+                      remcom_in_buffer);
+               kgdb_mem2hex((char *)&bad, remcom_out_buffer, sizeof(bad));
+               remcom_out_buffer[sizeof(bad) * 2] = 0;
+               info.ret = -1;
+       }
+       return info.ret;
+}
+
+/*
+ * This is done because I evidently made an incorrect 'p' encoding
+ * when my patch for gdb was committed. It was later corrected. This
+ * check supports both my wrong encoding of the register number and
+ * the correct encoding. Eventually this should be eliminated and
+ * kgdb_hex2long should be demarshalling the regnum.
+ */
+static inline int check_packet(unsigned int regnum, char *packet)
+{
+       static int check_done, swap;
+       unsigned long reglong;
+
+       if (likely(check_done)) {
+               if (swap) {
+                       kgdb_hex2long(&packet, &reglong);
+                       regnum = (int) reglong;
+               }
+
+       } else {
+               if (regnum > NUM_REGS) {
+                       kgdb_hex2long(&packet, &reglong);
+                       regnum = (int) reglong;
+                       swap = 1;
+               }
+               check_done = 1;
+       }
+       return regnum;
+}
+
+static void do_kgdb_handle_exception(struct unw_frame_info *unw_info,
+       void *data)
+{
+       long addr;
+       char *ptr;
+       unsigned long newPC;
+       int e_vector, signo;
+       unsigned long err_code;
+       struct pt_regs *linux_regs;
+       struct kgdb_state *info;
+       char *remcom_in_buffer, *remcom_out_buffer;
+
+       info = data;
+       info->unw = unw_info;
+       e_vector = info->e_vector;
+       signo = info->signo;
+       err_code = info->err_code;
+       remcom_in_buffer = info->inbuf;
+       remcom_out_buffer = info->outbuf;
+       linux_regs = info->regs;
+
+       if (info->unwind)
+               normalize(unw_info, linux_regs);
+
+       switch (remcom_in_buffer[0]) {
+       case 'p':
+               {
+                       unsigned int regnum;
+
+                       kgdb_hex2mem(&remcom_in_buffer[1], (char *)&regnum,
+                                    sizeof(regnum));
+                       regnum = check_packet(regnum, &remcom_in_buffer[1]);
+                       if (regnum >= NUM_REGS) {
+                               remcom_out_buffer[0] = 'E';
+                               remcom_out_buffer[1] = 0;
+                       } else
+                               kgdb_get_reg(remcom_out_buffer, regnum,
+                                            unw_info, linux_regs);
+                       break;
+               }
+       case 'P':
+               {
+                       unsigned int regno;
+                       long v;
+                       char *ptr;
+
+                       ptr = &remcom_in_buffer[1];
+                       if ((!kgdb_usethread || kgdb_usethread == current) &&
+                           kgdb_hex2long(&ptr, &v) &&
+                           *ptr++ == '=' && (v >= 0)) {
+                               regno = (unsigned int)v;
+                               regno = (regno >= NUM_REGS ? 0 : regno);
+                               kgdb_put_reg(ptr, remcom_out_buffer, regno,
+                                            unw_info, linux_regs);
+                       } else
+                               strcpy(remcom_out_buffer, "E01");
+                       break;
+               }
+       case 'c':
+       case 's':
+               if (e_vector == TRAP_BRKPT && err_code == KGDBBREAKNUM) {
+                       if (ia64_psr(linux_regs)->ri < 2)
+                               kgdb_pc(linux_regs, linux_regs->cr_iip +
+                                       ia64_psr(linux_regs)->ri + 1);
+                       else
+                               kgdb_pc(linux_regs, linux_regs->cr_iip + 16);
+               }
+
+               /* try to read optional parameter, pc unchanged if no parm */
+               ptr = &remcom_in_buffer[1];
+               if (kgdb_hex2long(&ptr, &addr)) {
+                       linux_regs->cr_iip = addr;
+               }
+               newPC = linux_regs->cr_iip;
+
+               /* clear the trace bit */
+               linux_regs->cr_ipsr &= ~IA64_PSR_SS;
+
+               atomic_set(&cpu_doing_single_step, -1);
+
+               /* set the trace bit if we're stepping or took a hardware break 
*/
+               if (remcom_in_buffer[0] == 's' || e_vector == TRAP_HWBKPT) {
+                       linux_regs->cr_ipsr |= IA64_PSR_SS;
+                       debugger_step = 1;
+                       if (kgdb_contthread)
+                               atomic_set(&cpu_doing_single_step,
+                                          smp_processor_id());
+               }
+
+               kgdb_correct_hw_break();
+
+               /* if not hardware breakpoint, then reenable them */
+               if (e_vector != TRAP_HWBKPT)
+                       linux_regs->cr_ipsr |= IA64_PSR_DB;
+               else {
+                       kgdb_hwbreak_sstep[smp_processor_id()] = 1;
+                       linux_regs->cr_ipsr &= ~IA64_PSR_DB;
+               }
+
+               info->ret = 0;
+               break;
+       default:
+               break;
+       }
+
+       return;
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+       .set_hw_breakpoint = kgdb_arch_set_hw_breakpoint,
+       .remove_hw_breakpoint = kgdb_arch_remove_hw_breakpoint,
+       .gdb_bpt_instr = {0xcc},
+       .flags = KGDB_HW_BREAKPOINT,
+};
Index: linux-2.6.21-rc3-kgdb/arch/ia64/kernel/smp.c
===================================================================
--- linux-2.6.21-rc3-kgdb.orig/arch/ia64/kernel/smp.c   2007-03-16 
14:37:34.000000000 -0500
+++ linux-2.6.21-rc3-kgdb/arch/ia64/kernel/smp.c        2007-03-18 
11:16:46.000000000 -0500
@@ -48,6 +48,7 @@
 #include <asm/tlbflush.h>
 #include <asm/unistd.h>
 #include <asm/mca.h>
+#include <linux/kgdb.h>
 
 /*
  * Structure and data for smp_call_function(). This is designed to minimise 
static memory
@@ -67,6 +68,9 @@ static volatile struct call_data_struct 
 
 #define IPI_CALL_FUNC          0
 #define IPI_CPU_STOP           1
+#ifdef CONFIG_KGDB
+#define        IPI_KGDB_INTERRUPT      2
+#endif
 #define IPI_KDUMP_CPU_STOP     3
 
 /* This needs to be cacheline aligned because it is written to by *other* 
CPUs.  */
@@ -157,6 +161,11 @@ handle_IPI (int irq, void *dev_id)
                              case IPI_CPU_STOP:
                                stop_this_cpu();
                                break;
+#ifdef CONFIG_KGDB
+                             case IPI_KGDB_INTERRUPT:
+                               kgdb_wait_ipi(get_irq_regs());
+                               break;
+#endif
 #ifdef CONFIG_KEXEC
                              case IPI_KDUMP_CPU_STOP:
                                unw_init_running(kdump_cpu_freeze, NULL);
@@ -331,6 +340,14 @@ smp_call_function_single (int cpuid, voi
 }
 EXPORT_SYMBOL(smp_call_function_single);
 
+#ifdef CONFIG_KGDB
+void
+smp_send_nmi_allbutself(void)
+{
+       send_IPI_allbutself(IPI_KGDB_INTERRUPT);
+}
+#endif
+
 /*
  * this function sends a 'generic call function' IPI to all other CPUs
  * in the system.
Index: linux-2.6.21-rc3-kgdb/arch/ia64/kernel/traps.c
===================================================================
--- linux-2.6.21-rc3-kgdb.orig/arch/ia64/kernel/traps.c 2007-03-16 
14:37:34.000000000 -0500
+++ linux-2.6.21-rc3-kgdb/arch/ia64/kernel/traps.c      2007-03-16 
14:40:29.000000000 -0500
@@ -170,8 +170,12 @@ __kprobes ia64_bad_break (unsigned long 
                break;
 
              default:
-               if (break_num < 0x40000 || break_num > 0x100000)
+               if (break_num < 0x40000 || break_num > 0x100000) {
+                       if (notify_die(DIE_BREAK, "bad break", regs,
+                               break_num, TRAP_BRKPT, SIGTRAP) == NOTIFY_STOP)
+                               return;
                        die_if_kernel("Bad break", regs, break_num);
+               }
 
                if (break_num < 0x80000) {
                        sig = SIGILL; code = __ILL_BREAK;
Index: linux-2.6.21-rc3-kgdb/arch/ia64/kernel/Makefile
===================================================================
--- linux-2.6.21-rc3-kgdb.orig/arch/ia64/kernel/Makefile        2007-03-16 
14:37:18.000000000 -0500
+++ linux-2.6.21-rc3-kgdb/arch/ia64/kernel/Makefile     2007-03-16 
14:40:29.000000000 -0500
@@ -34,6 +34,7 @@ obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) +=
 obj-$(CONFIG_AUDIT)            += audit.o
 obj-$(CONFIG_PCI_MSI)          += msi_ia64.o
 mca_recovery-y                 += mca_drv.o mca_drv_asm.o
+obj-$(CONFIG_KGDB)             += kgdb.o kgdb-jmp.o
 
 obj-$(CONFIG_IA64_ESI)         += esi.o
 ifneq ($(CONFIG_IA64_ESI),)
Index: linux-2.6.21-rc3-kgdb/lib/Kconfig.debug
===================================================================
--- linux-2.6.21-rc3-kgdb.orig/lib/Kconfig.debug        2007-03-16 
14:40:28.000000000 -0500
+++ linux-2.6.21-rc3-kgdb/lib/Kconfig.debug     2007-03-18 11:29:41.000000000 
-0500
@@ -456,7 +456,7 @@ config WANT_EXTRA_DEBUG_INFORMATION
 config KGDB
        bool "KGDB: kernel debugging with remote gdb"
        select WANT_EXTRA_DEBUG_INFORMATION
-       depends on DEBUG_KERNEL && (X86 || MIPS || PPC)
+       depends on DEBUG_KERNEL && (X86 || MIPS || IA64 || PPC)
        help
          If you say Y here, it will be possible to remotely debug the
          kernel using gdb. It is strongly suggested that you enable
Index: linux-2.6.21-rc3-kgdb/include/asm-ia64/kgdb.h
===================================================================
--- /dev/null   1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.21-rc3-kgdb/include/asm-ia64/kgdb.h       2007-03-18 
11:17:13.000000000 -0500
@@ -0,0 +1,36 @@
+#ifdef __KERNEL__
+#ifndef _ASM_KGDB_H_
+#define _ASM_KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+#include <linux/threads.h>
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound 
buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX                 1024
+
+/* Number of bytes of registers.  We set this to 0 so that certain GDB
+ * packets will fail, forcing the use of others, which are more friendly
+ * on ia64. */
+#define NUMREGBYTES            0
+
+#define NUMCRITREGBYTES                (70*8)
+#define JMP_REGS_ALIGNMENT     __attribute__ ((aligned (16)))
+
+#define BREAKNUM               0x00003333300LL
+#define KGDBBREAKNUM           0x6665UL
+#define BREAKPOINT()           asm volatile ("break.m 0x6665")
+#define BREAK_INSTR_SIZE       16
+#define CACHE_FLUSH_IS_SAFE    1
+
+struct pt_regs;
+extern volatile int kgdb_hwbreak_sstep[NR_CPUS];
+extern void smp_send_nmi_allbutself(void);
+extern void kgdb_wait_ipi(struct pt_regs *regs);
+#endif                         /* _ASM_KGDB_H_ */
+#endif                         /* __KERNEL__ */
Index: linux-2.6.21-rc3-kgdb/include/asm-ia64/kdebug.h
===================================================================
--- linux-2.6.21-rc3-kgdb.orig/include/asm-ia64/kdebug.h        2007-03-16 
14:36:51.000000000 -0500
+++ linux-2.6.21-rc3-kgdb/include/asm-ia64/kdebug.h     2007-03-16 
14:40:29.000000000 -0500
@@ -72,6 +72,7 @@ enum die_val {
        DIE_KDEBUG_LEAVE,
        DIE_KDUMP_ENTER,
        DIE_KDUMP_LEAVE,
+       DIE_PAGE_FAULT_NO_CONTEXT,
 };
 
 static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs,

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Kgdb-bugreport mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/kgdb-bugreport

Reply via email to