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