]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - sys/sparc64/sparc64/swtch.S
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / sys / sparc64 / sparc64 / swtch.S
1 /*-
2  * Copyright (c) 2001 Jake Burkholder.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <machine/asm.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <machine/asmacros.h>
31 #include <machine/asi.h>
32 #include <machine/fsr.h>
33 #include <machine/ktr.h>
34 #include <machine/pcb.h>
35 #include <machine/tstate.h>
36
37 #include "assym.s"
38
39         .register       %g2, #ignore
40         .register       %g3, #ignore
41
42 /*
43  * void cpu_throw(struct thread *old, struct thread *new)
44  */
45 ENTRY(cpu_throw)
46         save    %sp, -CCFSZ, %sp
47         flushw
48         ba      %xcc, .Lsw1
49          mov    %g0, %i2
50 END(cpu_throw)
51
52 /*
53  * void cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx)
54  */
55 ENTRY(cpu_switch)
56         save    %sp, -CCFSZ, %sp
57
58         /*
59          * If the current thread was using floating point in the kernel, save
60          * its context.  The userland floating point context has already been
61          * saved in that case.
62          */
63         rd      %fprs, %l2
64         andcc   %l2, FPRS_FEF, %g0
65         bz,a,pt %xcc, 1f
66          nop
67         call    savefpctx
68          add    PCB_REG, PCB_KFP, %o0
69         ba,a    %xcc, 2f
70          nop
71
72         /*
73          * If the current thread was using floating point in userland, save
74          * its context.
75          */
76 1:      sub     PCB_REG, TF_SIZEOF, %l2
77         ldx     [%l2 + TF_FPRS], %l3
78         andcc   %l3, FPRS_FEF, %g0
79         bz,a,pt %xcc, 2f
80          nop
81         call    savefpctx
82          add    PCB_REG, PCB_UFP, %o0
83         andn    %l3, FPRS_FEF, %l3
84         stx     %l3, [%l2 + TF_FPRS]
85
86         ldx     [PCB_REG + PCB_FLAGS], %l3
87         or      %l3, PCB_FEF, %l3
88         stx     %l3, [PCB_REG + PCB_FLAGS]
89
90         /*
91          * Flush the windows out to the stack and save the current frame
92          * pointer and program counter.
93          */
94 2:      flushw
95         wrpr    %g0, 0, %cleanwin
96         stx     %fp, [PCB_REG + PCB_SP]
97         stx     %i7, [PCB_REG + PCB_PC]
98
99         /*
100          * Load the new thread's frame pointer and program counter, and set
101          * the current thread and pcb.
102          */
103 .Lsw1:
104 #if KTR_COMPILE & KTR_PROC
105         CATR(KTR_PROC, "cpu_switch: new td=%p pc=%#lx fp=%#lx"
106             , %g1, %g2, %g3, 8, 9, 10)
107         stx     %i1, [%g1 + KTR_PARM1]
108         ldx     [%i1 + TD_PCB], %g2
109         ldx     [%g2 + PCB_PC], %g3
110         stx     %g3, [%g1 + KTR_PARM2]
111         ldx     [%g2 + PCB_SP], %g3
112         stx     %g3, [%g1 + KTR_PARM3]
113 10:
114 #endif
115         ldx     [%i1 + TD_PCB], %l0
116
117         stx     %i1, [PCPU(CURTHREAD)]
118         stx     %l0, [PCPU(CURPCB)]
119
120         wrpr    %g0, PSTATE_NORMAL, %pstate
121         mov     %l0, PCB_REG
122         wrpr    %g0, PSTATE_ALT, %pstate
123         mov     %l0, PCB_REG
124         wrpr    %g0, PSTATE_KERNEL, %pstate
125
126         ldx     [PCB_REG + PCB_SP], %fp
127         ldx     [PCB_REG + PCB_PC], %i7
128         sub     %fp, CCFSZ, %sp
129
130         /*
131          * Point to the pmaps of the new process, and of the last non-kernel
132          * process to run.
133          */
134         ldx     [%i1 + TD_PROC], %l1
135         ldx     [PCPU(PMAP)], %l2
136         ldx     [%l1 + P_VMSPACE], %i5
137         add     %i5, VM_PMAP, %l1
138
139 #if KTR_COMPILE & KTR_PROC
140         CATR(KTR_PROC, "cpu_switch: new pmap=%p old pmap=%p"
141             , %g1, %g2, %g3, 8, 9, 10)
142         stx     %l1, [%g1 + KTR_PARM1]
143         stx     %l2, [%g1 + KTR_PARM2]
144 10:
145 #endif
146
147         /*
148          * If they are the same we are done.
149          */
150         cmp     %l2, %l1
151         be,a,pn %xcc, 7f
152          nop
153
154         /*
155          * If the new process is a kernel thread we can just leave the old
156          * context active and avoid recycling its context number.
157          */
158         SET(vmspace0, %i4, %i3)
159         cmp     %i5, %i3
160         be,a,pn %xcc, 7f
161          nop
162
163         /*
164          * If there was no non-kernel pmap, don't try to deactivate it.
165          */
166         brz,pn  %l2, 3f
167          lduw   [PCPU(CPUID)], %l3
168
169         /*
170          * Mark the pmap of the last non-kernel vmspace to run as no longer
171          * active on this CPU.
172          */
173         mov     _NCPUBITS, %l5
174         mov     %g0, %y
175         udiv    %l3, %l5, %l6
176         srl     %l6, 0, %l4
177         sllx    %l4, PTR_SHIFT, %l4
178         add     %l4, PM_ACTIVE, %l4
179         smul    %l6, %l5, %l5
180         sub     %l3, %l5, %l5
181         mov     1, %l6
182         sllx    %l6, %l5, %l5
183         ldx     [%l2 + %l4], %l6
184         andn    %l6, %l5, %l6
185         stx     %l6, [%l2 + %l4]
186
187         /*
188          * Take away its context number.
189          */
190         sllx    %l3, INT_SHIFT, %l3
191         add     %l2, PM_CONTEXT, %l4
192         mov     -1, %l5
193         stw     %l5, [%l3 + %l4]
194
195 3:      cmp     %i2, %g0
196         be,pn   %xcc, 4f
197          lduw   [PCPU(TLB_CTX_MAX)], %i4
198         stx     %i2, [%i0 + TD_LOCK]
199
200         /*
201          * Find a new TLB context.  If we've run out we have to flush all
202          * user mappings from the TLB and reset the context numbers.
203          */
204 4:      lduw    [PCPU(TLB_CTX)], %i3
205         cmp     %i3, %i4
206         bne,a,pt %xcc, 5f
207          nop
208         SET(tlb_flush_user, %i5, %i4)
209         ldx     [%i4], %i5
210         call    %i5
211          lduw   [PCPU(TLB_CTX_MIN)], %i3
212
213         /*
214          * Advance next free context.
215          */
216 5:      add     %i3, 1, %i4
217         stw     %i4, [PCPU(TLB_CTX)]
218
219         /*
220          * Set the new context number in the pmap.
221          */
222         lduw    [PCPU(CPUID)], %l3
223         sllx    %l3, INT_SHIFT, %i4
224         add     %l1, PM_CONTEXT, %i5
225         stw     %i3, [%i4 + %i5]
226
227         /*
228          * Mark the pmap as active on this CPU.
229          */
230         mov     _NCPUBITS, %l5
231         mov     %g0, %y
232         udiv    %l3, %l5, %l6
233         srl     %l6, 0, %l4
234         sllx    %l4, PTR_SHIFT, %l4
235         add     %l4, PM_ACTIVE, %l4
236         smul    %l6, %l5, %l5
237         sub     %l3, %l5, %l5
238         mov     1, %l6
239         sllx    %l6, %l5, %l5
240         ldx     [%l1 + %l4], %l6
241         or      %l6, %l5, %l6
242         stx     %l6, [%l1 + %l4]
243
244         /*
245          * Make note of the change in pmap.
246          */
247         stx     %l1, [PCPU(PMAP)]
248
249         /*
250          * Fiddle the hardware bits.  Set the TSB registers and install the
251          * new context number in the CPU.
252          */
253         ldx     [%l1 + PM_TSB], %i4
254         mov     AA_DMMU_TSB, %i5
255         stxa    %i4, [%i5] ASI_DMMU
256         mov     AA_IMMU_TSB, %i5
257         stxa    %i4, [%i5] ASI_IMMU
258         setx    TLB_CXR_PGSZ_MASK, %i5, %i4
259         mov     AA_DMMU_PCXR, %i5
260         ldxa    [%i5] ASI_DMMU, %l1
261         and     %l1, %i4, %l1
262         or      %i3, %l1, %i3
263         sethi   %hi(KERNBASE), %i4
264         stxa    %i3, [%i5] ASI_DMMU
265         flush   %i4
266
267         /*
268          * Done, return and load the new process's window from the stack.
269          */
270
271 6:      ret
272          restore
273
274 7:      cmp     %i2, %g0
275         be,a,pn %xcc, 6b
276          nop
277         stx     %i2, [%i0 + TD_LOCK]
278         ret
279          restore
280 END(cpu_switch)
281
282 ENTRY(savectx)
283         save    %sp, -CCFSZ, %sp
284         flushw
285         call    savefpctx
286          add    %i0, PCB_UFP, %o0
287         stx     %fp, [%i0 + PCB_SP]
288         stx     %i7, [%i0 + PCB_PC]
289         ret
290          restore %g0, 0, %o0
291 END(savectx)
292
293 /*
294  * void savefpctx(uint32_t *);
295  */
296 ENTRY(savefpctx)
297         wr      %g0, FPRS_FEF, %fprs
298         wr      %g0, ASI_BLK_S, %asi
299         stda    %f0, [%o0 + (0 * 64)] %asi
300         stda    %f16, [%o0 + (1 * 64)] %asi
301         stda    %f32, [%o0 + (2 * 64)] %asi
302         stda    %f48, [%o0 + (3 * 64)] %asi
303         membar  #Sync
304         retl
305          wr     %g0, 0, %fprs
306 END(savefpctx)