From: Tom Rini <trini@kernel.crashing.org>
To: akpm@osdl.org
Cc: linux-kernel@vger.kernel.org, trini@kernel.crashing.org,
davidm@hpl.hp.com, Robert.Picco@hp.com, keldon@hp.com
Subject: [patch 6/8] KGDB support for ia64
Date: Fri, 29 Oct 2004 11:34:08 -0700 [thread overview]
Message-ID: <6.29102004.trini@kernel.crashing.org> (raw)
In-Reply-To: <5.29102004.trini@kernel.crashing.org>
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 = ®
+ 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, ®, &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, ®, &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, ®, 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, ®, 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, ®);
+ else
+ reg = ptregs->cr_iip;
+ size = sizeof(reg);
+ }
+ else if (regnum == IA64_CFM_REGNUM) {
+ if (!ptregs)
+ unw_get_cfm(info, ®);
+ 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, ®, 0);
+ size = sizeof(reg);
+ }
+ else if (regnum == IA64_BSP_REGNUM) {
+ unw_get_bsp(info, ®);
+ 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, ®, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_SSD_REGNUM:
+ if (ptregs)
+ reg = ptregs->ar_ssd;
+ else
+ unw_access_ar(info, UNW_AR_SSD, ®, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_UNAT_REGNUM:
+ if (ptregs)
+ reg = ptregs->ar_unat;
+ else
+ unw_access_ar(info, UNW_AR_UNAT, ®, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_RNAT_REGNUM:
+ unw_access_ar(info, UNW_AR_RNAT, ®, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_BSPSTORE_REGNUM:
+ unw_access_ar(info, UNW_AR_BSPSTORE, ®, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_PFS_REGNUM:
+ unw_access_ar(info, UNW_AR_PFS, ®, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_LC_REGNUM:
+ unw_access_ar(info, UNW_AR_LC, ®, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_EC_REGNUM:
+ unw_access_ar(info, UNW_AR_EC, ®, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_FPSR_REGNUM:
+ if (ptregs)
+ reg = ptregs->ar_fpsr;
+ else
+ unw_access_ar(info, UNW_AR_FPSR, ®, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_RSC_REGNUM:
+ if (ptregs)
+ reg = ptregs->ar_rsc;
+ else
+ unw_access_ar(info, UNW_AR_RNAT, ®, 0);
+ size = sizeof(reg);
+ break;
+ case IA64_CCV_REGNUM:
+ unw_access_ar(info, UNW_AR_CCV, ®, 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, ®);
+ 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, ®, &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, ®, 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, ®, 1);
+ break;
+ case IA64_BSPSTORE_REGNUM:
+ unw_access_ar(info, UNW_AR_BSPSTORE, ®, 1);
+ break;
+ case IA64_PFS_REGNUM:
+ unw_access_ar(info, UNW_AR_PFS, ®, 1);
+ break;
+ case IA64_LC_REGNUM:
+ unw_access_ar(info, UNW_AR_LC, ®, 1);
+ break;
+ case IA64_EC_REGNUM:
+ unw_access_ar(info, UNW_AR_EC, ®, 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, ®, 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 *) ®num, 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
_
next prev parent reply other threads:[~2004-10-29 19:19 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-10-29 18:32 [patch 1/8] A different KGDB stub for -mm Tom Rini
2004-10-29 18:33 ` [patch 2/8] KGDB support for i386 Tom Rini
2004-10-29 18:33 ` [patch 3/8] KGDB support for ppc32 Tom Rini
2004-10-29 18:33 ` [patch 4/8] 8250 uart driver for KGDB Tom Rini
2004-10-29 18:33 ` [patch 5/8] KGDB support for MIPS Tom Rini
2004-10-29 18:34 ` Tom Rini [this message]
2004-10-29 18:34 ` [patch 7/8] KGDB support for x86_64 Tom Rini
2004-10-29 18:34 ` [patch 8/8] KGDB over ethernet driver Tom Rini
2004-10-29 23:13 ` [patch 7/8] KGDB support for x86_64 Andi Kleen
2004-10-30 19:05 ` [patch 3/8] KGDB support for ppc32 Tom Rini
2004-10-29 18:35 ` [patch 1/8] A different KGDB stub for -mm Tom Rini
2004-10-29 19:53 ` Tom Rini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=6.29102004.trini@kernel.crashing.org \
--to=trini@kernel.crashing.org \
--cc=Robert.Picco@hp.com \
--cc=akpm@osdl.org \
--cc=davidm@hpl.hp.com \
--cc=keldon@hp.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.