LWN.net Logo

KGDB support for ia64

From:  Tom Rini <trini@kernel.crashing.org>
To:  akpm@osdl.org
Subject:  [patch 6/8] KGDB support for ia64
Date:  Fri, 29 Oct 2004 11:34:08 -0700
Cc:  linux-kernel@vger.kernel.org, trini@kernel.crashing.org, davidm@hpl.hp.com, Robert.Picco@hp.com, keldon@hp.com


Cc: David Mosberger-Tang <davidm@hpl.hp.com>, Robert Picco <Robert.Picco@hp.com>, Keldon Jones <keldon@hp.com>
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@veritas.com>
+ *  Modified for 386 by Jim Kingdon, Cygnus Support.
+ *  Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com>
+ */
+
+#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@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Copyright © 2004, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds