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 | |
parent | 618e9ed98aed924a1fc664eb6522db4a5e927043 (diff) |
[SPARC64]: SUN4V memory exception trap handlers.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc64/kernel/sun4v_tlb_miss.S | 170 | ||||
-rw-r--r-- | arch/sparc64/kernel/traps.c | 108 | ||||
-rw-r--r-- | arch/sparc64/kernel/unaligned.c | 45 | ||||
-rw-r--r-- | arch/sparc64/kernel/winfixup.S | 26 |
4 files changed, 325 insertions, 24 deletions
diff --git a/arch/sparc64/kernel/sun4v_tlb_miss.S b/arch/sparc64/kernel/sun4v_tlb_miss.S index b8678b5557aa..c408b05a5f0a 100644 --- a/arch/sparc64/kernel/sun4v_tlb_miss.S +++ b/arch/sparc64/kernel/sun4v_tlb_miss.S | |||
@@ -237,6 +237,167 @@ sun4v_tsb_miss_common: | |||
237 | ba,pt %xcc, tsb_miss_page_table_walk | 237 | ba,pt %xcc, tsb_miss_page_table_walk |
238 | add %g1, %g2, %g1 | 238 | add %g1, %g2, %g1 |
239 | 239 | ||
240 | /* Instruction Access Exception, tl0. */ | ||
241 | sun4v_iacc: | ||
242 | mov SCRATCHPAD_CPUID, %g1 | ||
243 | ldxa [%g1] ASI_SCRATCHPAD, %g3 | ||
244 | sethi %hi(trap_block), %g2 | ||
245 | or %g2, %lo(trap_block), %g2 | ||
246 | sllx %g3, TRAP_BLOCK_SZ_SHIFT, %g3 | ||
247 | add %g2, %g3, %g2 | ||
248 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_I_TYPE_OFFSET], %g3 | ||
249 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_I_ADDR_OFFSET], %g4 | ||
250 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_I_CTX_OFFSET], %g5 | ||
251 | sllx %g3, 16, %g3 | ||
252 | or %g5, %g3, %g5 | ||
253 | ba,pt %xcc, etrap | ||
254 | rd %pc, %g7 | ||
255 | mov %l4, %o1 | ||
256 | mov %l5, %o2 | ||
257 | call sun4v_insn_access_exception | ||
258 | add %sp, PTREGS_OFF, %o0 | ||
259 | ba,a,pt %xcc, rtrap_clr_l6 | ||
260 | |||
261 | /* Instruction Access Exception, tl1. */ | ||
262 | sun4v_iacc_tl1: | ||
263 | mov SCRATCHPAD_CPUID, %g1 | ||
264 | ldxa [%g1] ASI_SCRATCHPAD, %g3 | ||
265 | sethi %hi(trap_block), %g2 | ||
266 | or %g2, %lo(trap_block), %g2 | ||
267 | sllx %g3, TRAP_BLOCK_SZ_SHIFT, %g3 | ||
268 | add %g2, %g3, %g2 | ||
269 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_I_TYPE_OFFSET], %g3 | ||
270 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_I_ADDR_OFFSET], %g4 | ||
271 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_I_CTX_OFFSET], %g5 | ||
272 | sllx %g3, 16, %g3 | ||
273 | or %g5, %g3, %g5 | ||
274 | ba,pt %xcc, etraptl1 | ||
275 | rd %pc, %g7 | ||
276 | mov %l4, %o1 | ||
277 | mov %l5, %o2 | ||
278 | call sun4v_insn_access_exception_tl1 | ||
279 | add %sp, PTREGS_OFF, %o0 | ||
280 | ba,a,pt %xcc, rtrap_clr_l6 | ||
281 | |||
282 | /* Data Access Exception, tl0. */ | ||
283 | sun4v_dacc: | ||
284 | mov SCRATCHPAD_CPUID, %g1 | ||
285 | ldxa [%g1] ASI_SCRATCHPAD, %g3 | ||
286 | sethi %hi(trap_block), %g2 | ||
287 | or %g2, %lo(trap_block), %g2 | ||
288 | sllx %g3, TRAP_BLOCK_SZ_SHIFT, %g3 | ||
289 | add %g2, %g3, %g2 | ||
290 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_TYPE_OFFSET], %g3 | ||
291 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_ADDR_OFFSET], %g4 | ||
292 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_CTX_OFFSET], %g5 | ||
293 | sllx %g3, 16, %g3 | ||
294 | or %g5, %g3, %g5 | ||
295 | ba,pt %xcc, etrap | ||
296 | rd %pc, %g7 | ||
297 | mov %l4, %o1 | ||
298 | mov %l5, %o2 | ||
299 | call sun4v_data_access_exception | ||
300 | add %sp, PTREGS_OFF, %o0 | ||
301 | ba,a,pt %xcc, rtrap_clr_l6 | ||
302 | |||
303 | /* Data Access Exception, tl1. */ | ||
304 | sun4v_dacc_tl1: | ||
305 | mov SCRATCHPAD_CPUID, %g1 | ||
306 | ldxa [%g1] ASI_SCRATCHPAD, %g3 | ||
307 | sethi %hi(trap_block), %g2 | ||
308 | or %g2, %lo(trap_block), %g2 | ||
309 | sllx %g3, TRAP_BLOCK_SZ_SHIFT, %g3 | ||
310 | add %g2, %g3, %g2 | ||
311 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_TYPE_OFFSET], %g3 | ||
312 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_ADDR_OFFSET], %g4 | ||
313 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_CTX_OFFSET], %g5 | ||
314 | sllx %g3, 16, %g3 | ||
315 | or %g5, %g3, %g5 | ||
316 | ba,pt %xcc, etraptl1 | ||
317 | rd %pc, %g7 | ||
318 | mov %l4, %o1 | ||
319 | mov %l5, %o2 | ||
320 | call sun4v_data_access_exception_tl1 | ||
321 | add %sp, PTREGS_OFF, %o0 | ||
322 | ba,a,pt %xcc, rtrap_clr_l6 | ||
323 | |||
324 | /* Memory Address Unaligned. */ | ||
325 | sun4v_mna: | ||
326 | mov SCRATCHPAD_CPUID, %g1 | ||
327 | ldxa [%g1] ASI_SCRATCHPAD, %g3 | ||
328 | sethi %hi(trap_block), %g2 | ||
329 | or %g2, %lo(trap_block), %g2 | ||
330 | sllx %g3, TRAP_BLOCK_SZ_SHIFT, %g3 | ||
331 | add %g2, %g3, %g2 | ||
332 | mov HV_FAULT_TYPE_UNALIGNED, %g3 | ||
333 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_ADDR_OFFSET], %g4 | ||
334 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_CTX_OFFSET], %g5 | ||
335 | sllx %g3, 16, %g3 | ||
336 | or %g5, %g3, %g5 | ||
337 | |||
338 | /* Window fixup? */ | ||
339 | rdpr %tl, %g2 | ||
340 | cmp %g2, 1 | ||
341 | bgu,pn %icc, winfix_mna | ||
342 | rdpr %tpc, %g3 | ||
343 | |||
344 | ba,pt %xcc, etrap | ||
345 | rd %pc, %g7 | ||
346 | mov %l4, %o1 | ||
347 | mov %l5, %o2 | ||
348 | call sun4v_mna | ||
349 | add %sp, PTREGS_OFF, %o0 | ||
350 | ba,a,pt %xcc, rtrap_clr_l6 | ||
351 | |||
352 | /* Privileged Action. */ | ||
353 | sun4v_privact: | ||
354 | ba,pt %xcc, etrap | ||
355 | rd %pc, %g7 | ||
356 | call do_privact | ||
357 | add %sp, PTREGS_OFF, %o0 | ||
358 | ba,a,pt %xcc, rtrap_clr_l6 | ||
359 | |||
360 | /* Unaligned ldd float, tl0. */ | ||
361 | sun4v_lddfmna: | ||
362 | mov SCRATCHPAD_CPUID, %g1 | ||
363 | ldxa [%g1] ASI_SCRATCHPAD, %g3 | ||
364 | sethi %hi(trap_block), %g2 | ||
365 | or %g2, %lo(trap_block), %g2 | ||
366 | sllx %g3, TRAP_BLOCK_SZ_SHIFT, %g3 | ||
367 | add %g2, %g3, %g2 | ||
368 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_TYPE_OFFSET], %g3 | ||
369 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_ADDR_OFFSET], %g4 | ||
370 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_CTX_OFFSET], %g5 | ||
371 | sllx %g3, 16, %g3 | ||
372 | or %g5, %g3, %g5 | ||
373 | ba,pt %xcc, etrap | ||
374 | rd %pc, %g7 | ||
375 | mov %l4, %o1 | ||
376 | mov %l5, %o2 | ||
377 | call handle_lddfmna | ||
378 | add %sp, PTREGS_OFF, %o0 | ||
379 | ba,a,pt %xcc, rtrap_clr_l6 | ||
380 | |||
381 | /* Unaligned std float, tl0. */ | ||
382 | sun4v_stdfmna: | ||
383 | mov SCRATCHPAD_CPUID, %g1 | ||
384 | ldxa [%g1] ASI_SCRATCHPAD, %g3 | ||
385 | sethi %hi(trap_block), %g2 | ||
386 | or %g2, %lo(trap_block), %g2 | ||
387 | sllx %g3, TRAP_BLOCK_SZ_SHIFT, %g3 | ||
388 | add %g2, %g3, %g2 | ||
389 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_TYPE_OFFSET], %g3 | ||
390 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_ADDR_OFFSET], %g4 | ||
391 | ldx [%g2 + TRAP_PER_CPU_FAULT_INFO + HV_FAULT_D_CTX_OFFSET], %g5 | ||
392 | sllx %g3, 16, %g3 | ||
393 | or %g5, %g3, %g5 | ||
394 | ba,pt %xcc, etrap | ||
395 | rd %pc, %g7 | ||
396 | mov %l4, %o1 | ||
397 | mov %l5, %o2 | ||
398 | call handle_stdfmna | ||
399 | add %sp, PTREGS_OFF, %o0 | ||
400 | ba,a,pt %xcc, rtrap_clr_l6 | ||
240 | 401 | ||
241 | #define BRANCH_ALWAYS 0x10680000 | 402 | #define BRANCH_ALWAYS 0x10680000 |
242 | #define NOP 0x01000000 | 403 | #define NOP 0x01000000 |
@@ -265,6 +426,15 @@ sun4v_patch_tlb_handlers: | |||
265 | SUN4V_DO_PATCH(tl1_damiss, sun4v_dtlb_miss) | 426 | SUN4V_DO_PATCH(tl1_damiss, sun4v_dtlb_miss) |
266 | SUN4V_DO_PATCH(tl0_daprot, sun4v_dtlb_prot) | 427 | SUN4V_DO_PATCH(tl0_daprot, sun4v_dtlb_prot) |
267 | SUN4V_DO_PATCH(tl1_daprot, sun4v_dtlb_prot) | 428 | SUN4V_DO_PATCH(tl1_daprot, sun4v_dtlb_prot) |
429 | SUN4V_DO_PATCH(tl0_iax, sun4v_iacc) | ||
430 | SUN4V_DO_PATCH(tl1_iax, sun4v_iacc_tl1) | ||
431 | SUN4V_DO_PATCH(tl0_dax, sun4v_dacc) | ||
432 | SUN4V_DO_PATCH(tl1_dax, sun4v_dacc_tl1) | ||
433 | SUN4V_DO_PATCH(tl0_mna, sun4v_mna) | ||
434 | SUN4V_DO_PATCH(tl1_mna, sun4v_mna) | ||
435 | SUN4V_DO_PATCH(tl0_lddfmna, sun4v_lddfmna) | ||
436 | SUN4V_DO_PATCH(tl0_stdfmna, sun4v_stdfmna) | ||
437 | SUN4V_DO_PATCH(tl0_privact, sun4v_privact) | ||
268 | retl | 438 | retl |
269 | nop | 439 | nop |
270 | .size sun4v_patch_tlb_handlers,.-sun4v_patch_tlb_handlers | 440 | .size sun4v_patch_tlb_handlers,.-sun4v_patch_tlb_handlers |
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; |
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 70faf630603b..001e8518331f 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c | |||
@@ -277,7 +277,7 @@ static void kernel_mna_trap_fault(void) | |||
277 | regs->tstate |= (ASI_AIUS << 24UL); | 277 | regs->tstate |= (ASI_AIUS << 24UL); |
278 | } | 278 | } |
279 | 279 | ||
280 | asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr) | 280 | asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) |
281 | { | 281 | { |
282 | enum direction dir = decode_direction(insn); | 282 | enum direction dir = decode_direction(insn); |
283 | int size = decode_access_size(insn); | 283 | int size = decode_access_size(insn); |
@@ -405,6 +405,9 @@ extern void do_privact(struct pt_regs *regs); | |||
405 | extern void spitfire_data_access_exception(struct pt_regs *regs, | 405 | extern void spitfire_data_access_exception(struct pt_regs *regs, |
406 | unsigned long sfsr, | 406 | unsigned long sfsr, |
407 | unsigned long sfar); | 407 | unsigned long sfar); |
408 | extern void sun4v_data_access_exception(struct pt_regs *regs, | ||
409 | unsigned long addr, | ||
410 | unsigned long type_ctx); | ||
408 | 411 | ||
409 | int handle_ldf_stq(u32 insn, struct pt_regs *regs) | 412 | int handle_ldf_stq(u32 insn, struct pt_regs *regs) |
410 | { | 413 | { |
@@ -447,14 +450,20 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) | |||
447 | break; | 450 | break; |
448 | } | 451 | } |
449 | default: | 452 | default: |
450 | spitfire_data_access_exception(regs, 0, addr); | 453 | if (tlb_type == hypervisor) |
454 | sun4v_data_access_exception(regs, addr, 0); | ||
455 | else | ||
456 | spitfire_data_access_exception(regs, 0, addr); | ||
451 | return 1; | 457 | return 1; |
452 | } | 458 | } |
453 | if (put_user (first >> 32, (u32 __user *)addr) || | 459 | if (put_user (first >> 32, (u32 __user *)addr) || |
454 | __put_user ((u32)first, (u32 __user *)(addr + 4)) || | 460 | __put_user ((u32)first, (u32 __user *)(addr + 4)) || |
455 | __put_user (second >> 32, (u32 __user *)(addr + 8)) || | 461 | __put_user (second >> 32, (u32 __user *)(addr + 8)) || |
456 | __put_user ((u32)second, (u32 __user *)(addr + 12))) { | 462 | __put_user ((u32)second, (u32 __user *)(addr + 12))) { |
457 | spitfire_data_access_exception(regs, 0, addr); | 463 | if (tlb_type == hypervisor) |
464 | sun4v_data_access_exception(regs, addr, 0); | ||
465 | else | ||
466 | spitfire_data_access_exception(regs, 0, addr); | ||
458 | return 1; | 467 | return 1; |
459 | } | 468 | } |
460 | } else { | 469 | } else { |
@@ -467,7 +476,10 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) | |||
467 | do_privact(regs); | 476 | do_privact(regs); |
468 | return 1; | 477 | return 1; |
469 | } else if (asi > ASI_SNFL) { | 478 | } else if (asi > ASI_SNFL) { |
470 | spitfire_data_access_exception(regs, 0, addr); | 479 | if (tlb_type == hypervisor) |
480 | sun4v_data_access_exception(regs, addr, 0); | ||
481 | else | ||
482 | spitfire_data_access_exception(regs, 0, addr); | ||
471 | return 1; | 483 | return 1; |
472 | } | 484 | } |
473 | switch (insn & 0x180000) { | 485 | switch (insn & 0x180000) { |
@@ -484,7 +496,10 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) | |||
484 | err |= __get_user (data[i], (u32 __user *)(addr + 4*i)); | 496 | err |= __get_user (data[i], (u32 __user *)(addr + 4*i)); |
485 | } | 497 | } |
486 | if (err && !(asi & 0x2 /* NF */)) { | 498 | if (err && !(asi & 0x2 /* NF */)) { |
487 | spitfire_data_access_exception(regs, 0, addr); | 499 | if (tlb_type == hypervisor) |
500 | sun4v_data_access_exception(regs, addr, 0); | ||
501 | else | ||
502 | spitfire_data_access_exception(regs, 0, addr); | ||
488 | return 1; | 503 | return 1; |
489 | } | 504 | } |
490 | if (asi & 0x8) /* Little */ { | 505 | if (asi & 0x8) /* Little */ { |
@@ -548,7 +563,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
548 | u32 insn; | 563 | u32 insn; |
549 | u32 first, second; | 564 | u32 first, second; |
550 | u64 value; | 565 | u64 value; |
551 | u8 asi, freg; | 566 | u8 freg; |
552 | int flag; | 567 | int flag; |
553 | struct fpustate *f = FPUSTATE; | 568 | struct fpustate *f = FPUSTATE; |
554 | 569 | ||
@@ -557,7 +572,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
557 | if (test_thread_flag(TIF_32BIT)) | 572 | if (test_thread_flag(TIF_32BIT)) |
558 | pc = (u32)pc; | 573 | pc = (u32)pc; |
559 | if (get_user(insn, (u32 __user *) pc) != -EFAULT) { | 574 | if (get_user(insn, (u32 __user *) pc) != -EFAULT) { |
560 | asi = sfsr >> 16; | 575 | int asi = decode_asi(insn, regs); |
561 | if ((asi > ASI_SNFL) || | 576 | if ((asi > ASI_SNFL) || |
562 | (asi < ASI_P)) | 577 | (asi < ASI_P)) |
563 | goto daex; | 578 | goto daex; |
@@ -587,7 +602,11 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
587 | *(u64 *)(f->regs + freg) = value; | 602 | *(u64 *)(f->regs + freg) = value; |
588 | current_thread_info()->fpsaved[0] |= flag; | 603 | current_thread_info()->fpsaved[0] |= flag; |
589 | } else { | 604 | } else { |
590 | daex: spitfire_data_access_exception(regs, sfsr, sfar); | 605 | daex: |
606 | if (tlb_type == hypervisor) | ||
607 | sun4v_data_access_exception(regs, sfar, sfsr); | ||
608 | else | ||
609 | spitfire_data_access_exception(regs, sfsr, sfar); | ||
591 | return; | 610 | return; |
592 | } | 611 | } |
593 | advance(regs); | 612 | advance(regs); |
@@ -600,7 +619,7 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
600 | unsigned long tstate = regs->tstate; | 619 | unsigned long tstate = regs->tstate; |
601 | u32 insn; | 620 | u32 insn; |
602 | u64 value; | 621 | u64 value; |
603 | u8 asi, freg; | 622 | u8 freg; |
604 | int flag; | 623 | int flag; |
605 | struct fpustate *f = FPUSTATE; | 624 | struct fpustate *f = FPUSTATE; |
606 | 625 | ||
@@ -609,8 +628,8 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
609 | if (test_thread_flag(TIF_32BIT)) | 628 | if (test_thread_flag(TIF_32BIT)) |
610 | pc = (u32)pc; | 629 | pc = (u32)pc; |
611 | if (get_user(insn, (u32 __user *) pc) != -EFAULT) { | 630 | if (get_user(insn, (u32 __user *) pc) != -EFAULT) { |
631 | int asi = decode_asi(insn, regs); | ||
612 | freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); | 632 | freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); |
613 | asi = sfsr >> 16; | ||
614 | value = 0; | 633 | value = 0; |
615 | flag = (freg < 32) ? FPRS_DL : FPRS_DU; | 634 | flag = (freg < 32) ? FPRS_DL : FPRS_DU; |
616 | if ((asi > ASI_SNFL) || | 635 | if ((asi > ASI_SNFL) || |
@@ -631,7 +650,11 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr | |||
631 | __put_user ((u32)value, (u32 __user *)(sfar + 4))) | 650 | __put_user ((u32)value, (u32 __user *)(sfar + 4))) |
632 | goto daex; | 651 | goto daex; |
633 | } else { | 652 | } else { |
634 | daex: spitfire_data_access_exception(regs, sfsr, sfar); | 653 | daex: |
654 | if (tlb_type == hypervisor) | ||
655 | sun4v_data_access_exception(regs, sfar, sfsr); | ||
656 | else | ||
657 | spitfire_data_access_exception(regs, sfsr, sfar); | ||
635 | return; | 658 | return; |
636 | } | 659 | } |
637 | advance(regs); | 660 | advance(regs); |
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S index efe2770e8f5d..aca2a98b930b 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S | |||
@@ -109,16 +109,23 @@ winfix_mna: | |||
109 | done | 109 | done |
110 | 110 | ||
111 | fill_fixup_mna: | 111 | fill_fixup_mna: |
112 | TRAP_LOAD_THREAD_REG(%g6, %g1) | ||
113 | rdpr %tstate, %g1 | 112 | rdpr %tstate, %g1 |
114 | and %g1, TSTATE_CWP, %g1 | 113 | and %g1, TSTATE_CWP, %g1 |
115 | wrpr %g1, %cwp | 114 | wrpr %g1, %cwp |
116 | ba,pt %xcc, etrap | 115 | ba,pt %xcc, etrap |
117 | rd %pc, %g7 | 116 | rd %pc, %g7 |
118 | mov %l4, %o2 | 117 | sethi %hi(tlb_type), %g1 |
119 | mov %l5, %o1 | 118 | mov %l4, %o1 |
120 | call mem_address_unaligned | 119 | lduw [%g1 + %lo(tlb_type)], %g1 |
120 | mov %l5, %o2 | ||
121 | cmp %g1, 3 | ||
122 | bne,pt %icc, 1f | ||
121 | add %sp, PTREGS_OFF, %o0 | 123 | add %sp, PTREGS_OFF, %o0 |
124 | call sun4v_mna | ||
125 | nop | ||
126 | ba,a,pt %xcc, rtrap_clr_l6 | ||
127 | 1: call mem_address_unaligned | ||
128 | nop | ||
122 | ba,a,pt %xcc, rtrap_clr_l6 | 129 | ba,a,pt %xcc, rtrap_clr_l6 |
123 | 130 | ||
124 | winfix_dax: | 131 | winfix_dax: |
@@ -128,14 +135,21 @@ winfix_dax: | |||
128 | done | 135 | done |
129 | 136 | ||
130 | fill_fixup_dax: | 137 | fill_fixup_dax: |
131 | TRAP_LOAD_THREAD_REG(%g6, %g1) | ||
132 | rdpr %tstate, %g1 | 138 | rdpr %tstate, %g1 |
133 | and %g1, TSTATE_CWP, %g1 | 139 | and %g1, TSTATE_CWP, %g1 |
134 | wrpr %g1, %cwp | 140 | wrpr %g1, %cwp |
135 | ba,pt %xcc, etrap | 141 | ba,pt %xcc, etrap |
136 | rd %pc, %g7 | 142 | rd %pc, %g7 |
143 | sethi %hi(tlb_type), %g1 | ||
137 | mov %l4, %o1 | 144 | mov %l4, %o1 |
145 | lduw [%g1 + %lo(tlb_type)], %g1 | ||
138 | mov %l5, %o2 | 146 | mov %l5, %o2 |
139 | call spitfire_data_access_exception | 147 | cmp %g1, 3 |
148 | bne,pt %icc, 1f | ||
140 | add %sp, PTREGS_OFF, %o0 | 149 | add %sp, PTREGS_OFF, %o0 |
150 | call sun4v_data_access_exception | ||
151 | nop | ||
152 | ba,a,pt %xcc, rtrap_clr_l6 | ||
153 | 1: call spitfire_data_access_exception | ||
154 | nop | ||
141 | ba,a,pt %xcc, rtrap_clr_l6 | 155 | ba,a,pt %xcc, rtrap_clr_l6 |