diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-02-09 23:20:34 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-03-20 04:12:07 -0500 |
commit | ed6b0b45437dcf7ef1c48b3be413bebcc84771d8 (patch) | |
tree | e52dbcebe1435f9d2957b55c100824cb7b8b1f98 /arch/sparc64/kernel/traps.c | |
parent | 618e9ed98aed924a1fc664eb6522db4a5e927043 (diff) |
[SPARC64]: SUN4V memory exception trap handlers.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/traps.c')
-rw-r--r-- | arch/sparc64/kernel/traps.c | 108 |
1 files changed, 101 insertions, 7 deletions
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index ac171161e794..1e9a4b6b1fec 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c | |||
@@ -180,6 +180,45 @@ void spitfire_insn_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr | |||
180 | spitfire_insn_access_exception(regs, sfsr, sfar); | 180 | spitfire_insn_access_exception(regs, sfsr, sfar); |
181 | } | 181 | } |
182 | 182 | ||
183 | void sun4v_insn_access_exception(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx) | ||
184 | { | ||
185 | unsigned short type = (type_ctx >> 16); | ||
186 | unsigned short ctx = (type_ctx & 0xffff); | ||
187 | siginfo_t info; | ||
188 | |||
189 | if (notify_die(DIE_TRAP, "instruction access exception", regs, | ||
190 | 0, 0x8, SIGTRAP) == NOTIFY_STOP) | ||
191 | return; | ||
192 | |||
193 | if (regs->tstate & TSTATE_PRIV) { | ||
194 | printk("sun4v_insn_access_exception: ADDR[%016lx] " | ||
195 | "CTX[%04x] TYPE[%04x], going.\n", | ||
196 | addr, ctx, type); | ||
197 | die_if_kernel("Iax", regs); | ||
198 | } | ||
199 | |||
200 | if (test_thread_flag(TIF_32BIT)) { | ||
201 | regs->tpc &= 0xffffffff; | ||
202 | regs->tnpc &= 0xffffffff; | ||
203 | } | ||
204 | info.si_signo = SIGSEGV; | ||
205 | info.si_errno = 0; | ||
206 | info.si_code = SEGV_MAPERR; | ||
207 | info.si_addr = (void __user *) addr; | ||
208 | info.si_trapno = 0; | ||
209 | force_sig_info(SIGSEGV, &info, current); | ||
210 | } | ||
211 | |||
212 | void sun4v_insn_access_exception_tl1(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx) | ||
213 | { | ||
214 | if (notify_die(DIE_TRAP_TL1, "instruction access exception tl1", regs, | ||
215 | 0, 0x8, SIGTRAP) == NOTIFY_STOP) | ||
216 | return; | ||
217 | |||
218 | dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); | ||
219 | sun4v_insn_access_exception(regs, addr, type_ctx); | ||
220 | } | ||
221 | |||
183 | void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) | 222 | void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) |
184 | { | 223 | { |
185 | siginfo_t info; | 224 | siginfo_t info; |
@@ -228,6 +267,45 @@ void spitfire_data_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr | |||
228 | spitfire_data_access_exception(regs, sfsr, sfar); | 267 | spitfire_data_access_exception(regs, sfsr, sfar); |
229 | } | 268 | } |
230 | 269 | ||
270 | void sun4v_data_access_exception(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx) | ||
271 | { | ||
272 | unsigned short type = (type_ctx >> 16); | ||
273 | unsigned short ctx = (type_ctx & 0xffff); | ||
274 | siginfo_t info; | ||
275 | |||
276 | if (notify_die(DIE_TRAP, "data access exception", regs, | ||
277 | 0, 0x8, SIGTRAP) == NOTIFY_STOP) | ||
278 | return; | ||
279 | |||
280 | if (regs->tstate & TSTATE_PRIV) { | ||
281 | printk("sun4v_data_access_exception: ADDR[%016lx] " | ||
282 | "CTX[%04x] TYPE[%04x], going.\n", | ||
283 | addr, ctx, type); | ||
284 | die_if_kernel("Iax", regs); | ||
285 | } | ||
286 | |||
287 | if (test_thread_flag(TIF_32BIT)) { | ||
288 | regs->tpc &= 0xffffffff; | ||
289 | regs->tnpc &= 0xffffffff; | ||
290 | } | ||
291 | info.si_signo = SIGSEGV; | ||
292 | info.si_errno = 0; | ||
293 | info.si_code = SEGV_MAPERR; | ||
294 | info.si_addr = (void __user *) addr; | ||
295 | info.si_trapno = 0; | ||
296 | force_sig_info(SIGSEGV, &info, current); | ||
297 | } | ||
298 | |||
299 | void sun4v_data_access_exception_tl1(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx) | ||
300 | { | ||
301 | if (notify_die(DIE_TRAP_TL1, "data access exception tl1", regs, | ||
302 | 0, 0x8, SIGTRAP) == NOTIFY_STOP) | ||
303 | return; | ||
304 | |||
305 | dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); | ||
306 | sun4v_data_access_exception(regs, addr, type_ctx); | ||
307 | } | ||
308 | |||
231 | #ifdef CONFIG_PCI | 309 | #ifdef CONFIG_PCI |
232 | /* This is really pathetic... */ | 310 | /* This is really pathetic... */ |
233 | extern volatile int pci_poke_in_progress; | 311 | extern volatile int pci_poke_in_progress; |
@@ -2150,6 +2228,8 @@ void do_illegal_instruction(struct pt_regs *regs) | |||
2150 | force_sig_info(SIGILL, &info, current); | 2228 | force_sig_info(SIGILL, &info, current); |
2151 | } | 2229 | } |
2152 | 2230 | ||
2231 | extern void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn); | ||
2232 | |||
2153 | void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) | 2233 | void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr) |
2154 | { | 2234 | { |
2155 | siginfo_t info; | 2235 | siginfo_t info; |
@@ -2159,13 +2239,7 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo | |||
2159 | return; | 2239 | return; |
2160 | 2240 | ||
2161 | if (regs->tstate & TSTATE_PRIV) { | 2241 | if (regs->tstate & TSTATE_PRIV) { |
2162 | extern void kernel_unaligned_trap(struct pt_regs *regs, | 2242 | kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc)); |
2163 | unsigned int insn, | ||
2164 | unsigned long sfar, | ||
2165 | unsigned long sfsr); | ||
2166 | |||
2167 | kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), | ||
2168 | sfar, sfsr); | ||
2169 | return; | 2243 | return; |
2170 | } | 2244 | } |
2171 | info.si_signo = SIGBUS; | 2245 | info.si_signo = SIGBUS; |
@@ -2176,6 +2250,26 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo | |||
2176 | force_sig_info(SIGBUS, &info, current); | 2250 | force_sig_info(SIGBUS, &info, current); |
2177 | } | 2251 | } |
2178 | 2252 | ||
2253 | void sun4v_mna(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx) | ||
2254 | { | ||
2255 | siginfo_t info; | ||
2256 | |||
2257 | if (notify_die(DIE_TRAP, "memory address unaligned", regs, | ||
2258 | 0, 0x34, SIGSEGV) == NOTIFY_STOP) | ||
2259 | return; | ||
2260 | |||
2261 | if (regs->tstate & TSTATE_PRIV) { | ||
2262 | kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc)); | ||
2263 | return; | ||
2264 | } | ||
2265 | info.si_signo = SIGBUS; | ||
2266 | info.si_errno = 0; | ||
2267 | info.si_code = BUS_ADRALN; | ||
2268 | info.si_addr = (void __user *) addr; | ||
2269 | info.si_trapno = 0; | ||
2270 | force_sig_info(SIGBUS, &info, current); | ||
2271 | } | ||
2272 | |||
2179 | void do_privop(struct pt_regs *regs) | 2273 | void do_privop(struct pt_regs *regs) |
2180 | { | 2274 | { |
2181 | siginfo_t info; | 2275 | siginfo_t info; |