- Revision
- 6941
- Author
- rgetz
- Date
- 2009-07-07 15:17:09 -0500 (Tue, 07 Jul 2009)
Log Message
Allow hardware errors to be caught during early portions of booting, and
leave something in the shadow console that people can use to debug their
system with. (to be printed out by the bootloader on next reset).
This enables the hardare error interrupts in head.S, allowing us to
find hardware errors when they happen (well, as much as you can with a
hardware error) and prints out the trace if it is enabled. This will
catch errors (like booting the wrong image on a 533) which previously
resulted in a infinite loop/hang, as well as random hardware errors
before setup_arch().
To disable this debug only feature - turn off EARLY_PRINTK.
Modified Paths
Diff
Modified: trunk/arch/blackfin/include/asm/early_printk.h (6940 => 6941)
--- trunk/arch/blackfin/include/asm/early_printk.h 2009-07-07 09:33:38 UTC (rev 6940)
+++ trunk/arch/blackfin/include/asm/early_printk.h 2009-07-07 20:17:09 UTC (rev 6941)
@@ -24,6 +24,12 @@
#ifdef CONFIG_EARLY_PRINTK
extern int setup_early_printk(char *);
extern void enable_shadow_console(void);
+extern int shadow_console_enabled(void);
+extern void mark_shadow_error(void);
+extern void early_shadow_reg(unsigned long reg, unsigned int n);
+extern void early_shadow_write(struct console *con, const char *s,
+ unsigned int n) __attribute__((nonnull(2)));
+#define early_shadow_puts(str) early_shadow_write(NULL, str, strlen(str))
#else
#define setup_early_printk(fmt) do { } while (0)
#define enable_shadow_console(fmt) do { } while (0)
Modified: trunk/arch/blackfin/kernel/early_printk.c (6940 => 6941)
--- trunk/arch/blackfin/kernel/early_printk.c 2009-07-07 09:33:38 UTC (rev 6940)
+++ trunk/arch/blackfin/kernel/early_printk.c 2009-07-07 20:17:09 UTC (rev 6941)
@@ -27,6 +27,7 @@
#include <linux/serial_core.h>
#include <linux/console.h>
#include <linux/string.h>
+#include <linux/reboot.h>
#include <asm/blackfin.h>
#include <asm/irq_handler.h>
#include <asm/early_printk.h>
@@ -199,6 +200,7 @@
}
+__attribute__((__noreturn__))
asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
{
/* This can happen before the uart is initialized, so initialize
@@ -210,11 +212,69 @@
if (likely(early_console == NULL) && CPUID == bfin_cpuid())
setup_early_printk(DEFAULT_EARLY_PORT);
- printk(KERN_EMERG "Early panic\n");
- dump_bfin_mem(fp);
- show_regs(fp);
- dump_bfin_trace_buffer();
+ if (!shadow_console_enabled()) {
+ /* crap - we crashed before setup_arch() */
+ mark_shadow_error();
+ early_shadow_puts(linux_banner);
+ early_shadow_puts("panic before setup_arch\n");
+ if (CPUID != bfin_cpuid()) {
+ early_shadow_puts("Running on wrong machine type, "
+ "expected");
+ early_shadow_reg(CPUID, 16);
+ early_shadow_puts(", but running on");
+ early_shadow_reg(bfin_cpuid(), 16);
+ early_shadow_puts("\n");
+ }
+ early_shadow_puts("IPEND:");
+ early_shadow_reg(fp->ipend, 16);
+ if (fp->seqstat & SEQSTAT_EXCAUSE) {
+ early_shadow_puts("\nEXCAUSE:");
+ early_shadow_reg(fp->seqstat & SEQSTAT_EXCAUSE, 8);
+ }
+ if (fp->seqstat & SEQSTAT_HWERRCAUSE) {
+ early_shadow_puts("\nHWERRCAUSE:");
+ early_shadow_reg(
+ (fp->seqstat & SEQSTAT_HWERRCAUSE) >> 14, 8);
+ }
+ early_shadow_puts("\nErr @");
+ if (fp->ipend & EVT_EVX)
+ early_shadow_reg(fp->retx, 32);
+ else
+ early_shadow_reg(fp->pc, 32);
+#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
+ early_shadow_puts("\nTrace:");
+ if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
+ while (bfin_read_TBUFSTAT() & TBUFCNT) {
+ early_shadow_puts("\nT :");
+ early_shadow_reg(bfin_read_TBUF(), 32);
+ early_shadow_puts("\n S :");
+ early_shadow_reg(bfin_read_TBUF(), 32);
+ }
+ }
+#endif
+ early_shadow_puts("\nUse bfin-elf-addr2line to determine "
+ "function names\n");
+ /*
+ * We should panic(), but we can't - since panic calls printk,
+ * and printk uses memcpy.
+ * we want to reboot, but if the machine type is different,
+ * can't due to machine specific reboot sequences
+ */
+ if (CPUID == bfin_cpuid()) {
+ early_shadow_puts("Trying to restart\n");
+ machine_restart("");
+ }
+ early_shadow_puts("Halting, since it is not safe to restart\n");
+ while (1)
+ asm volatile ("EMUEXCPT; IDLE;\n");
+
+ } else {
+ printk(KERN_EMERG "Early panic\n");
+ show_regs(fp);
+ dump_bfin_trace_buffer();
+ }
+
panic("Died early");
}
Modified: trunk/arch/blackfin/kernel/shadow_console.c (6940 => 6941)
--- trunk/arch/blackfin/kernel/shadow_console.c 2009-07-07 09:33:38 UTC (rev 6940)
+++ trunk/arch/blackfin/kernel/shadow_console.c 2009-07-07 20:17:09 UTC (rev 6941)
@@ -36,15 +36,18 @@
static __initdata char *shadow_console_buffer = (char *)SHADOW_CONSOLE_START;
-static __init void early_shadow_write(struct console *con, const char *s,
+__init void early_shadow_write(struct console *con, const char *s,
unsigned int n)
{
+ unsigned int i;
/*
* save 2 bytes for the double null at the end
* once we fail on a long line, make sure we don't write a short line afterwards
*/
if ((shadow_console_buffer + n) <= (char *)(SHADOW_CONSOLE_END - 2)) {
- memcpy(shadow_console_buffer, s, n);
+ /* can't use memcpy - it may not be relocated yet */
+ for (i = 0; i <= n; i++)
+ shadow_console_buffer[i] = s[i];
shadow_console_buffer += n;
shadow_console_buffer[0] = 0;
shadow_console_buffer[1] = 0;
@@ -60,16 +63,24 @@
.device = 0,
};
-__init void enable_shadow_console(void)
+__init int shadow_console_enabled(void)
{
+ return early_shadow_console.flags & CON_ENABLED;
+}
+
+__init void mark_shadow_error(void)
+{
int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC;
+ loc[0] = SHADOW_CONSOLE_MAGIC;
+ loc[1] = SHADOW_CONSOLE_START;
+}
- if (!(early_shadow_console.flags & CON_ENABLED)) {
+__init void enable_shadow_console(void)
+{
+ if (!shadow_console_enabled()) {
register_console(&early_shadow_console);
/* for now, assume things are going to fail */
- *loc = SHADOW_CONSOLE_MAGIC;
- loc++;
- *loc = SHADOW_CONSOLE_START;
+ mark_shadow_error();
}
}
@@ -83,8 +94,32 @@
*/
int *loc = (int *)SHADOW_CONSOLE_MAGIC_LOC;
- *loc = 0;
+ loc[0] = 0;
return 0;
}
pure_initcall(disable_shadow_console);
+
+/*
+ * since we can't use printk, dump numbers (as hex), n = # bits
+ */
+__init void early_shadow_reg(unsigned long reg, unsigned int n)
+{
+ /*
+ * can't use any "normal" kernel features, since thay
+ * may not be relocated to their execute address yet
+ */
+ int i;
+ char ascii[11] = " 0x";
+
+ n = n / 4;
+ reg = reg << ((8 - n) * 4);
+ n += 3;
+
+ for (i = 3; i <= n ; i++) {
+ ascii[i] = hex_asc_lo(reg >> 28);
+ reg <<= 4;
+ }
+ early_shadow_write(NULL, ascii, n);
+
+}
Modified: trunk/arch/blackfin/mach-common/head.S (6940 => 6941)
--- trunk/arch/blackfin/mach-common/head.S 2009-07-07 09:33:38 UTC (rev 6940)
+++ trunk/arch/blackfin/mach-common/head.S 2009-07-07 20:17:09 UTC (rev 6941)
@@ -153,6 +153,8 @@
#ifdef CONFIG_EARLY_PRINTK
call _init_early_exception_vectors;
+ r0 = (EVT_IVHW | EVT_IRPTEN | EVT_EVX | EVT_NMI | EVT_RST | EVT_EMU);
+ sti r0;
#endif
r0 = 0 (x);