diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-02-04 03:10:01 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-03-20 04:11:36 -0500 |
commit | 314ef6859750b6539eac48d78059bb7986f29cb1 (patch) | |
tree | 26c7da386349c1cf377225356e1012ae62da6f07 /arch/sparc64/kernel | |
parent | ffe483d55229fadbaf4cc7316d47024a24ecd1a2 (diff) |
[SPARC64]: Refine register window trap handling.
When saving and restoing trap state, do the window spill/fill
handling inline so that we never trap deeper than 2 trap levels.
This is important for chips like Niagara.
The window fixup code is massively simplified, and many more
improvements are now possible.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r-- | arch/sparc64/kernel/etrap.S | 104 | ||||
-rw-r--r-- | arch/sparc64/kernel/process.c | 20 | ||||
-rw-r--r-- | arch/sparc64/kernel/rtrap.S | 58 | ||||
-rw-r--r-- | arch/sparc64/kernel/tsb.S | 1 | ||||
-rw-r--r-- | arch/sparc64/kernel/ttable.S | 16 | ||||
-rw-r--r-- | arch/sparc64/kernel/winfixup.S | 454 |
6 files changed, 214 insertions, 439 deletions
diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index b5f6bc52d917..4a0e01b14044 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S | |||
@@ -55,7 +55,31 @@ etrap_irq: | |||
55 | rd %y, %g3 | 55 | rd %y, %g3 |
56 | stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] | 56 | stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] |
57 | st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y] | 57 | st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y] |
58 | save %g2, -STACK_BIAS, %sp ! Ordering here is critical | 58 | |
59 | rdpr %cansave, %g1 | ||
60 | brnz,pt %g1, etrap_save | ||
61 | nop | ||
62 | |||
63 | rdpr %cwp, %g1 | ||
64 | add %g1, 2, %g1 | ||
65 | wrpr %g1, %cwp | ||
66 | be,pt %xcc, etrap_user_spill | ||
67 | mov ASI_AIUP, %g3 | ||
68 | |||
69 | rdpr %otherwin, %g3 | ||
70 | brz %g3, etrap_kernel_spill | ||
71 | mov ASI_AIUS, %g3 | ||
72 | |||
73 | etrap_user_spill: | ||
74 | |||
75 | wr %g3, 0x0, %asi | ||
76 | ldx [%g6 + TI_FLAGS], %g3 | ||
77 | and %g3, _TIF_32BIT, %g3 | ||
78 | brnz,pt %g3, etrap_user_spill_32bit | ||
79 | nop | ||
80 | ba,a,pt %xcc, etrap_user_spill_64bit | ||
81 | |||
82 | etrap_save: save %g2, -STACK_BIAS, %sp | ||
59 | mov %g6, %l6 | 83 | mov %g6, %l6 |
60 | 84 | ||
61 | bne,pn %xcc, 3f | 85 | bne,pn %xcc, 3f |
@@ -176,83 +200,5 @@ etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself. | |||
176 | ba,pt %xcc, 1b | 200 | ba,pt %xcc, 1b |
177 | andcc %g1, TSTATE_PRIV, %g0 | 201 | andcc %g1, TSTATE_PRIV, %g0 |
178 | 202 | ||
179 | .align 64 | ||
180 | .globl scetrap | ||
181 | scetrap: | ||
182 | TRAP_LOAD_THREAD_REG(%g6, %g1) | ||
183 | rdpr %pil, %g2 | ||
184 | rdpr %tstate, %g1 | ||
185 | sllx %g2, 20, %g3 | ||
186 | andcc %g1, TSTATE_PRIV, %g0 | ||
187 | or %g1, %g3, %g1 | ||
188 | bne,pn %xcc, 1f | ||
189 | sub %sp, (STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS), %g2 | ||
190 | wrpr %g0, 7, %cleanwin | ||
191 | |||
192 | sllx %g1, 51, %g3 | ||
193 | sethi %hi(TASK_REGOFF), %g2 | ||
194 | or %g2, %lo(TASK_REGOFF), %g2 | ||
195 | brlz,pn %g3, 1f | ||
196 | add %g6, %g2, %g2 | ||
197 | wr %g0, 0, %fprs | ||
198 | 1: rdpr %tpc, %g3 | ||
199 | stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE] | ||
200 | |||
201 | rdpr %tnpc, %g1 | ||
202 | stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC] | ||
203 | stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC] | ||
204 | save %g2, -STACK_BIAS, %sp ! Ordering here is critical | ||
205 | mov %g6, %l6 | ||
206 | bne,pn %xcc, 2f | ||
207 | mov ASI_P, %l7 | ||
208 | rdpr %canrestore, %g3 | ||
209 | |||
210 | rdpr %wstate, %g2 | ||
211 | wrpr %g0, 0, %canrestore | ||
212 | sll %g2, 3, %g2 | ||
213 | mov PRIMARY_CONTEXT, %l4 | ||
214 | wrpr %g3, 0, %otherwin | ||
215 | wrpr %g2, 0, %wstate | ||
216 | sethi %hi(sparc64_kern_pri_context), %g2 | ||
217 | ldx [%g2 + %lo(sparc64_kern_pri_context)], %g3 | ||
218 | stxa %g3, [%l4] ASI_DMMU | ||
219 | sethi %hi(KERNBASE), %l4 | ||
220 | flush %l4 | ||
221 | |||
222 | mov ASI_AIUS, %l7 | ||
223 | 2: mov %g4, %l4 | ||
224 | mov %g5, %l5 | ||
225 | add %g7, 0x4, %l2 | ||
226 | wrpr %g0, ETRAP_PSTATE1, %pstate | ||
227 | stx %g1, [%sp + PTREGS_OFF + PT_V9_G1] | ||
228 | stx %g2, [%sp + PTREGS_OFF + PT_V9_G2] | ||
229 | sllx %l7, 24, %l7 | ||
230 | |||
231 | stx %g3, [%sp + PTREGS_OFF + PT_V9_G3] | ||
232 | rdpr %cwp, %l0 | ||
233 | stx %g4, [%sp + PTREGS_OFF + PT_V9_G4] | ||
234 | stx %g5, [%sp + PTREGS_OFF + PT_V9_G5] | ||
235 | stx %g6, [%sp + PTREGS_OFF + PT_V9_G6] | ||
236 | stx %g7, [%sp + PTREGS_OFF + PT_V9_G7] | ||
237 | or %l7, %l0, %l7 | ||
238 | sethi %hi(TSTATE_RMO | TSTATE_PEF), %l0 | ||
239 | |||
240 | or %l7, %l0, %l7 | ||
241 | wrpr %l2, %tnpc | ||
242 | wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate | ||
243 | stx %i0, [%sp + PTREGS_OFF + PT_V9_I0] | ||
244 | stx %i1, [%sp + PTREGS_OFF + PT_V9_I1] | ||
245 | stx %i2, [%sp + PTREGS_OFF + PT_V9_I2] | ||
246 | stx %i3, [%sp + PTREGS_OFF + PT_V9_I3] | ||
247 | stx %i4, [%sp + PTREGS_OFF + PT_V9_I4] | ||
248 | |||
249 | stx %i5, [%sp + PTREGS_OFF + PT_V9_I5] | ||
250 | stx %i6, [%sp + PTREGS_OFF + PT_V9_I6] | ||
251 | mov %l6, %g6 | ||
252 | stx %i7, [%sp + PTREGS_OFF + PT_V9_I7] | ||
253 | LOAD_PER_CPU_BASE(%g5, %g6, %g4, %g3, %l1) | ||
254 | ldx [%g6 + TI_TASK], %g4 | ||
255 | done | ||
256 | |||
257 | #undef TASK_REGOFF | 203 | #undef TASK_REGOFF |
258 | #undef ETRAP_PSTATE1 | 204 | #undef ETRAP_PSTATE1 |
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 26548fc604b6..803eea4dc4ff 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c | |||
@@ -541,6 +541,18 @@ void synchronize_user_stack(void) | |||
541 | } | 541 | } |
542 | } | 542 | } |
543 | 543 | ||
544 | static void stack_unaligned(unsigned long sp) | ||
545 | { | ||
546 | siginfo_t info; | ||
547 | |||
548 | info.si_signo = SIGBUS; | ||
549 | info.si_errno = 0; | ||
550 | info.si_code = BUS_ADRALN; | ||
551 | info.si_addr = (void __user *) sp; | ||
552 | info.si_trapno = 0; | ||
553 | force_sig_info(SIGBUS, &info, current); | ||
554 | } | ||
555 | |||
544 | void fault_in_user_windows(void) | 556 | void fault_in_user_windows(void) |
545 | { | 557 | { |
546 | struct thread_info *t = current_thread_info(); | 558 | struct thread_info *t = current_thread_info(); |
@@ -556,13 +568,17 @@ void fault_in_user_windows(void) | |||
556 | flush_user_windows(); | 568 | flush_user_windows(); |
557 | window = get_thread_wsaved(); | 569 | window = get_thread_wsaved(); |
558 | 570 | ||
559 | if (window != 0) { | 571 | if (likely(window != 0)) { |
560 | window -= 1; | 572 | window -= 1; |
561 | do { | 573 | do { |
562 | unsigned long sp = (t->rwbuf_stkptrs[window] + bias); | 574 | unsigned long sp = (t->rwbuf_stkptrs[window] + bias); |
563 | struct reg_window *rwin = &t->reg_window[window]; | 575 | struct reg_window *rwin = &t->reg_window[window]; |
564 | 576 | ||
565 | if (copy_to_user((char __user *)sp, rwin, winsize)) | 577 | if (unlikely(sp & 0x7UL)) |
578 | stack_unaligned(sp); | ||
579 | |||
580 | if (unlikely(copy_to_user((char __user *)sp, | ||
581 | rwin, winsize))) | ||
566 | goto barf; | 582 | goto barf; |
567 | } while (window--); | 583 | } while (window--); |
568 | } | 584 | } |
diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index 61bd45e7697e..ecfbbdc56125 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S | |||
@@ -267,15 +267,69 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 | |||
267 | 267 | ||
268 | wrpr %l2, %g0, %canrestore | 268 | wrpr %l2, %g0, %canrestore |
269 | wrpr %l1, %g0, %wstate | 269 | wrpr %l1, %g0, %wstate |
270 | wrpr %g0, %g0, %otherwin | 270 | brnz,pt %l2, user_rtt_restore |
271 | wrpr %g0, %g0, %otherwin | ||
272 | |||
273 | ldx [%g6 + TI_FLAGS], %g3 | ||
274 | wr %g0, ASI_AIUP, %asi | ||
275 | rdpr %cwp, %g1 | ||
276 | andcc %g3, _TIF_32BIT, %g0 | ||
277 | sub %g1, 1, %g1 | ||
278 | bne,pt %xcc, user_rtt_fill_32bit | ||
279 | wrpr %g1, %cwp | ||
280 | ba,a,pt %xcc, user_rtt_fill_64bit | ||
281 | |||
282 | user_rtt_fill_fixup: | ||
283 | rdpr %cwp, %g1 | ||
284 | add %g1, 1, %g1 | ||
285 | wrpr %g1, 0x0, %cwp | ||
286 | |||
287 | rdpr %wstate, %g2 | ||
288 | sll %g2, 3, %g2 | ||
289 | wrpr %g2, 0x0, %wstate | ||
290 | |||
291 | /* We know %canrestore and %otherwin are both zero. */ | ||
292 | |||
293 | sethi %hi(sparc64_kern_pri_context), %g2 | ||
294 | ldx [%g2 + %lo(sparc64_kern_pri_context)], %g2 | ||
295 | mov PRIMARY_CONTEXT, %g1 | ||
296 | stxa %g2, [%g1] ASI_DMMU | ||
297 | sethi %hi(KERNBASE), %g1 | ||
298 | flush %g1 | ||
299 | |||
300 | or %g4, FAULT_CODE_WINFIXUP, %g4 | ||
301 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
302 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
303 | |||
304 | mov %g6, %l1 | ||
305 | wrpr %g0, 0x0, %tl | ||
306 | wrpr %g0, RTRAP_PSTATE, %pstate | ||
307 | mov %l1, %g6 | ||
308 | ldx [%g6 + TI_TASK], %g4 | ||
309 | LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3) | ||
310 | call do_sparc64_fault | ||
311 | add %sp, PTREGS_OFF, %o0 | ||
312 | ba,pt %xcc, rtrap | ||
313 | nop | ||
314 | |||
315 | user_rtt_pre_restore: | ||
316 | add %g1, 1, %g1 | ||
317 | wrpr %g1, 0x0, %cwp | ||
318 | |||
319 | user_rtt_restore: | ||
271 | restore | 320 | restore |
272 | rdpr %canrestore, %g1 | 321 | rdpr %canrestore, %g1 |
273 | wrpr %g1, 0x0, %cleanwin | 322 | wrpr %g1, 0x0, %cleanwin |
274 | retry | 323 | retry |
275 | nop | 324 | nop |
276 | 325 | ||
277 | kern_rtt: restore | 326 | kern_rtt: rdpr %canrestore, %g1 |
327 | brz,pn %g1, kern_rtt_fill | ||
328 | nop | ||
329 | kern_rtt_restore: | ||
330 | restore | ||
278 | retry | 331 | retry |
332 | |||
279 | to_kernel: | 333 | to_kernel: |
280 | #ifdef CONFIG_PREEMPT | 334 | #ifdef CONFIG_PREEMPT |
281 | ldsw [%g6 + TI_PRE_COUNT], %l5 | 335 | ldsw [%g6 + TI_PRE_COUNT], %l5 |
diff --git a/arch/sparc64/kernel/tsb.S b/arch/sparc64/kernel/tsb.S index 28e38b168dda..3b45db98005a 100644 --- a/arch/sparc64/kernel/tsb.S +++ b/arch/sparc64/kernel/tsb.S | |||
@@ -115,7 +115,6 @@ sparc64_realfault_common: | |||
115 | ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state | 115 | ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state |
116 | nop ! Delay slot (fill me) | 116 | nop ! Delay slot (fill me) |
117 | 117 | ||
118 | .globl winfix_trampoline | ||
119 | winfix_trampoline: | 118 | winfix_trampoline: |
120 | rdpr %tpc, %g3 ! Prepare winfixup TNPC | 119 | rdpr %tpc, %g3 ! Prepare winfixup TNPC |
121 | or %g3, 0x7c, %g3 ! Compute branch offset | 120 | or %g3, 0x7c, %g3 ! Compute branch offset |
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 99531424c598..2679b6e253ae 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S | |||
@@ -92,11 +92,11 @@ tl0_resv07c: BTRAP(0x7c) BTRAP(0x7d) BTRAP(0x7e) BTRAP(0x7f) | |||
92 | tl0_s0n: SPILL_0_NORMAL | 92 | tl0_s0n: SPILL_0_NORMAL |
93 | tl0_s1n: SPILL_1_NORMAL | 93 | tl0_s1n: SPILL_1_NORMAL |
94 | tl0_s2n: SPILL_2_NORMAL | 94 | tl0_s2n: SPILL_2_NORMAL |
95 | tl0_s3n: SPILL_3_NORMAL | 95 | tl0_s3n: SPILL_0_NORMAL_ETRAP |
96 | tl0_s4n: SPILL_4_NORMAL | 96 | tl0_s4n: SPILL_1_GENERIC_ETRAP |
97 | tl0_s5n: SPILL_5_NORMAL | 97 | tl0_s5n: SPILL_1_GENERIC_ETRAP_FIXUP |
98 | tl0_s6n: SPILL_6_NORMAL | 98 | tl0_s6n: SPILL_2_GENERIC_ETRAP |
99 | tl0_s7n: SPILL_7_NORMAL | 99 | tl0_s7n: SPILL_2_GENERIC_ETRAP_FIXUP |
100 | tl0_s0o: SPILL_0_OTHER | 100 | tl0_s0o: SPILL_0_OTHER |
101 | tl0_s1o: SPILL_1_OTHER | 101 | tl0_s1o: SPILL_1_OTHER |
102 | tl0_s2o: SPILL_2_OTHER | 102 | tl0_s2o: SPILL_2_OTHER |
@@ -110,9 +110,9 @@ tl0_f1n: FILL_1_NORMAL | |||
110 | tl0_f2n: FILL_2_NORMAL | 110 | tl0_f2n: FILL_2_NORMAL |
111 | tl0_f3n: FILL_3_NORMAL | 111 | tl0_f3n: FILL_3_NORMAL |
112 | tl0_f4n: FILL_4_NORMAL | 112 | tl0_f4n: FILL_4_NORMAL |
113 | tl0_f5n: FILL_5_NORMAL | 113 | tl0_f5n: FILL_0_NORMAL_RTRAP |
114 | tl0_f6n: FILL_6_NORMAL | 114 | tl0_f6n: FILL_1_GENERIC_RTRAP |
115 | tl0_f7n: FILL_7_NORMAL | 115 | tl0_f7n: FILL_2_GENERIC_RTRAP |
116 | tl0_f0o: FILL_0_OTHER | 116 | tl0_f0o: FILL_0_OTHER |
117 | tl0_f1o: FILL_1_OTHER | 117 | tl0_f1o: FILL_1_OTHER |
118 | tl0_f2o: FILL_2_OTHER | 118 | tl0_f2o: FILL_2_OTHER |
diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S index 211021ae6e8a..efe2770e8f5d 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S | |||
@@ -1,8 +1,6 @@ | |||
1 | /* $Id: winfixup.S,v 1.30 2002/02/09 19:49:30 davem Exp $ | 1 | /* winfixup.S: Handle cases where user stack pointer is found to be bogus. |
2 | * | 2 | * |
3 | * winfixup.S: Handle cases where user stack pointer is found to be bogus. | 3 | * Copyright (C) 1997, 2006 David S. Miller (davem@davemloft.net) |
4 | * | ||
5 | * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) | ||
6 | */ | 4 | */ |
7 | 5 | ||
8 | #include <asm/asi.h> | 6 | #include <asm/asi.h> |
@@ -15,367 +13,129 @@ | |||
15 | 13 | ||
16 | .text | 14 | .text |
17 | 15 | ||
18 | set_pcontext: | 16 | /* It used to be the case that these register window fault |
19 | sethi %hi(sparc64_kern_pri_context), %l1 | 17 | * handlers could run via the save and restore instructions |
20 | ldx [%l1 + %lo(sparc64_kern_pri_context)], %l1 | 18 | * done by the trap entry and exit code. They now do the |
21 | mov PRIMARY_CONTEXT, %g1 | 19 | * window spill/fill by hand, so that case no longer can occur. |
22 | stxa %l1, [%g1] ASI_DMMU | 20 | */ |
23 | sethi %hi(KERNBASE), %l1 | ||
24 | flush %l1 | ||
25 | retl | ||
26 | nop | ||
27 | 21 | ||
28 | .align 32 | 22 | .align 32 |
29 | |||
30 | /* Here are the rules, pay attention. | ||
31 | * | ||
32 | * The kernel is disallowed from touching user space while | ||
33 | * the trap level is greater than zero, except for from within | ||
34 | * the window spill/fill handlers. This must be followed | ||
35 | * so that we can easily detect the case where we tried to | ||
36 | * spill/fill with a bogus (or unmapped) user stack pointer. | ||
37 | * | ||
38 | * These are layed out in a special way for cache reasons, | ||
39 | * don't touch... | ||
40 | */ | ||
41 | .globl fill_fixup, spill_fixup | ||
42 | fill_fixup: | 23 | fill_fixup: |
43 | TRAP_LOAD_THREAD_REG(%g6, %g1) | 24 | TRAP_LOAD_THREAD_REG(%g6, %g1) |
44 | rdpr %tstate, %g1 | 25 | rdpr %tstate, %g1 |
45 | andcc %g1, TSTATE_PRIV, %g0 | 26 | and %g1, TSTATE_CWP, %g1 |
46 | or %g4, FAULT_CODE_WINFIXUP, %g4 | 27 | or %g4, FAULT_CODE_WINFIXUP, %g4 |
47 | be,pt %xcc, window_scheisse_from_user_common | 28 | stb %g4, [%g6 + TI_FAULT_CODE] |
48 | and %g1, TSTATE_CWP, %g1 | 29 | stx %g5, [%g6 + TI_FAULT_ADDR] |
49 | 30 | wrpr %g1, %cwp | |
50 | /* This is the extremely complex case, but it does happen from | 31 | ba,pt %xcc, etrap |
51 | * time to time if things are just right. Essentially the restore | 32 | rd %pc, %g7 |
52 | * done in rtrap right before going back to user mode, with tl=1 | 33 | call do_sparc64_fault |
53 | * and that levels trap stack registers all setup, took a fill trap, | 34 | add %sp, PTREGS_OFF, %o0 |
54 | * the user stack was not mapped in the tlb, and tlb miss occurred, | 35 | ba,pt %xcc, rtrap_clr_l6 |
55 | * the pte found was not valid, and a simple ref bit watch update | ||
56 | * could not satisfy the miss, so we got here. | ||
57 | * | ||
58 | * We must carefully unwind the state so we get back to tl=0, preserve | ||
59 | * all the register values we were going to give to the user. Luckily | ||
60 | * most things are where they need to be, we also have the address | ||
61 | * which triggered the fault handy as well. | ||
62 | * | ||
63 | * Also note that we must preserve %l5 and %l6. If the user was | ||
64 | * returning from a system call, we must make it look this way | ||
65 | * after we process the fill fault on the users stack. | ||
66 | * | ||
67 | * First, get into the window where the original restore was executed. | ||
68 | */ | ||
69 | |||
70 | rdpr %wstate, %g2 ! Grab user mode wstate. | ||
71 | wrpr %g1, %cwp ! Get into the right window. | ||
72 | sll %g2, 3, %g2 ! NORMAL-->OTHER | ||
73 | |||
74 | wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. | ||
75 | wrpr %g2, 0x0, %wstate ! This must be consistent. | ||
76 | wrpr %g0, 0x0, %otherwin ! We know this. | ||
77 | call set_pcontext ! Change contexts... | ||
78 | nop | 36 | nop |
79 | rdpr %pstate, %l1 ! Prepare to change globals. | ||
80 | mov %g6, %o7 ! Get current. | ||
81 | |||
82 | andn %l1, PSTATE_MM, %l1 ! We want to be in RMO | ||
83 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
84 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
85 | wrpr %g0, 0x0, %tl ! Out of trap levels. | ||
86 | wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate | ||
87 | mov %o7, %g6 | ||
88 | ldx [%g6 + TI_TASK], %g4 | ||
89 | LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3) | ||
90 | 37 | ||
91 | /* This is the same as below, except we handle this a bit special | 38 | /* Be very careful about usage of the trap globals here. |
92 | * since we must preserve %l5 and %l6, see comment above. | 39 | * You cannot touch %g5 as that has the fault information. |
93 | */ | ||
94 | call do_sparc64_fault | ||
95 | add %sp, PTREGS_OFF, %o0 | ||
96 | ba,pt %xcc, rtrap | ||
97 | nop ! yes, nop is correct | ||
98 | |||
99 | /* Be very careful about usage of the alternate globals here. | ||
100 | * You cannot touch %g4/%g5 as that has the fault information | ||
101 | * should this be from usermode. Also be careful for the case | ||
102 | * where we get here from the save instruction in etrap.S when | ||
103 | * coming from either user or kernel (does not matter which, it | ||
104 | * is the same problem in both cases). Essentially this means | ||
105 | * do not touch %g7 or %g2 so we handle the two cases fine. | ||
106 | */ | 40 | */ |
107 | spill_fixup: | 41 | spill_fixup: |
42 | spill_fixup_mna: | ||
43 | spill_fixup_dax: | ||
108 | TRAP_LOAD_THREAD_REG(%g6, %g1) | 44 | TRAP_LOAD_THREAD_REG(%g6, %g1) |
109 | ldx [%g6 + TI_FLAGS], %g1 | 45 | ldx [%g6 + TI_FLAGS], %g1 |
110 | andcc %g1, _TIF_32BIT, %g0 | 46 | andcc %g1, _TIF_32BIT, %g0 |
111 | ldub [%g6 + TI_WSAVED], %g1 | 47 | ldub [%g6 + TI_WSAVED], %g1 |
112 | 48 | sll %g1, 3, %g3 | |
113 | sll %g1, 3, %g3 | 49 | add %g6, %g3, %g3 |
114 | add %g6, %g3, %g3 | 50 | stx %sp, [%g3 + TI_RWIN_SPTRS] |
115 | stx %sp, [%g3 + TI_RWIN_SPTRS] | 51 | sll %g1, 7, %g3 |
116 | sll %g1, 7, %g3 | 52 | bne,pt %xcc, 1f |
117 | bne,pt %xcc, 1f | 53 | add %g6, %g3, %g3 |
118 | add %g6, %g3, %g3 | 54 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] |
119 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] | 55 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] |
120 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] | 56 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] |
121 | 57 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] | |
122 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] | 58 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] |
123 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] | 59 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] |
124 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] | 60 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] |
125 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] | 61 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] |
126 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] | 62 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] |
127 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] | 63 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] |
128 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] | 64 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] |
129 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] | 65 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] |
130 | 66 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] | |
131 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] | 67 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] |
132 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] | 68 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] |
133 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] | 69 | ba,pt %xcc, 2f |
134 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] | 70 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] |
135 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] | 71 | 1: stw %l0, [%g3 + TI_REG_WINDOW + 0x00] |
136 | b,pt %xcc, 2f | 72 | stw %l1, [%g3 + TI_REG_WINDOW + 0x04] |
137 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] | 73 | stw %l2, [%g3 + TI_REG_WINDOW + 0x08] |
138 | 1: stw %l0, [%g3 + TI_REG_WINDOW + 0x00] | 74 | stw %l3, [%g3 + TI_REG_WINDOW + 0x0c] |
139 | 75 | stw %l4, [%g3 + TI_REG_WINDOW + 0x10] | |
140 | stw %l1, [%g3 + TI_REG_WINDOW + 0x04] | 76 | stw %l5, [%g3 + TI_REG_WINDOW + 0x14] |
141 | stw %l2, [%g3 + TI_REG_WINDOW + 0x08] | 77 | stw %l6, [%g3 + TI_REG_WINDOW + 0x18] |
142 | stw %l3, [%g3 + TI_REG_WINDOW + 0x0c] | 78 | stw %l7, [%g3 + TI_REG_WINDOW + 0x1c] |
143 | stw %l4, [%g3 + TI_REG_WINDOW + 0x10] | 79 | stw %i0, [%g3 + TI_REG_WINDOW + 0x20] |
144 | stw %l5, [%g3 + TI_REG_WINDOW + 0x14] | 80 | stw %i1, [%g3 + TI_REG_WINDOW + 0x24] |
145 | stw %l6, [%g3 + TI_REG_WINDOW + 0x18] | 81 | stw %i2, [%g3 + TI_REG_WINDOW + 0x28] |
146 | stw %l7, [%g3 + TI_REG_WINDOW + 0x1c] | 82 | stw %i3, [%g3 + TI_REG_WINDOW + 0x2c] |
147 | stw %i0, [%g3 + TI_REG_WINDOW + 0x20] | 83 | stw %i4, [%g3 + TI_REG_WINDOW + 0x30] |
148 | 84 | stw %i5, [%g3 + TI_REG_WINDOW + 0x34] | |
149 | stw %i1, [%g3 + TI_REG_WINDOW + 0x24] | 85 | stw %i6, [%g3 + TI_REG_WINDOW + 0x38] |
150 | stw %i2, [%g3 + TI_REG_WINDOW + 0x28] | 86 | stw %i7, [%g3 + TI_REG_WINDOW + 0x3c] |
151 | stw %i3, [%g3 + TI_REG_WINDOW + 0x2c] | 87 | 2: add %g1, 1, %g1 |
152 | stw %i4, [%g3 + TI_REG_WINDOW + 0x30] | 88 | stb %g1, [%g6 + TI_WSAVED] |
153 | stw %i5, [%g3 + TI_REG_WINDOW + 0x34] | 89 | rdpr %tstate, %g1 |
154 | stw %i6, [%g3 + TI_REG_WINDOW + 0x38] | 90 | andcc %g1, TSTATE_PRIV, %g0 |
155 | stw %i7, [%g3 + TI_REG_WINDOW + 0x3c] | ||
156 | 2: add %g1, 1, %g1 | ||
157 | |||
158 | stb %g1, [%g6 + TI_WSAVED] | ||
159 | rdpr %tstate, %g1 | ||
160 | andcc %g1, TSTATE_PRIV, %g0 | ||
161 | saved | 91 | saved |
162 | and %g1, TSTATE_CWP, %g1 | 92 | be,pn %xcc, 1f |
163 | be,a,pn %xcc, window_scheisse_from_user_common | 93 | and %g1, TSTATE_CWP, %g1 |
164 | mov FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4 | ||
165 | retry | 94 | retry |
95 | 1: mov FAULT_CODE_WRITE | FAULT_CODE_DTLB | FAULT_CODE_WINFIXUP, %g4 | ||
96 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
97 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
98 | wrpr %g1, %cwp | ||
99 | ba,pt %xcc, etrap | ||
100 | rd %pc, %g7 | ||
101 | call do_sparc64_fault | ||
102 | add %sp, PTREGS_OFF, %o0 | ||
103 | ba,a,pt %xcc, rtrap_clr_l6 | ||
166 | 104 | ||
167 | window_scheisse_from_user_common: | ||
168 | stb %g4, [%g6 + TI_FAULT_CODE] | ||
169 | stx %g5, [%g6 + TI_FAULT_ADDR] | ||
170 | wrpr %g1, %cwp | ||
171 | ba,pt %xcc, etrap | ||
172 | rd %pc, %g7 | ||
173 | call do_sparc64_fault | ||
174 | add %sp, PTREGS_OFF, %o0 | ||
175 | ba,a,pt %xcc, rtrap_clr_l6 | ||
176 | |||
177 | .globl winfix_mna, fill_fixup_mna, spill_fixup_mna | ||
178 | winfix_mna: | 105 | winfix_mna: |
179 | andn %g3, 0x7f, %g3 | 106 | andn %g3, 0x7f, %g3 |
180 | add %g3, 0x78, %g3 | 107 | add %g3, 0x78, %g3 |
181 | wrpr %g3, %tnpc | 108 | wrpr %g3, %tnpc |
182 | done | 109 | done |
183 | fill_fixup_mna: | ||
184 | TRAP_LOAD_THREAD_REG(%g6, %g1) | ||
185 | rdpr %tstate, %g1 | ||
186 | andcc %g1, TSTATE_PRIV, %g0 | ||
187 | be,pt %xcc, window_mna_from_user_common | ||
188 | and %g1, TSTATE_CWP, %g1 | ||
189 | |||
190 | /* Please, see fill_fixup commentary about why we must preserve | ||
191 | * %l5 and %l6 to preserve absolute correct semantics. | ||
192 | */ | ||
193 | rdpr %wstate, %g2 ! Grab user mode wstate. | ||
194 | wrpr %g1, %cwp ! Get into the right window. | ||
195 | sll %g2, 3, %g2 ! NORMAL-->OTHER | ||
196 | wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. | ||
197 | |||
198 | wrpr %g2, 0x0, %wstate ! This must be consistent. | ||
199 | wrpr %g0, 0x0, %otherwin ! We know this. | ||
200 | call set_pcontext ! Change contexts... | ||
201 | nop | ||
202 | rdpr %pstate, %l1 ! Prepare to change globals. | ||
203 | mov %g4, %o2 ! Setup args for | ||
204 | mov %g5, %o1 ! final call to mem_address_unaligned. | ||
205 | andn %l1, PSTATE_MM, %l1 ! We want to be in RMO | ||
206 | |||
207 | mov %g6, %o7 ! Stash away current. | ||
208 | wrpr %g0, 0x0, %tl ! Out of trap levels. | ||
209 | wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate | ||
210 | mov %o7, %g6 ! Get current back. | ||
211 | ldx [%g6 + TI_TASK], %g4 ! Finish it. | ||
212 | LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3) | ||
213 | call mem_address_unaligned | ||
214 | add %sp, PTREGS_OFF, %o0 | ||
215 | 110 | ||
216 | b,pt %xcc, rtrap | 111 | fill_fixup_mna: |
217 | nop ! yes, the nop is correct | ||
218 | spill_fixup_mna: | ||
219 | TRAP_LOAD_THREAD_REG(%g6, %g1) | 112 | TRAP_LOAD_THREAD_REG(%g6, %g1) |
220 | ldx [%g6 + TI_FLAGS], %g1 | 113 | rdpr %tstate, %g1 |
221 | andcc %g1, _TIF_32BIT, %g0 | 114 | and %g1, TSTATE_CWP, %g1 |
222 | ldub [%g6 + TI_WSAVED], %g1 | 115 | wrpr %g1, %cwp |
223 | sll %g1, 3, %g3 | 116 | ba,pt %xcc, etrap |
224 | add %g6, %g3, %g3 | 117 | rd %pc, %g7 |
225 | stx %sp, [%g3 + TI_RWIN_SPTRS] | 118 | mov %l4, %o2 |
226 | 119 | mov %l5, %o1 | |
227 | sll %g1, 7, %g3 | 120 | call mem_address_unaligned |
228 | bne,pt %xcc, 1f | 121 | add %sp, PTREGS_OFF, %o0 |
229 | add %g6, %g3, %g3 | 122 | ba,a,pt %xcc, rtrap_clr_l6 |
230 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
231 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] | ||
232 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] | ||
233 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] | ||
234 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] | ||
235 | |||
236 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] | ||
237 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] | ||
238 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] | ||
239 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] | ||
240 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] | ||
241 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] | ||
242 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] | ||
243 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] | ||
244 | |||
245 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] | ||
246 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] | ||
247 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] | ||
248 | b,pt %xcc, 2f | ||
249 | add %g1, 1, %g1 | ||
250 | 1: std %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
251 | std %l2, [%g3 + TI_REG_WINDOW + 0x08] | ||
252 | std %l4, [%g3 + TI_REG_WINDOW + 0x10] | ||
253 | 123 | ||
254 | std %l6, [%g3 + TI_REG_WINDOW + 0x18] | ||
255 | std %i0, [%g3 + TI_REG_WINDOW + 0x20] | ||
256 | std %i2, [%g3 + TI_REG_WINDOW + 0x28] | ||
257 | std %i4, [%g3 + TI_REG_WINDOW + 0x30] | ||
258 | std %i6, [%g3 + TI_REG_WINDOW + 0x38] | ||
259 | add %g1, 1, %g1 | ||
260 | 2: stb %g1, [%g6 + TI_WSAVED] | ||
261 | rdpr %tstate, %g1 | ||
262 | |||
263 | andcc %g1, TSTATE_PRIV, %g0 | ||
264 | saved | ||
265 | be,pn %xcc, window_mna_from_user_common | ||
266 | and %g1, TSTATE_CWP, %g1 | ||
267 | retry | ||
268 | window_mna_from_user_common: | ||
269 | wrpr %g1, %cwp | ||
270 | sethi %hi(109f), %g7 | ||
271 | ba,pt %xcc, etrap | ||
272 | 109: or %g7, %lo(109b), %g7 | ||
273 | mov %l4, %o2 | ||
274 | mov %l5, %o1 | ||
275 | call mem_address_unaligned | ||
276 | add %sp, PTREGS_OFF, %o0 | ||
277 | ba,pt %xcc, rtrap | ||
278 | clr %l6 | ||
279 | |||
280 | .globl winfix_dax, fill_fixup_dax, spill_fixup_dax | ||
281 | winfix_dax: | 124 | winfix_dax: |
282 | andn %g3, 0x7f, %g3 | 125 | andn %g3, 0x7f, %g3 |
283 | add %g3, 0x74, %g3 | 126 | add %g3, 0x74, %g3 |
284 | wrpr %g3, %tnpc | 127 | wrpr %g3, %tnpc |
285 | done | 128 | done |
286 | fill_fixup_dax: | ||
287 | TRAP_LOAD_THREAD_REG(%g6, %g1) | ||
288 | rdpr %tstate, %g1 | ||
289 | andcc %g1, TSTATE_PRIV, %g0 | ||
290 | be,pt %xcc, window_dax_from_user_common | ||
291 | and %g1, TSTATE_CWP, %g1 | ||
292 | |||
293 | /* Please, see fill_fixup commentary about why we must preserve | ||
294 | * %l5 and %l6 to preserve absolute correct semantics. | ||
295 | */ | ||
296 | rdpr %wstate, %g2 ! Grab user mode wstate. | ||
297 | wrpr %g1, %cwp ! Get into the right window. | ||
298 | sll %g2, 3, %g2 ! NORMAL-->OTHER | ||
299 | wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. | ||
300 | |||
301 | wrpr %g2, 0x0, %wstate ! This must be consistent. | ||
302 | wrpr %g0, 0x0, %otherwin ! We know this. | ||
303 | call set_pcontext ! Change contexts... | ||
304 | nop | ||
305 | rdpr %pstate, %l1 ! Prepare to change globals. | ||
306 | mov %g4, %o1 ! Setup args for | ||
307 | mov %g5, %o2 ! final call to spitfire_data_access_exception. | ||
308 | andn %l1, PSTATE_MM, %l1 ! We want to be in RMO | ||
309 | |||
310 | mov %g6, %o7 ! Stash away current. | ||
311 | wrpr %g0, 0x0, %tl ! Out of trap levels. | ||
312 | wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate | ||
313 | mov %o7, %g6 ! Get current back. | ||
314 | ldx [%g6 + TI_TASK], %g4 ! Finish it. | ||
315 | LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3) | ||
316 | call spitfire_data_access_exception | ||
317 | add %sp, PTREGS_OFF, %o0 | ||
318 | 129 | ||
319 | b,pt %xcc, rtrap | 130 | fill_fixup_dax: |
320 | nop ! yes, the nop is correct | ||
321 | spill_fixup_dax: | ||
322 | TRAP_LOAD_THREAD_REG(%g6, %g1) | 131 | TRAP_LOAD_THREAD_REG(%g6, %g1) |
323 | ldx [%g6 + TI_FLAGS], %g1 | 132 | rdpr %tstate, %g1 |
324 | andcc %g1, _TIF_32BIT, %g0 | 133 | and %g1, TSTATE_CWP, %g1 |
325 | ldub [%g6 + TI_WSAVED], %g1 | 134 | wrpr %g1, %cwp |
326 | sll %g1, 3, %g3 | 135 | ba,pt %xcc, etrap |
327 | add %g6, %g3, %g3 | 136 | rd %pc, %g7 |
328 | stx %sp, [%g3 + TI_RWIN_SPTRS] | 137 | mov %l4, %o1 |
329 | 138 | mov %l5, %o2 | |
330 | sll %g1, 7, %g3 | 139 | call spitfire_data_access_exception |
331 | bne,pt %xcc, 1f | 140 | add %sp, PTREGS_OFF, %o0 |
332 | add %g6, %g3, %g3 | 141 | ba,a,pt %xcc, rtrap_clr_l6 |
333 | stx %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
334 | stx %l1, [%g3 + TI_REG_WINDOW + 0x08] | ||
335 | stx %l2, [%g3 + TI_REG_WINDOW + 0x10] | ||
336 | stx %l3, [%g3 + TI_REG_WINDOW + 0x18] | ||
337 | stx %l4, [%g3 + TI_REG_WINDOW + 0x20] | ||
338 | |||
339 | stx %l5, [%g3 + TI_REG_WINDOW + 0x28] | ||
340 | stx %l6, [%g3 + TI_REG_WINDOW + 0x30] | ||
341 | stx %l7, [%g3 + TI_REG_WINDOW + 0x38] | ||
342 | stx %i0, [%g3 + TI_REG_WINDOW + 0x40] | ||
343 | stx %i1, [%g3 + TI_REG_WINDOW + 0x48] | ||
344 | stx %i2, [%g3 + TI_REG_WINDOW + 0x50] | ||
345 | stx %i3, [%g3 + TI_REG_WINDOW + 0x58] | ||
346 | stx %i4, [%g3 + TI_REG_WINDOW + 0x60] | ||
347 | |||
348 | stx %i5, [%g3 + TI_REG_WINDOW + 0x68] | ||
349 | stx %i6, [%g3 + TI_REG_WINDOW + 0x70] | ||
350 | stx %i7, [%g3 + TI_REG_WINDOW + 0x78] | ||
351 | b,pt %xcc, 2f | ||
352 | add %g1, 1, %g1 | ||
353 | 1: std %l0, [%g3 + TI_REG_WINDOW + 0x00] | ||
354 | std %l2, [%g3 + TI_REG_WINDOW + 0x08] | ||
355 | std %l4, [%g3 + TI_REG_WINDOW + 0x10] | ||
356 | |||
357 | std %l6, [%g3 + TI_REG_WINDOW + 0x18] | ||
358 | std %i0, [%g3 + TI_REG_WINDOW + 0x20] | ||
359 | std %i2, [%g3 + TI_REG_WINDOW + 0x28] | ||
360 | std %i4, [%g3 + TI_REG_WINDOW + 0x30] | ||
361 | std %i6, [%g3 + TI_REG_WINDOW + 0x38] | ||
362 | add %g1, 1, %g1 | ||
363 | 2: stb %g1, [%g6 + TI_WSAVED] | ||
364 | rdpr %tstate, %g1 | ||
365 | |||
366 | andcc %g1, TSTATE_PRIV, %g0 | ||
367 | saved | ||
368 | be,pn %xcc, window_dax_from_user_common | ||
369 | and %g1, TSTATE_CWP, %g1 | ||
370 | retry | ||
371 | window_dax_from_user_common: | ||
372 | wrpr %g1, %cwp | ||
373 | sethi %hi(109f), %g7 | ||
374 | ba,pt %xcc, etrap | ||
375 | 109: or %g7, %lo(109b), %g7 | ||
376 | mov %l4, %o1 | ||
377 | mov %l5, %o2 | ||
378 | call spitfire_data_access_exception | ||
379 | add %sp, PTREGS_OFF, %o0 | ||
380 | ba,pt %xcc, rtrap | ||
381 | clr %l6 | ||