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