]>
Commit | Line | Data |
---|---|---|
51533b61 | 1 | /* |
9ce1ea75 | 2 | * Copyright (C) 2003-2006, Axis Communications AB. |
51533b61 MS |
3 | */ |
4 | ||
51533b61 | 5 | #include <linux/ptrace.h> |
9ce1ea75 | 6 | #include <linux/module.h> |
7c0f6ba6 | 7 | #include <linux/uaccess.h> |
9ce1ea75 JN |
8 | #include <hwregs/supp_reg.h> |
9 | #include <hwregs/intr_vect_defs.h> | |
10 | #include <asm/irq.h> | |
51533b61 | 11 | |
e2ee9bb2 | 12 | void show_registers(struct pt_regs *regs) |
51533b61 MS |
13 | { |
14 | /* | |
15 | * It's possible to use either the USP register or current->thread.usp. | |
9ce1ea75 | 16 | * USP might not correspond to the current process for all cases this |
51533b61 | 17 | * function is called, and current->thread.usp isn't up to date for the |
9ce1ea75 | 18 | * current process. Experience shows that using USP is the way to go. |
51533b61 | 19 | */ |
9ce1ea75 | 20 | unsigned long usp = rdusp(); |
51533b61 MS |
21 | unsigned long d_mmu_cause; |
22 | unsigned long i_mmu_cause; | |
23 | ||
9ce1ea75 | 24 | printk("CPU: %d\n", smp_processor_id()); |
51533b61 | 25 | |
9ce1ea75 JN |
26 | printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n", |
27 | regs->erp, regs->srp, regs->ccs, usp, regs->mof); | |
51533b61 | 28 | |
9ce1ea75 JN |
29 | printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", |
30 | regs->r0, regs->r1, regs->r2, regs->r3); | |
51533b61 | 31 | |
9ce1ea75 JN |
32 | printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", |
33 | regs->r4, regs->r5, regs->r6, regs->r7); | |
51533b61 | 34 | |
9ce1ea75 JN |
35 | printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", |
36 | regs->r8, regs->r9, regs->r10, regs->r11); | |
51533b61 | 37 | |
9ce1ea75 JN |
38 | printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n", |
39 | regs->r12, regs->r13, regs->orig_r10, regs->acr); | |
51533b61 | 40 | |
9ce1ea75 | 41 | printk(" sp: %08lx\n", (unsigned long)regs); |
51533b61 MS |
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 | ||
9ce1ea75 JN |
49 | printk(" Data MMU Cause: %08lx\n", d_mmu_cause); |
50 | printk("Instruction MMU Cause: %08lx\n", i_mmu_cause); | |
51533b61 | 51 | |
9ce1ea75 JN |
52 | printk("Process %s (pid: %d, stackpage=%08lx)\n", |
53 | current->comm, current->pid, (unsigned long)current); | |
51533b61 | 54 | |
9ce1ea75 JN |
55 | /* |
56 | * When in-kernel, we also print out the stack and code at the | |
57 | * time of the fault.. | |
58 | */ | |
51533b61 MS |
59 | if (!user_mode(regs)) { |
60 | int i; | |
51533b61 | 61 | |
9ce1ea75 | 62 | show_stack(NULL, (unsigned long *)usp); |
51533b61 MS |
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 | ||
9ce1ea75 | 71 | printk("\nCode: "); |
51533b61 MS |
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 | |
9ce1ea75 | 83 | * wrapping the byte for that address in parenthesises. |
51533b61 MS |
84 | */ |
85 | for (i = -12; i < 12; i++) { | |
9ce1ea75 JN |
86 | unsigned char c; |
87 | ||
88 | if (__get_user(c, &((unsigned char *)regs->erp)[i])) { | |
51533b61 | 89 | bad_value: |
9ce1ea75 | 90 | printk(" Bad IP value."); |
51533b61 MS |
91 | break; |
92 | } | |
93 | ||
94 | if (i == 0) | |
9ce1ea75 | 95 | printk("(%02x) ", c); |
51533b61 | 96 | else |
9ce1ea75 | 97 | printk("%02x ", c); |
51533b61 | 98 | } |
9ce1ea75 | 99 | printk("\n"); |
51533b61 MS |
100 | } |
101 | } | |
102 | ||
e2ee9bb2 | 103 | void arch_enable_nmi(void) |
51533b61 | 104 | { |
9ce1ea75 | 105 | unsigned long flags; |
51533b61 | 106 | |
9ce1ea75 JN |
107 | local_save_flags(flags); |
108 | flags |= (1 << 30); /* NMI M flag is at bit 30 */ | |
109 | local_irq_restore(flags); | |
51533b61 MS |
110 | } |
111 | ||
9ce1ea75 JN |
112 | extern void (*nmi_handler)(struct pt_regs *); |
113 | void handle_nmi(struct pt_regs *regs) | |
51533b61 | 114 | { |
9ce1ea75 JN |
115 | #ifdef CONFIG_ETRAXFS |
116 | reg_intr_vect_r_nmi r; | |
117 | #endif | |
51533b61 | 118 | |
9ce1ea75 JN |
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); | |
51533b61 | 127 | #endif |
9ce1ea75 | 128 | } |
51533b61 | 129 | |
51533b61 | 130 | |
9ce1ea75 JN |
131 | #ifdef CONFIG_BUG |
132 | extern void die_if_kernel(const char *str, struct pt_regs *regs, long err); | |
51533b61 | 133 | |
9ce1ea75 JN |
134 | /* Copy of the regs at BUG() time. */ |
135 | struct pt_regs BUG_regs; | |
51533b61 | 136 | |
9ce1ea75 JN |
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); | |
51533b61 | 141 | } |
9ce1ea75 | 142 | EXPORT_SYMBOL(do_BUG); |
51533b61 | 143 | |
9ce1ea75 | 144 | void fixup_BUG(struct pt_regs *regs) |
51533b61 | 145 | { |
9ce1ea75 JN |
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 | |
51533b61 | 170 | } |
9ce1ea75 JN |
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 |