Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 1 | /* |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 2 | * Copyright (C) 2003-2006, Axis Communications AB. |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 3 | */ |
| 4 | |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 5 | #include <linux/ptrace.h> |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 6 | #include <linux/module.h> |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 7 | #include <asm/uaccess.h> |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 8 | #include <hwregs/supp_reg.h> |
| 9 | #include <hwregs/intr_vect_defs.h> |
| 10 | #include <asm/irq.h> |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 11 | |
Jesper Nilsson | e2ee9bb | 2010-08-03 15:59:26 +0200 | [diff] [blame] | 12 | void show_registers(struct pt_regs *regs) |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 13 | { |
| 14 | /* |
| 15 | * It's possible to use either the USP register or current->thread.usp. |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 16 | * USP might not correspond to the current process for all cases this |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 17 | * function is called, and current->thread.usp isn't up to date for the |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 18 | * current process. Experience shows that using USP is the way to go. |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 19 | */ |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 20 | unsigned long usp = rdusp(); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 21 | unsigned long d_mmu_cause; |
| 22 | unsigned long i_mmu_cause; |
| 23 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 24 | printk("CPU: %d\n", smp_processor_id()); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 25 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 26 | printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n", |
| 27 | regs->erp, regs->srp, regs->ccs, usp, regs->mof); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 28 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 29 | printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", |
| 30 | regs->r0, regs->r1, regs->r2, regs->r3); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 31 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 32 | printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", |
| 33 | regs->r4, regs->r5, regs->r6, regs->r7); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 34 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 35 | printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", |
| 36 | regs->r8, regs->r9, regs->r10, regs->r11); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 37 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 38 | printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n", |
| 39 | regs->r12, regs->r13, regs->orig_r10, regs->acr); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 40 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 41 | printk(" sp: %08lx\n", (unsigned long)regs); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 42 | |
| 43 | SUPP_BANK_SEL(BANK_IM); |
| 44 | SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause); |
| 45 | |
| 46 | SUPP_BANK_SEL(BANK_DM); |
| 47 | SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause); |
| 48 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 49 | printk(" Data MMU Cause: %08lx\n", d_mmu_cause); |
| 50 | printk("Instruction MMU Cause: %08lx\n", i_mmu_cause); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 51 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 52 | printk("Process %s (pid: %d, stackpage=%08lx)\n", |
| 53 | current->comm, current->pid, (unsigned long)current); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 54 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 55 | /* |
| 56 | * When in-kernel, we also print out the stack and code at the |
| 57 | * time of the fault.. |
| 58 | */ |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 59 | if (!user_mode(regs)) { |
| 60 | int i; |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 61 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 62 | show_stack(NULL, (unsigned long *)usp); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 63 | |
| 64 | /* |
| 65 | * If the previous stack-dump wasn't a kernel one, dump the |
| 66 | * kernel stack now. |
| 67 | */ |
| 68 | if (usp != 0) |
| 69 | show_stack(NULL, NULL); |
| 70 | |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 71 | printk("\nCode: "); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 72 | |
| 73 | if (regs->erp < PAGE_OFFSET) |
| 74 | goto bad_value; |
| 75 | |
| 76 | /* |
| 77 | * Quite often the value at regs->erp doesn't point to the |
| 78 | * interesting instruction, which often is the previous |
| 79 | * instruction. So dump at an offset large enough that the |
| 80 | * instruction decoding should be in sync at the interesting |
| 81 | * point, but small enough to fit on a row. The regs->erp |
| 82 | * location is pointed out in a ksymoops-friendly way by |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 83 | * wrapping the byte for that address in parenthesises. |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 84 | */ |
| 85 | for (i = -12; i < 12; i++) { |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 86 | unsigned char c; |
| 87 | |
| 88 | if (__get_user(c, &((unsigned char *)regs->erp)[i])) { |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 89 | bad_value: |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 90 | printk(" Bad IP value."); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 91 | break; |
| 92 | } |
| 93 | |
| 94 | if (i == 0) |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 95 | printk("(%02x) ", c); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 96 | else |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 97 | printk("%02x ", c); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 98 | } |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 99 | printk("\n"); |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 100 | } |
| 101 | } |
| 102 | |
Jesper Nilsson | e2ee9bb | 2010-08-03 15:59:26 +0200 | [diff] [blame] | 103 | void arch_enable_nmi(void) |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 104 | { |
| 105 | unsigned long flags; |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 106 | |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 107 | local_save_flags(flags); |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 108 | flags |= (1 << 30); /* NMI M flag is at bit 30 */ |
Mikael Starvik | 51533b6 | 2005-07-27 11:44:44 -0700 | [diff] [blame] | 109 | local_irq_restore(flags); |
| 110 | } |
Jesper Nilsson | 9ce1ea7 | 2007-12-03 11:12:10 +0100 | [diff] [blame] | 111 | |
| 112 | extern void (*nmi_handler)(struct pt_regs *); |
| 113 | void handle_nmi(struct pt_regs *regs) |
| 114 | { |
| 115 | #ifdef CONFIG_ETRAXFS |
| 116 | reg_intr_vect_r_nmi r; |
| 117 | #endif |
| 118 | |
| 119 | if (nmi_handler) |
| 120 | nmi_handler(regs); |
| 121 | |
| 122 | #ifdef CONFIG_ETRAXFS |
| 123 | /* Wait until nmi is no longer active. */ |
| 124 | do { |
| 125 | r = REG_RD(intr_vect, regi_irq, r_nmi); |
| 126 | } while (r.ext == regk_intr_vect_on); |
| 127 | #endif |
| 128 | } |
| 129 | |
| 130 | |
| 131 | #ifdef CONFIG_BUG |
| 132 | extern void die_if_kernel(const char *str, struct pt_regs *regs, long err); |
| 133 | |
| 134 | /* Copy of the regs at BUG() time. */ |
| 135 | struct pt_regs BUG_regs; |
| 136 | |
| 137 | void do_BUG(char *file, unsigned int line) |
| 138 | { |
| 139 | printk("kernel BUG at %s:%d!\n", file, line); |
| 140 | die_if_kernel("Oops", &BUG_regs, 0); |
| 141 | } |
| 142 | EXPORT_SYMBOL(do_BUG); |
| 143 | |
| 144 | void fixup_BUG(struct pt_regs *regs) |
| 145 | { |
| 146 | BUG_regs = *regs; |
| 147 | |
| 148 | #ifdef CONFIG_DEBUG_BUGVERBOSE |
| 149 | /* |
| 150 | * Fixup the BUG arguments through exception handlers. |
| 151 | */ |
| 152 | { |
| 153 | const struct exception_table_entry *fixup; |
| 154 | |
| 155 | /* |
| 156 | * ERP points at the "break 14" + 2, compensate for the 2 |
| 157 | * bytes. |
| 158 | */ |
| 159 | fixup = search_exception_tables(instruction_pointer(regs) - 2); |
| 160 | if (fixup) { |
| 161 | /* Adjust the instruction pointer in the stackframe. */ |
| 162 | instruction_pointer(regs) = fixup->fixup; |
| 163 | arch_fixup(regs); |
| 164 | } |
| 165 | } |
| 166 | #else |
| 167 | /* Dont try to lookup the filename + line, just dump regs. */ |
| 168 | do_BUG("unknown", 0); |
| 169 | #endif |
| 170 | } |
| 171 | |
| 172 | /* |
| 173 | * Break 14 handler. Save regs and jump into the fixup_BUG. |
| 174 | */ |
| 175 | __asm__ ( ".text\n\t" |
| 176 | ".global breakh_BUG\n\t" |
| 177 | "breakh_BUG:\n\t" |
| 178 | SAVE_ALL |
| 179 | KGDB_FIXUP |
| 180 | "move.d $sp, $r10\n\t" |
| 181 | "jsr fixup_BUG\n\t" |
| 182 | "nop\n\t" |
| 183 | "jump ret_from_intr\n\t" |
| 184 | "nop\n\t"); |
| 185 | |
| 186 | |
| 187 | #ifdef CONFIG_DEBUG_BUGVERBOSE |
| 188 | void |
| 189 | handle_BUG(struct pt_regs *regs) |
| 190 | { |
| 191 | } |
| 192 | #endif |
| 193 | #endif |