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