[patch 6/8] KGDB support for ia64

From: Tom Rini
Date: Fri Oct 29 2004 - 14:21:23 EST



Cc: David Mosberger-Tang <davidm@xxxxxxxxxx>, Robert Picco <Robert.Picco@xxxxxx>, Keldon Jones <keldon@xxxxxx>
This adds support for KGDB to ia64 and was done by Robert Picco and Keldon
Jones.

---

linux-2.6.10-rc1-trini/arch/ia64/kernel/Makefile | 1
linux-2.6.10-rc1-trini/arch/ia64/kernel/irq.c | 4
linux-2.6.10-rc1-trini/arch/ia64/kernel/ivt.S | 17
linux-2.6.10-rc1-trini/arch/ia64/kernel/kgdb.c | 991 ++++++++++++++++++++++
linux-2.6.10-rc1-trini/arch/ia64/kernel/process.c | 6
linux-2.6.10-rc1-trini/arch/ia64/kernel/smp.c | 17
linux-2.6.10-rc1-trini/arch/ia64/kernel/traps.c | 26
linux-2.6.10-rc1-trini/arch/ia64/kernel/unwind.c | 61 +
linux-2.6.10-rc1-trini/arch/ia64/mm/fault.c | 3
linux-2.6.10-rc1-trini/drivers/firmware/pcdp.c | 19
linux-2.6.10-rc1-trini/include/asm-ia64/kgdb.h | 34
linux-2.6.10-rc1-trini/lib/Kconfig.debug | 2
12 files changed, 1179 insertions(+), 2 deletions(-)

diff -puN arch/ia64/kernel/Makefile~ia64-lite arch/ia64/kernel/Makefile
--- linux-2.6.10-rc1/arch/ia64/kernel/Makefile~ia64-lite 2004-10-29 11:26:45.490207282 -0700
+++ linux-2.6.10-rc1-trini/arch/ia64/kernel/Makefile 2004-10-29 11:26:45.514201648 -0700
@@ -19,6 +19,7 @@ obj-$(CONFIG_PERFMON) += perfmon_defaul
obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
mca_recovery-y += mca_drv.o mca_drv_asm.o
+obj-$(CONFIG_KGDB) += kgdb.o

# The gate DSO image is built using a special linker script.
targets += gate.so gate-syms.o
diff -puN arch/ia64/kernel/irq.c~ia64-lite arch/ia64/kernel/irq.c
--- linux-2.6.10-rc1/arch/ia64/kernel/irq.c~ia64-lite 2004-10-29 11:26:45.492206812 -0700
+++ linux-2.6.10-rc1-trini/arch/ia64/kernel/irq.c 2004-10-29 11:26:45.515201413 -0700
@@ -42,6 +42,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/kallsyms.h>
+#include <linux/kgdb.h>
#include <linux/notifier.h>
#include <linux/bitops.h>

@@ -543,6 +544,9 @@ unsigned int do_IRQ(unsigned long irq, s
desc->handler->end(irq);
spin_unlock(&desc->lock);
}
+
+ kgdb_process_breakpoint();
+
return 1;
}

diff -puN arch/ia64/kernel/ivt.S~ia64-lite arch/ia64/kernel/ivt.S
--- linux-2.6.10-rc1/arch/ia64/kernel/ivt.S~ia64-lite 2004-10-29 11:26:45.494206343 -0700
+++ linux-2.6.10-rc1-trini/arch/ia64/kernel/ivt.S 2004-10-29 11:26:45.516201178 -0700
@@ -68,6 +68,13 @@
# define DBG_FAULT(i)
#endif

+#ifdef CONFIG_KGDB
+#define KGDB_ENABLE_PSR_DB mov r31=psr;; movl r30=IA64_PSR_DB;; or r31=r31,r30;; \
+ mov psr.l=r31;; srlz.i;;
+#else
+#define KGDB_ENABLE_PSR_DB
+#endif
+
#define MINSTATE_VIRT /* needed by minstate.h */
#include "minstate.h"

