public inbox for linux-ia64@vger.kernel.org
 help / color / mirror / Atom feed
* [Linux-ia64] print backtrace from OS INIT handler
@ 2003-04-15 20:24 David Mosberger
  2003-04-21 17:21 ` Bjorn Helgaas
  0 siblings, 1 reply; 2+ messages in thread
From: David Mosberger @ 2003-04-15 20:24 UTC (permalink / raw)
  To: linux-ia64

The patch below is relative to 2.5.67 and adds support to print a
backtrace from the OS INIT handler.  The complete INIT output looks
now something like shown below.  The example is for the case when INIT
is received while a CPU is idle in PAL_LIGHT_HALT.  Caveat: at the
moment, the INIT handler doing this dumping is called only on the
bootstrap CPU.  Hopefully, this can be extended to cover the other
CPUs without too much trouble (hint hint... ;-).

	--david

Entered OS INIT handler
Delaying for 5 seconds...
NaT bits        0000000000000000
pr              fffffffffffe598d
b0              e000000004417810 ia64_pal_call_static+0x70/0xa0
ar.rsc          0000000000000003
cr.iip          e00000003ff5eec2 0xe00000003ff5eec2
cr.ipsr         0000141008020038
cr.ifs          8000000000003060
xip             e000000004417820 ia64_pal_call_static+0x80/0xa0
xpsr            0000101008026038
xfs             8000000000003060
b1              80000000ffee0000 0x80000000ffee0000

static registers r0-r15:
 r0- 3 0000000000000000 e00000000502ab10 e000000004b2fe50 0000000000000001
 r4- 7 0000000000000000 0000000000000000 0000000000000000 80000000fed00000
 r8-11 fffffffffffffffe 0000000000000000 0000000000000000 0000000000000000
r11-15 e000000004b2fdb0 e000000004b28000 00000000000006c2 00020c1000002f0f

bank 0:
r16-19 e000000004b29320 0000000000000308 0000000000000000 0000000000000000
r20-23 e00000000502ab10 e000000004402f80 e00000003d148f30 0000000000000000
r24-27 0000000000000000 0000000000000000 0000000000000188 0000000000000003
r28-31 e000000004417820 0000101008026038 8000000000003060 fffffffffffe510d

bank 1:
r16-19 02800000ff440000 fffffffffffe518d 000000001f000604 0000001008022038
r20-23 0000000000000588 0000001400000000 0000001008022038 0000000000000000
r24-27 0000001008020000 0000001008020000 0bad0bad0bad0bad e000000004b290d0
r28-31 000000000000001d 0000000000000000 0000000000000000 0000000000000000

Call Trace:
 [<e000000004417820>] ia64_pal_call_static+0x80/0xa0
                spà00000004b2fdb0 bspà00000004b29018
 [<e000000004425990>] default_idle+0x90/0x100
                spà00000004b2fdb0 bspà00000004b29000
 [<e000000004425b00>] cpu_idle+0x100/0x180
                spà00000004b2fe50 bspà00000004b28f88
 [<e000000004aecea0>] 0xe000000004aecea0
                spà00000004b2fe50 bspà00000004b28f30
 [<e000000004408200>] _start+0x200/0x220
                spà00000004b2fe60 bspà00000004b28f30

INIT dump complete.  Please reboot now.

---
=== arch/ia64/kernel/mca.c 1.23 vs edited ==--- 1.23/arch/ia64/kernel/mca.c	Fri Apr 11 18:18:35 2003
+++ edited/arch/ia64/kernel/mca.c	Tue Apr 15 12:20:54 2003
@@ -239,17 +239,91 @@
 	       minstate->pmsa_bank1_gr[14], minstate->pmsa_bank1_gr[15]);
 }
 
-/*
- * This routine will be used to deal with platform specific handling
- * of the init, i.e. drop into the kernel debugger on server machine,
- * or if the processor is part of some parallel machine without a
- * console, then we would call the appropriate debug hooks here.
- */
-unsigned long tr_val[32], tr_idx;
-
-void
-init_handler_platform (sal_log_processor_info_t *proc_ptr, struct pt_regs *regs)
+static void
+fetch_min_state (pal_min_state_area_t *ms, struct pt_regs *pt, struct switch_stack *sw)
 {
+	u64 *dst_banked, *src_banked, bit, shift, nat_bits;
+	int i;
+
+	/*
+	 * First, update the pt-regs and switch-stack structures with the contents stored
+	 * in the min-state area:
+	 */
+	if (((struct ia64_psr *) &ms->pmsa_ipsr)->ic = 0) {
+		pt->cr_ipsr = ms->pmsa_xpsr;
+		pt->cr_iip = ms->pmsa_xip;
+		pt->cr_ifs = ms->pmsa_xfs;
+	} else {
+		pt->cr_ipsr = ms->pmsa_ipsr;
+		pt->cr_iip = ms->pmsa_iip;
+		pt->cr_ifs = ms->pmsa_ifs;
+	}
+	pt->ar_rsc = ms->pmsa_rsc;
+	pt->pr = ms->pmsa_pr;
+	pt->r1 = ms->pmsa_gr[0];
+	pt->r2 = ms->pmsa_gr[1];
+	pt->r3 = ms->pmsa_gr[2];
+	sw->r4 = ms->pmsa_gr[3];
+	sw->r5 = ms->pmsa_gr[4];
+	sw->r6 = ms->pmsa_gr[5];
+	sw->r7 = ms->pmsa_gr[6];
+	pt->r8 = ms->pmsa_gr[7];
+	pt->r9 = ms->pmsa_gr[8];
+	pt->r10 = ms->pmsa_gr[9];
+	pt->r11 = ms->pmsa_gr[10];
+	pt->r12 = ms->pmsa_gr[11];
+	pt->r13 = ms->pmsa_gr[12];
+	pt->r14 = ms->pmsa_gr[13];
+	pt->r15 = ms->pmsa_gr[14];
+	dst_banked = &pt->r16;		/* r16-r31 are contiguous in struct pt_regs */
+	src_banked = ms->pmsa_bank1_gr;
+	for (i = 0; i < 16; ++i)
+		*dst_banked = *src_banked;
+	pt->b0 = ms->pmsa_br0;
+	sw->b1 = ms->pmsa_br1;
+
+	/* construct the NaT bits for the pt-regs structure: */
+#	define PUT_NAT_BIT(dst, addr)					\
+	do {								\
+		bit = nat_bits & 1; nat_bits >>= 1;			\
+		shift = ((unsigned long) addr >> 3) & 0x3f;		\
+		dst = ((dst) & ~(1UL << shift)) | (bit << shift);	\
+	} while (0)
+
+	/* Rotate the saved NaT bits such that bit 0 corresponds to pmsa_gr[0]: */
+	shift = ((unsigned long) &ms->pmsa_gr[0] >> 3) & 0x3f;
+	nat_bits = (ms->pmsa_nat_bits >> shift) | (ms->pmsa_nat_bits << (64 - shift));
+
+	PUT_NAT_BIT(sw->caller_unat, &pt->r1);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r2);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r3);
+	PUT_NAT_BIT(sw->ar_unat, &sw->r4);
+	PUT_NAT_BIT(sw->ar_unat, &sw->r5);
+	PUT_NAT_BIT(sw->ar_unat, &sw->r6);
+	PUT_NAT_BIT(sw->ar_unat, &sw->r7);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r8);	PUT_NAT_BIT(sw->caller_unat, &pt->r9);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r10);	PUT_NAT_BIT(sw->caller_unat, &pt->r11);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r12);	PUT_NAT_BIT(sw->caller_unat, &pt->r13);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r14);	PUT_NAT_BIT(sw->caller_unat, &pt->r15);
+	nat_bits >>= 16;	/* skip over bank0 NaT bits */
+	PUT_NAT_BIT(sw->caller_unat, &pt->r16);	PUT_NAT_BIT(sw->caller_unat, &pt->r17);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r18);	PUT_NAT_BIT(sw->caller_unat, &pt->r19);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r20);	PUT_NAT_BIT(sw->caller_unat, &pt->r21);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r22);	PUT_NAT_BIT(sw->caller_unat, &pt->r23);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r24);	PUT_NAT_BIT(sw->caller_unat, &pt->r25);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r26);	PUT_NAT_BIT(sw->caller_unat, &pt->r27);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r28);	PUT_NAT_BIT(sw->caller_unat, &pt->r29);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r30);	PUT_NAT_BIT(sw->caller_unat, &pt->r31);
+}
+
+void
+init_handler_platform (sal_log_processor_info_t *proc_ptr,
+		       struct pt_regs *pt, struct switch_stack *sw)
+{
+	unsigned long ip, sp, bsp;
+	struct unw_frame_info info;
+	char buf[80];
+
 	/* if a kernel debugger is available call it here else just dump the registers */
 
 	/*
@@ -262,6 +336,23 @@
 	udelay(5*1000000);
 	show_min_state(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area);
 
+	fetch_min_state(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area, pt, sw);
+
+	printk("\nCall Trace:\n");
+	unw_init_from_interruption(&info, current, pt, sw);
+	do {
+		unw_get_ip(&info, &ip);
+		if (ip = 0)
+			break;
+
+		unw_get_sp(&info, &sp);
+		unw_get_bsp(&info, &bsp);
+		snprintf(buf, sizeof(buf), " [<%016lx>] %%s\n\t\tsp=%016lx bsp=%016lx\n",
+			 ip, sp, bsp);
+		print_symbol(buf, ip);
+	} while (unw_unwind(&info) >= 0);
+
+	printk("\nINIT dump complete.  Please reboot now.\n");
 	while (1);			/* hang city if no debugger */
 }
 
@@ -1133,7 +1224,7 @@
  *
  */
 void
-ia64_init_handler (struct pt_regs *regs)
+ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw)
 {
 	sal_log_processor_info_t *proc_ptr;
 	ia64_err_rec_t *plog_ptr;
@@ -1160,7 +1251,7 @@
 	/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
 	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT);
 
-	init_handler_platform(proc_ptr, regs);		/* call platform specific routines */
+	init_handler_platform(proc_ptr, pt, sw);	/* call platform specific routines */
 }
 
 /*
@@ -2210,7 +2301,8 @@
 	switch(sal_info_type) {
 	      case SAL_INFO_TYPE_MCA:
 		prfunc("+BEGIN HARDWARE ERROR STATE AT MCA\n");
-		platform_err = ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
+		platform_err = ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type),
+							    prfunc);
 		prfunc("+END HARDWARE ERROR STATE AT MCA\n");
 		break;
 	      case SAL_INFO_TYPE_INIT:
=== arch/ia64/kernel/mca_asm.S 1.7 vs edited ==--- 1.7/arch/ia64/kernel/mca_asm.S	Fri Apr 11 18:18:35 2003
+++ edited/arch/ia64/kernel/mca_asm.S	Mon Apr 14 13:51:58 2003
@@ -796,10 +796,12 @@
 	//
 	// Let's call the C handler to get the rest of the state info
 	//
-	alloc r14=ar.pfs,0,0,1,0		// now it's safe (must be first in insn group!)
-	;;					//
+	alloc r14=ar.pfs,0,0,2,0		// now it's safe (must be first in insn group!)
+	;;
 	adds out0\x16,sp				// out0 = pointer to pt_regs
 	;;
+	DO_SAVE_SWITCH_STACK
+	adds out1\x16,sp				// out0 = pointer to switch_stack
 
 	br.call.sptk.many rp=ia64_init_handler
 .ret1:
=== arch/ia64/kernel/process.c 1.31 vs edited ==--- 1.31/arch/ia64/kernel/process.c	Fri Apr 11 18:18:35 2003
+++ edited/arch/ia64/kernel/process.c	Tue Apr 15 11:58:36 2003
@@ -57,7 +57,7 @@
 
 		unw_get_sp(info, &sp);
 		unw_get_bsp(info, &bsp);
-		snprintf(buf, sizeof(buf), " [<%016lx>] %%s sp=0x%016lx bsp=0x%016lx\n",
+		snprintf(buf, sizeof(buf), " [<%016lx>] %%s\n\t\tsp=%016lx bsp=%016lx\n",
 			 ip, sp, bsp);
 		print_symbol(buf, ip);
 	} while (unw_unwind(info) >= 0);
=== arch/ia64/kernel/unwind.c 1.19 vs edited ==--- 1.19/arch/ia64/kernel/unwind.c	Tue Mar 25 04:49:15 2003
+++ edited/arch/ia64/kernel/unwind.c	Tue Apr 15 11:40:31 2003
@@ -1888,22 +1888,21 @@
 	return -1;
 }
 
-void
-unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw)
+static void
+init_frame_info (struct unw_frame_info *info, struct task_struct *t,
+		 struct switch_stack *sw, unsigned long stktop)
 {
-	unsigned long rbslimit, rbstop, stklimit, stktop, sol;
+	unsigned long rbslimit, rbstop, stklimit;
 	STAT(unsigned long start, flags;)
 
 	STAT(local_irq_save(flags); ++unw.stat.api.inits; start = ia64_get_itc());
 
 	/*
-	 * Subtle stuff here: we _could_ unwind through the
-	 * switch_stack frame but we don't want to do that because it
-	 * would be slow as each preserved register would have to be
-	 * processed.  Instead, what we do here is zero out the frame
-	 * info and start the unwind process at the function that
-	 * created the switch_stack frame.  When a preserved value in
-	 * switch_stack needs to be accessed, run_script() will
+	 * Subtle stuff here: we _could_ unwind through the switch_stack frame but we
+	 * don't want to do that because it would be slow as each preserved register would
+	 * have to be processed.  Instead, what we do here is zero out the frame info and
+	 * start the unwind process at the function that created the switch_stack frame.
+	 * When a preserved value in switch_stack needs to be accessed, run_script() will
 	 * initialize the appropriate pointer on demand.
 	 */
 	memset(info, 0, sizeof(*info));
@@ -1914,7 +1913,6 @@
 		rbstop = rbslimit;
 
 	stklimit = (unsigned long) t + IA64_STK_OFFSET;
-	stktop   = (unsigned long) sw - 16;
 	if (stktop <= rbstop)
 		stktop = rbstop;
 
@@ -1924,34 +1922,56 @@
 	info->memstk.top   = stktop;
 	info->task = t;
 	info->sw  = sw;
-	info->sp = info->psp = (unsigned long) (sw + 1) - 16;
-	info->pt = 0;
+	info->sp = info->psp = stktop;
+	info->pr = sw->pr;
+	UNW_DPRINT(3, "unwind.%s:\n"
+		   "  task   0x%lx\n"
+		   "  rbs = [0x%lx-0x%lx)\n"
+		   "  stk = [0x%lx-0x%lx)\n"
+		   "  pr     0x%lx\n"
+		   "  sw     0x%lx\n"
+		   "  sp     0x%lx\n",
+		   __FUNCTION__, (unsigned long) task, rbslimit, rbstop, stktop, stklimit,
+		   info->pr, (unsigned long) info->sw, info->sp);
+	STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
+}
+
+void
+unw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t,
+			    struct pt_regs *pt, struct switch_stack *sw)
+{
+	unsigned long sof;
+
+	init_frame_info(info, t, sw, pt->r12);
+	info->cfm_loc = &pt->cr_ifs;
+	sof = *info->cfm_loc & 0x7f;
+	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sof);
+	info->ip = pt->cr_iip + ia64_psr(pt)->ri;
+	info->pt = (unsigned long) pt;
+	UNW_DPRINT(3, "unwind.%s:\n"
+		   "  bsp    0x%lx\n"
+		   "  sof    0x%lx\n"
+		   "  ip     0x%lx\n",
+		   info->bsp, sof, info->ip);
+	find_save_locs(info);
+}
+
+void
+unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw)
+{
+	unsigned long sol;
+
+	init_frame_info(info, t, sw, (unsigned long) (sw + 1) - 16);
 	info->cfm_loc = &sw->ar_pfs;
 	sol = (*info->cfm_loc >> 7) & 0x7f;
 	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);
 	info->ip = sw->b0;
-	info->pr = sw->pr;
-	UNW_DPRINT(3,
-			"unwind.%s\n"
-			"  rbslimit 0x%lx\n"
-			"  rbstop   0x%lx\n"
-			"  stklimit 0x%lx\n"
-			"  stktop   0x%lx\n"
-			"  task     0x%lx\n"
-			"  sw       0x%lx\n",
-			__FUNCTION__, rbslimit, rbstop, stklimit, stktop,
-			(unsigned long)(info->task),
-			(unsigned long)(info->sw));
-	UNW_DPRINT(3,
-			"  sp/psp   0x%lx\n"
-			"  sol      0x%lx\n"
-			"  bsp      0x%lx\n"
-			"  ip       0x%lx\n"
-			"  pr       0x%lx\n",
-			info->sp, sol, info->bsp, info->ip, info->pr);
-
+	UNW_DPRINT(3, "unwind.%s:\n"
+		   "  bsp    0x%lx\n"
+		   "  sol    0x%lx\n"
+		   "  ip     0x%lx\n",
+		   info->bsp, sol, info->ip);
 	find_save_locs(info);
-	STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
 }
 
 void
=== include/asm-ia64/unwind.h 1.4 vs edited ==--- 1.4/include/asm-ia64/unwind.h	Mon Mar  3 16:00:00 2003
+++ edited/include/asm-ia64/unwind.h	Tue Apr 15 11:12:37 2003
@@ -2,8 +2,8 @@
 #define _ASM_IA64_UNWIND_H
 
 /*
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2000, 2003 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * A simple API for unwinding kernel stacks.  This is used for
  * debugging and error reporting purposes.  The kernel doesn't need
@@ -106,6 +106,13 @@
  * Prepare to unwind blocked task t.
  */
 extern void unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t);
+
+/*
+ * Prepare to unwind from interruption.  The pt-regs and switch-stack structures must have
+ * be "adjacent" (no state modifications between pt-regs and switch-stack).
+ */
+extern void unw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t,
+					struct pt_regs *pt, struct switch_stack *sw);
 
 extern void unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t,
 				 struct switch_stack *sw);


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2003-04-21 17:21 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-04-15 20:24 [Linux-ia64] print backtrace from OS INIT handler David Mosberger
2003-04-21 17:21 ` Bjorn Helgaas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox