Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | /*
* Copyright (C) 2003, Axis Communications AB.
*/
#include <linux/config.h>
#include <linux/ptrace.h>
#include <asm/uaccess.h>
#include <asm/arch/hwregs/supp_reg.h>
extern void reset_watchdog(void);
extern void stop_watchdog(void);
extern int raw_printk(const char *fmt, ...);
void
show_registers(struct pt_regs *regs)
{
/*
* It's possible to use either the USP register or current->thread.usp.
* USP might not correspond to the current proccess for all cases this
* function is called, and current->thread.usp isn't up to date for the
* current proccess. Experience shows that using USP is the way to go.
*/
unsigned long usp;
unsigned long d_mmu_cause;
unsigned long i_mmu_cause;
usp = rdusp();
raw_printk("CPU: %d\n", smp_processor_id());
raw_printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n",
regs->erp, regs->srp, regs->ccs, usp, regs->mof);
raw_printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
regs->r0, regs->r1, regs->r2, regs->r3);
raw_printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
regs->r4, regs->r5, regs->r6, regs->r7);
raw_printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
regs->r8, regs->r9, regs->r10, regs->r11);
raw_printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n",
regs->r12, regs->r13, regs->orig_r10, regs->acr);
raw_printk("sp: %08lx\n", regs);
SUPP_BANK_SEL(BANK_IM);
SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause);
SUPP_BANK_SEL(BANK_DM);
SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause);
raw_printk(" Data MMU Cause: %08lx\n", d_mmu_cause);
raw_printk("Instruction MMU Cause: %08lx\n", i_mmu_cause);
raw_printk("Process %s (pid: %d, stackpage: %08lx)\n",
current->comm, current->pid, (unsigned long) current);
/* Show additional info if in kernel-mode. */
if (!user_mode(regs)) {
int i;
unsigned char c;
show_stack(NULL, (unsigned long *) usp);
/*
* If the previous stack-dump wasn't a kernel one, dump the
* kernel stack now.
*/
if (usp != 0)
show_stack(NULL, NULL);
raw_printk("\nCode: ");
if (regs->erp < PAGE_OFFSET)
goto bad_value;
/*
* Quite often the value at regs->erp doesn't point to the
* interesting instruction, which often is the previous
* instruction. So dump at an offset large enough that the
* instruction decoding should be in sync at the interesting
* point, but small enough to fit on a row. The regs->erp
* location is pointed out in a ksymoops-friendly way by
* wrapping the byte for that address in parenthesis.
*/
for (i = -12; i < 12; i++) {
if (__get_user(c, &((unsigned char *) regs->erp)[i])) {
bad_value:
raw_printk(" Bad IP value.");
break;
}
if (i == 0)
raw_printk("(%02x) ", c);
else
raw_printk("%02x ", c);
}
raw_printk("\n");
}
}
/*
* This gets called from entry.S when the watchdog has bitten. Show something
* similiar to an Oops dump, and if the kernel if configured to be a nice doggy;
* halt instead of reboot.
*/
void
watchdog_bite_hook(struct pt_regs *regs)
{
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
local_irq_disable();
stop_watchdog();
show_registers(regs);
while (1)
; /* Do nothing. */
#else
show_registers(regs);
#endif
}
/* This is normally the Oops function. */
void
die_if_kernel(const char *str, struct pt_regs *regs, long err)
{
if (user_mode(regs))
return;
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
/*
* This printout might take too long and could trigger
* the watchdog normally. If NICE_DOGGY is set, simply
* stop the watchdog during the printout.
*/
stop_watchdog();
#endif
raw_printk("%s: %04lx\n", str, err & 0xffff);
show_registers(regs);
#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY
reset_watchdog();
#endif
do_exit(SIGSEGV);
}
void arch_enable_nmi(void)
{
unsigned long flags;
local_save_flags(flags);
flags |= (1<<30); /* NMI M flag is at bit 30 */
local_irq_restore(flags);
}
|