@@ -473,6 +480,7 @@ ENTRY(page_fault)
movl r14=ia64_leave_kernel
;;
SAVE_REST
+ KGDB_ENABLE_PSR_DB
mov rp=r14
;;
adds out2=16,r12 // out2 = pointer to pt_regs
@@ -733,6 +741,8 @@ ENTRY(break_fault)
;;
srlz.i // guarantee that interruption collection is on
;;
+ KGDB_ENABLE_PSR_DB
+ ;;
(p15) ssm psr.i // restore psr.i
;;
mov r3=NR_syscalls - 1
@@ -776,6 +786,7 @@ ENTRY(interrupt)
srlz.i // ensure everybody knows psr.ic is back on
;;
SAVE_REST
+ KGDB_ENABLE_PSR_DB
;;
alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group
mov out0=cr.ivr // pass cr.ivr as first arg
@@ -1003,6 +1014,7 @@ ENTRY(non_syscall)
movl r15=ia64_leave_kernel
;;
SAVE_REST
+ KGDB_ENABLE_PSR_DB
mov rp=r15
;;
br.call.sptk.many b6=ia64_bad_break // avoid WAW on CFM and ignore return addr
@@ -1036,6 +1048,7 @@ ENTRY(dispatch_unaligned_handler)
adds r3=8,r2 // set up second base pointer
;;
SAVE_REST
+ KGDB_ENABLE_PSR_DB
movl r14=ia64_leave_kernel
;;
mov rp=r14
@@ -1078,6 +1091,10 @@ ENTRY(dispatch_to_fault_handler)
adds r3=8,r2 // set up second base pointer for SAVE_REST
;;
SAVE_REST
+ cmp.eq p6,p0=29,out0
+(p6) br.cond.spnt 1f;; // debug_vector
+ KGDB_ENABLE_PSR_DB
+1:
movl r14=ia64_leave_kernel
;;
mov rp=r14
diff -puN /dev/null arch/ia64/kernel/kgdb.c
--- /dev/null 2004-10-25 00:35:20.587727328 -0700
+++ linux-2.6.10-rc1-trini/arch/ia64/kernel/kgdb.c 2004-10-29 11:26:45.518200709 -0700
@@ -0,0 +1,991 @@
+/*
+ *
+ * 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.
+ */
+/*
+ * Contributor: Lake Stevens Instrument Division$
+ * Written by: Glenn Engel $
+ * Updated by: Amit Kale<akale@xxxxxxxxxxx>
+ * Modified for 386 by Jim Kingdon, Cygnus Support.
+ * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@xxxxxxxx>
+ */
+
+#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 <linux/debugger.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 ptoff(V) ((unsigned int) &((struct pt_regs *)0x0)->V)
+struct reg_to_ptreg_index {
+ unsigned int reg;
+ unsigned int ptregoff;
+};
+struct reg_to_ptreg_index gr_reg_to_ptreg_index[] = {
+ {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+1, ptoff(r1)},
+ {IA64_GR0_REGNUM+12, ptoff(r12)},
+ {IA64_GR0_REGNUM+13, ptoff(r13)},
+ {IA64_GR0_REGNUM+14, ptoff(r14)},
+ {IA64_GR0_REGNUM+15, ptoff(r15)},
+};
+
+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)},
+};
+
+extern atomic_t cpu_doing_single_step;
+
+void kgdb_get_reg(char *outbuffer, int regnum, struct unw_frame_info *info, struct pt_regs *ptregs)
+{
+ unsigned long reg, size = 0, *mem = &reg;
+ char nat;
+ struct ia64_fpreg freg;
+ int i;
+
+ if ((regnum >= IA64_GR0_REGNUM && regnum <= (IA64_GR0_REGNUM+1)) ||
+ (regnum >= (IA64_GR0_REGNUM+4) && regnum <= (IA64_GR0_REGNUM+7)) ||
+ (regnum >= (IA64_GR0_REGNUM+16) && regnum <= (IA64_GR0_REGNUM+31))) {
+ unw_access_gr(info, regnum - IA64_GR0_REGNUM, &reg, &nat, 0);
+ size = sizeof(reg);
+ }
+ else if ((regnum >= (IA64_GR0_REGNUM+2) && regnum <= (IA64_GR0_REGNUM+3)) ||
+ (regnum >= (IA64_GR0_REGNUM+8) && regnum <= (IA64_GR0_REGNUM+15))) {
+ if (ptregs) {
+ for (i = 0; i < (sizeof (gr_reg_to_ptreg_index) /
+ sizeof(gr_reg_to_ptreg_index[0])); i++)
+ if (gr_reg_to_ptreg_index[0].reg == regnum) {
+ reg = * ((unsigned long *)
+ (((void *) ptregs) + gr_reg_to_ptreg_index[i].ptregoff));
+ break;
+ }
+ } else
+ unw_access_gr(info, regnum - IA64_GR0_REGNUM, &reg, &nat, 0);
+ size = sizeof(reg);
+ }
+ else if (regnum >= IA64_BR0_REGNUM && regnum <= (IA64_BR0_REGNUM+7)) switch(regnum) {
+ case IA64_BR0_REGNUM:
+ case IA64_BR0_REGNUM+6:
+ case IA64_BR0_REGNUM+7:
+ if (ptregs) {
+ for (i = 0; i < (sizeof(br_reg_to_ptreg_index) /
+ sizeof(br_reg_to_ptreg_index[0])); i++)
+ if (br_reg_to_ptreg_index[i].reg == regnum) {
+ reg = * ((unsigned long *)
+ (((void *) ptregs) + br_reg_to_ptreg_index[i].ptregoff));
+ break;
+ }
+ } else
+ unw_access_br(info, regnum - IA64_BR0_REGNUM, &reg, 0);
+ size = sizeof(reg);
+ 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:
+ unw_access_br(info, regnum - IA64_BR0_REGNUM, &reg, 0);
+ size = sizeof(reg);
+ break;
+ }
+ else if (regnum >= IA64_FR0_REGNUM && regnum <= (IA64_FR0_REGNUM + 127)) 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 (!ptregs)
+ unw_access_fr(info, regnum - IA64_FR0_REGNUM, &freg, 0);
+ else {
+ freg = *(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM+6)));
+ }
+ size = sizeof(freg);
+ mem = (unsigned long *) &freg;
+ break;
+ default:
+ unw_access_fr(info, regnum - IA64_FR0_REGNUM, &freg, 0);
+ break;
+ }
+ else if (regnum == IA64_IP_REGNUM) {
+ if (!ptregs)
+ unw_get_ip(info, &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);
+ }
+ else if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_EC_REGNUM) switch (regnum) {
+ case IA64_CSD_REGNUM:
+ if (ptregs)
+ reg = ptregs->ar_csd;
+ else
+ unw_access_ar(info, UNW_AR_CSD, &reg, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_SSD_REGNUM:
+ if (ptregs)
+ reg = ptregs->ar_ssd;
+ else
+ unw_access_ar(info, UNW_AR_SSD, &reg, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_UNAT_REGNUM:
+ if (ptregs)
+ reg = ptregs->ar_unat;
+ else
+ unw_access_ar(info, UNW_AR_UNAT, &reg, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_RNAT_REGNUM:
+ unw_access_ar(info, UNW_AR_RNAT, &reg, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_BSPSTORE_REGNUM:
+ unw_access_ar(info, UNW_AR_BSPSTORE, &reg, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_PFS_REGNUM:
+ unw_access_ar(info, UNW_AR_PFS, &reg, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_LC_REGNUM:
+ unw_access_ar(info, UNW_AR_LC, &reg, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_EC_REGNUM:
+ unw_access_ar(info, UNW_AR_EC, &reg, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_FPSR_REGNUM:
+ if (ptregs)
+ reg = ptregs->ar_fpsr;
+ else
+ unw_access_ar(info, UNW_AR_FPSR, &reg, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_RSC_REGNUM:
+ if (ptregs)
+ reg = ptregs->ar_rsc;
+ else
+ unw_access_ar(info, UNW_AR_RNAT, &reg, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_CCV_REGNUM:
+ unw_access_ar(info, UNW_AR_CCV, &reg, 0);
+ size = sizeof(reg);
+ break;
+ }
+
+ 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;
+ char nat = 0;
+ struct ia64_fpreg freg;
+ int i;
+ char *ptr;
+
+ ptr = inbuffer;
+ kgdb_hex2long(&ptr, &reg);
+ strcpy(outbuffer, "OK");
+
+ if ((regnum >= IA64_GR0_REGNUM && regnum <= (IA64_GR0_REGNUM+1)) ||
+ (regnum >= (IA64_GR0_REGNUM+4) && regnum <= (IA64_GR0_REGNUM+7)) ||
+ (regnum >= (IA64_GR0_REGNUM+16) && regnum <= (IA64_GR0_REGNUM+31))) {
+ unw_access_gr(info, regnum - IA64_GR0_REGNUM, &reg, &nat, 1);
+ }
+ else if ((regnum >= (IA64_GR0_REGNUM+2) && regnum <= (IA64_GR0_REGNUM+3)) ||
+ (regnum >= (IA64_GR0_REGNUM+8) && regnum <= (IA64_GR0_REGNUM+15))) {
+ for (i = 0; i < (sizeof (gr_reg_to_ptreg_index) /
+ sizeof(gr_reg_to_ptreg_index[0])); i++)
+ if (gr_reg_to_ptreg_index[0].reg == regnum) {
+ * ((unsigned long *)
+ (((void *) ptregs) + gr_reg_to_ptreg_index[i].ptregoff)) = reg;
+ break;
+ }
+ }
+ else if (regnum >= IA64_BR0_REGNUM && regnum <= (IA64_BR0_REGNUM+7)) switch(regnum) {
+ case IA64_BR0_REGNUM:
+ case IA64_BR0_REGNUM+6:
+ case IA64_BR0_REGNUM+7:
+ for (i = 0; i < (sizeof(br_reg_to_ptreg_index) /
+ sizeof(br_reg_to_ptreg_index[0])); i++)
+ if (br_reg_to_ptreg_index[i].reg == regnum) {
+ * ((unsigned long *)
+ (((void *) ptregs) + br_reg_to_ptreg_index[i].ptregoff)) = reg;
+ 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:
+ unw_access_br(info, regnum - IA64_BR0_REGNUM, &reg, 1);
+ break;
+ }
+ else if (regnum >= IA64_FR0_REGNUM && regnum <= (IA64_FR0_REGNUM + 127)) 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:
+ freg.u.bits[0] = reg;
+ kgdb_hex2long(&ptr, &freg.u.bits[1]);
+ *(&ptregs->f6 + (regnum - (IA64_FR0_REGNUM+6))) = freg;
+ break;
+ default:
+ break;
+ }
+ 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 if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_EC_REGNUM) switch (regnum) {
+ case IA64_CSD_REGNUM:
+ ptregs->ar_csd = reg;
+ break;
+ case IA64_SSD_REGNUM:
+ ptregs->ar_ssd = reg;
+ case IA64_UNAT_REGNUM:
+ ptregs->ar_unat = reg;
+ case IA64_RNAT_REGNUM:
+ unw_access_ar(info, UNW_AR_RNAT, &reg, 1);
+ break;
+ case IA64_BSPSTORE_REGNUM:
+ unw_access_ar(info, UNW_AR_BSPSTORE, &reg, 1);
+ break;
+ case IA64_PFS_REGNUM:
+ unw_access_ar(info, UNW_AR_PFS, &reg, 1);
+ break;
+ case IA64_LC_REGNUM:
+ unw_access_ar(info, UNW_AR_LC, &reg, 1);
+ break;
+ case IA64_EC_REGNUM:
+ unw_access_ar(info, UNW_AR_EC, &reg, 1);
+ break;
+ case IA64_FPSR_REGNUM:
+ ptregs->ar_fpsr = reg;
+ break;
+ case IA64_RSC_REGNUM:
+ ptregs->ar_rsc = reg;
+ break;
+ case IA64_CCV_REGNUM:
+ unw_access_ar(info, UNW_AR_CCV, &reg, 1);
+ break;
+ }
+ 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 */
+};
+
+static int kgdb_arch_set_breakpoint(unsigned long addr, char *saved_instr)
+{
+ extern unsigned long _start[];
+ unsigned long slot = addr & 0xf, 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);
+}
+
+static int kgdb_arch_remove_breakpoint(unsigned long addr, char *bundle)
+{
+ extern unsigned long _start[];
+
+ addr = addr & ~0xFULL;
+ 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;
+ }
+
+ 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);
+}
+
+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;
+}
+
+void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+{
+ if (num_online_cpus() > 1)
+ smp_send_nmi_allbutself();
+}
+
+static void do_kgdb_handle_exception(struct unw_frame_info *, void *data);
+
+struct kgdb_state {
+ int exceptionVector;
+ 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;
+}
+
+volatile int kgdb_hwbreak_sstep[NR_CPUS];
+
+int kgdb_arch_handle_exception(int exceptionVector, int signo,
+ int err_code, char *remcom_in_buffer,
+ char *remcom_out_buffer, struct pt_regs *linux_regs)
+{
+ struct kgdb_state info;
+
+ info.exceptionVector = exceptionVector;
+ 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.unwind = 1;
+ info.regs = linux_regs;
+ 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\n");
+ kgdb_mem2hex((char *) &bad, remcom_out_buffer, sizeof (bad));
+ remcom_out_buffer[sizeof (bad) * 2] = 0;
+ info.ret = -1;
+ }
+ return info.ret;
+}
+
+
+
+static void do_kgdb_handle_exception(struct unw_frame_info *unw_info, void *data)
+{
+ long addr;
+ char *ptr;
+ unsigned long newPC;
+ int exceptionVector, 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;
+ exceptionVector = info->exceptionVector;
+ 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':
+ {
+ int regnum;
+
+ kgdb_hex2mem(&remcom_in_buffer[1], (char *) &regnum, sizeof(regnum));
+ 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':
+ {
+ 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 = (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 (kgdb_contthread && kgdb_contthread != current) {
+ strcpy(remcom_out_buffer, "E00");
+ break;
+ }
+
+ if (exceptionVector == 11 && 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' || exceptionVector == 29) {
+ 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 (exceptionVector != 29)
+ 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_breakpoint = kgdb_arch_set_breakpoint,
+ .remove_breakpoint = kgdb_arch_remove_breakpoint,
+ .set_hw_breakpoint = kgdb_arch_set_hw_breakpoint,
+ .remove_hw_breakpoint = kgdb_arch_remove_hw_breakpoint,
+ .gdb_bpt_instr = {0xcc},
+ .flags = KGDB_HW_BREAKPOINT,
+};
diff -puN arch/ia64/kernel/process.c~ia64-lite arch/ia64/kernel/process.c
--- linux-2.6.10-rc1/arch/ia64/kernel/process.c~ia64-lite 2004-10-29 11:26:45.496205873 -0700
+++ linux-2.6.10-rc1-trini/arch/ia64/kernel/process.c 2004-10-29 11:26:45.518200709 -0700
@@ -415,6 +415,9 @@ copy_thread (int nr, unsigned long clone
*/
child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
& ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
+#ifdef CONFIG_KGDB
+ child_ptregs->cr_ipsr |= IA64_PSR_DB;
+#endif

/*
* NOTE: The calling convention considers all floating point
@@ -643,6 +646,9 @@ kernel_thread (int (*fn)(void *), void *
regs.pt.r11 = (unsigned long) arg; /* 2nd argument */
/* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read. */
regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
+#ifdef CONFIG_KGDB
+ regs.pt.cr_ipsr |= IA64_PSR_DB;
+#endif
regs.pt.cr_ifs = 1UL << 63; /* mark as valid, empty frame */
regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR);
regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET;
diff -puN arch/ia64/kernel/smp.c~ia64-lite arch/ia64/kernel/smp.c
--- linux-2.6.10-rc1/arch/ia64/kernel/smp.c~ia64-lite 2004-10-29 11:26:45.498205404 -0700
+++ linux-2.6.10-rc1-trini/arch/ia64/kernel/smp.c 2004-10-29 11:26:45.519200474 -0700
@@ -47,6 +47,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
@@ -66,6 +67,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

/* This needs to be cacheline aligned because it is written to by *other* CPUs. */
static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned;
@@ -155,6 +159,11 @@ handle_IPI (int irq, void *dev_id, struc
case IPI_CPU_STOP:
stop_this_cpu();
break;
+#ifdef CONFIG_KGDB
+ case IPI_KGDB_INTERRUPT:
+ kgdb_wait_ipi(regs);
+ break;
+#endif

default:
printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
@@ -303,6 +312,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.
diff -puN arch/ia64/kernel/traps.c~ia64-lite arch/ia64/kernel/traps.c
--- linux-2.6.10-rc1/arch/ia64/kernel/traps.c~ia64-lite 2004-10-29 11:26:45.500204934 -0700
+++ linux-2.6.10-rc1-trini/arch/ia64/kernel/traps.c 2004-10-29 11:26:45.520200239 -0700
@@ -15,6 +15,7 @@
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/module.h> /* for EXPORT_SYMBOL */
#include <linux/hardirq.h>
+#include <linux/kgdb.h>

#include <asm/fpswa.h>
#include <asm/ia32.h>
@@ -92,6 +93,8 @@ die (const char *str, struct pt_regs *re
} else
printk(KERN_ERR "Recursive die() failure, output suppressed\n");

+ CHK_DEBUGGER(1, SIGTRAP, err, regs,);
+
bust_spinlocks(0);
die.lock_owner = -1;
spin_unlock_irq(&die.lock);
@@ -119,7 +122,9 @@ ia64_bad_break (unsigned long break_num,

switch (break_num) {
case 0: /* unknown error (used by GCC for __builtin_abort()) */
+#ifndef CONFIG_KGDB
die_if_kernel("bugcheck!", regs, break_num);
+#endif
sig = SIGILL; code = ILL_ILLOPC;
break;

@@ -172,8 +177,10 @@ ia64_bad_break (unsigned long break_num,
break;

default:
+#ifndef CONFIG_KGDB
if (break_num < 0x40000 || break_num > 0x100000)
die_if_kernel("Bad break", regs, break_num);
+#endif

if (break_num < 0x80000) {
sig = SIGILL; code = __ILL_BREAK;
@@ -181,6 +188,13 @@ ia64_bad_break (unsigned long break_num,
sig = SIGTRAP; code = TRAP_BRKPT;
}
}
+#ifdef CONFIG_KGDB
+ /*
+ * We don't want to trap simulator system calls.
+ */
+ if (break_num != 0x80001)
+ CHK_DEBUGGER(11, sig, break_num, regs, return);
+#endif
siginfo.si_signo = sig;
siginfo.si_errno = 0;
siginfo.si_code = code;
@@ -487,9 +501,18 @@ ia64_fault (unsigned long vector, unsign
sprintf(buf, "Unsupported data reference");
break;

+ case 36: /* Single Step Trap */
+#ifdef CONFIG_KGDB
+ if (linux_debug_hook != (gdb_debug_hook *) NULL && !user_mode(regs) &&
+ kgdb_hwbreak_sstep[smp_processor_id()]) {
+ kgdb_hwbreak_sstep[smp_processor_id()] = 0;
+ regs->cr_ipsr &= ~IA64_PSR_SS;
+ return;
+ }
+#endif
case 29: /* Debug */
+ CHK_DEBUGGER(vector, SIGTRAP, isr, regs, return);
case 35: /* Taken Branch Trap */
- case 36: /* Single Step Trap */
if (fsys_mode(current, regs)) {
extern char __kernel_syscall_via_break[];
/*
@@ -604,6 +627,7 @@ ia64_fault (unsigned long vector, unsign
sprintf(buf, "Fault %lu", vector);
break;
}
+ CHK_DEBUGGER(vector, SIGTRAP, isr, regs,);
die_if_kernel(buf, regs, error);
force_sig(SIGILL, current);
}
diff -puN arch/ia64/kernel/unwind.c~ia64-lite arch/ia64/kernel/unwind.c
--- linux-2.6.10-rc1/arch/ia64/kernel/unwind.c~ia64-lite 2004-10-29 11:26:45.502204465 -0700
+++ linux-2.6.10-rc1-trini/arch/ia64/kernel/unwind.c 2004-10-29 11:26:45.522199770 -0700
@@ -74,10 +74,68 @@
# define STAT(x...)
#endif

+#ifdef CONFIG_KGDB
+#define KGDB_EARLY_SIZE 100
+static struct unw_reg_state __initdata kgdb_reg_state[KGDB_EARLY_SIZE];
+static struct unw_labeled_state __initdata kgdb_labeled_state[KGDB_EARLY_SIZE];
+void __initdata *kgdb_reg_state_free, __initdata *kgdb_labeled_state_free;
+
+static void __init
+kgdb_malloc_init(void)
+{
+ int i;
+
+ kgdb_reg_state_free = kgdb_reg_state;
+ for (i = 1; i < KGDB_EARLY_SIZE; i++) {
+ *((unsigned long *) &kgdb_reg_state[i]) = (unsigned long) kgdb_reg_state_free;
+ kgdb_reg_state_free = &kgdb_reg_state[i];
+ }
+
+ kgdb_labeled_state_free = kgdb_labeled_state;
+ for (i = 1; i < KGDB_EARLY_SIZE; i++) {
+ *((unsigned long *) &kgdb_labeled_state[i]) =
+ (unsigned long) kgdb_labeled_state_free;
+ kgdb_labeled_state_free = &kgdb_labeled_state[i];
+ }
+
+}
+
+static void * __init
+kgdb_malloc(void **mem)
+{
+ void *p;
+
+ p = *mem;
+ *mem = *((void **) p);
+ return p;
+}
+
+static void __init
+kgdb_free(void **mem, void *p)
+{
+ *((void **)p) = *mem;
+ *mem = p;
+}
+
+#define alloc_reg_state() (!malloc_sizes[0].cs_cachep ? \
+ kgdb_malloc(&kgdb_reg_state_free) : \
+ kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC))
+#define free_reg_state(usr) (!malloc_sizes[0].cs_cachep ? \
+ kgdb_free(&kgdb_reg_state_free, usr) : \
+ kfree(usr))
+#define alloc_labeled_state() (!malloc_sizes[0].cs_cachep ? \
+ kgdb_malloc(&kgdb_labeled_state_free) : \
+ kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC))
+#define free_labeled_state(usr) (!malloc_sizes[0].cs_cachep ? \
+ kgdb_free(&kgdb_labeled_state_free, usr) : \
+ kfree(usr))
+
+#else
#define alloc_reg_state() kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC)
#define free_reg_state(usr) kfree(usr)
#define alloc_labeled_state() kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC)
#define free_labeled_state(usr) kfree(usr)
+#endif

typedef unsigned long unw_word;
typedef unsigned char unw_hash_index_t;
@@ -2261,6 +2319,9 @@ unw_init (void)

init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) __gp,
__start_unwind, __end_unwind);
+#ifdef CONFIG_KGDB
+ kgdb_malloc_init();
+#endif
}

/*
diff -puN arch/ia64/mm/fault.c~ia64-lite arch/ia64/mm/fault.c
--- linux-2.6.10-rc1/arch/ia64/mm/fault.c~ia64-lite 2004-10-29 11:26:45.504203995 -0700
+++ linux-2.6.10-rc1-trini/arch/ia64/mm/fault.c 2004-10-29 11:26:45.522199770 -0700
@@ -9,6 +9,7 @@
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
+#include <linux/kgdb.h>

#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -232,6 +233,8 @@ ia64_do_page_fault (unsigned long addres
*/
bust_spinlocks(1);

+ CHK_DEBUGGER(14, SIGSEGV, isr, regs,);
+
if (address < PAGE_SIZE)
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference (address %016lx)\n", address);
else
diff -puN drivers/firmware/pcdp.c~ia64-lite drivers/firmware/pcdp.c
--- linux-2.6.10-rc1/drivers/firmware/pcdp.c~ia64-lite 2004-10-29 11:26:45.506203526 -0700
+++ linux-2.6.10-rc1-trini/drivers/firmware/pcdp.c 2004-10-29 11:26:45.523199535 -0700
@@ -56,7 +56,11 @@ uart_edge_level(int rev, struct pcdp_uar
}

static void __init
+#ifndef CONFIG_KGDB
setup_serial_console(int rev, struct pcdp_uart *uart)
+#else
+setup_serial_console(int rev, struct pcdp_uart *uart, int line)
+#endif
{
#ifdef CONFIG_SERIAL_8250_CONSOLE
struct uart_port port;
@@ -64,6 +68,9 @@ setup_serial_console(int rev, struct pcd
int mapsize = 64;

memset(&port, 0, sizeof(port));
+#ifdef CONFIG_KGDB
+ port.line = line;
+#endif
port.uartclk = uart->clock_rate;
if (!port.uartclk) /* some FW doesn't supply this */
port.uartclk = BASE_BAUD * 16;
@@ -110,6 +117,9 @@ setup_serial_console(int rev, struct pcd

snprintf(options, sizeof(options), "%lun%d", uart->baud,
uart->bits ? uart->bits : 8);
+#ifdef CONFIG_KGDB
+ if (!line)
+#endif
add_preferred_console("ttyS", port.line, options);

printk(KERN_INFO "PCDP: serial console at %s 0x%lx (ttyS%d, options %s)\n",
@@ -156,10 +166,19 @@ efi_setup_pcdp_console(char *cmdline)
for (i = 0, uart = pcdp->uart; i < pcdp->num_uarts; i++, uart++) {
if (uart->flags & PCDP_UART_PRIMARY_CONSOLE || serial) {
if (uart->type == PCDP_CONSOLE_UART) {
+#ifndef CONFIG_KGDB
setup_serial_console(pcdp->rev, uart);
return;
+#else
+ setup_serial_console(pcdp->rev, uart, 0);
+ serial = 0;
+#endif
}
}
+#ifdef CONFIG_KGDB
+ else if (uart->type == PCDP_DEBUG_UART)
+ setup_serial_console(pcdp->rev, uart, 1);
+#endif
}

end = (struct pcdp_device *) ((u8 *) pcdp + pcdp->length);
diff -puN /dev/null include/asm-ia64/kgdb.h
--- /dev/null 2004-10-25 00:35:20.587727328 -0700
+++ linux-2.6.10-rc1-trini/include/asm-ia64/kgdb.h 2004-10-29 11:26:45.523199535 -0700
@@ -0,0 +1,34 @@
+#ifndef _ASM_KGDB_H_
+#define _ASM_KGDB_H_
+
+/*
+ * Copyright (C) 2001-2004 Amit S. Kale
+ */
+
+#include <linux/ptrace.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. */
+#define NUMREGBYTES 0
+
+#define BREAKNUM 0x00003333300LL
+#define KGDBBREAKNUM 0x6665UL
+
+extern volatile int kgdb_hwbreak_sstep[NR_CPUS];
+
+#define BREAKPOINT() asm volatile ("break.m 0x6665")
+#define BREAK_INSTR_SIZE 16
+
+#define CHECK_EXCEPTION_STACK() 1
+
+#define SERIAL_PORT_DFNS {0,}, {0,}, {0,}, {0,}
+
+extern void smp_send_nmi_allbutself(void);
+extern void kgdb_wait_ipi(struct pt_regs *);
+
+#endif /* _ASM_KGDB_H_ */
diff -puN lib/Kconfig.debug~ia64-lite lib/Kconfig.debug
--- linux-2.6.10-rc1/lib/Kconfig.debug~ia64-lite 2004-10-29 11:26:45.510202587 -0700
+++ linux-2.6.10-rc1-trini/lib/Kconfig.debug 2004-10-29 11:32:55.162382599 -0700
@@ -115,7 +115,7 @@ endif

config KGDB
bool "KGDB: kernel debugging with remote gdb"
- depends on DEBUG_KERNEL && (X86 || MIPS32 || ((!SMP || BROKEN) && PPC32))
+ depends on DEBUG_KERNEL && (X86 || MIPS32 || IA64 || ((!SMP || BROKEN) && PPC32))
help
If you say Y here, it will be possible to remotely debug the
kernel using gdb. This enlarges your kernel image disk size by
_
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/