]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/sparc64/sparc64/swtch.S
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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    %i1, %i0
50 END(cpu_throw)
51
52 /*
53  * void cpu_switch(struct thread *old, struct thread *new)
54  */
55 ENTRY(cpu_switch)
56         save    %sp, -CCFSZ, %sp
57         mov     %i1, %i0
58
59         /*
60          * If the current thread was using floating point in the kernel, save
61          * its context.  The userland floating point context has already been
62          * saved in that case.
63          */
64         rd      %fprs, %l2
65         andcc   %l2, FPRS_FEF, %g0
66         bz,a,pt %xcc, 1f
67          nop
68         call    savefpctx
69          add    PCB_REG, PCB_KFP, %o0
70         ba,a    %xcc, 2f
71          nop
72
73         /*
74          * If the current thread was using floating point in userland, save
75          * its context.
76          */
77 1:      sub     PCB_REG, TF_SIZEOF, %l2
78         ldx     [%l2 + TF_FPRS], %l3
79         andcc   %l3, FPRS_FEF, %g0
80         bz,a,pt %xcc, 2f
81          nop
82         call    savefpctx
83          add    PCB_REG, PCB_UFP, %o0
84         andn    %l3, FPRS_FEF, %l3
85         stx     %l3, [%l2 + TF_FPRS]
86
87         ldx     [PCB_REG + PCB_FLAGS], %l3
88         or      %l3, PCB_FEF, %l3
89         stx     %l3, [PCB_REG + PCB_FLAGS]
90
91         /*
92          * Flush the windows out to the stack and save the current frame
93          * pointer and program counter.
94          */
95 2:      flushw
96         wrpr    %g0, 0, %cleanwin
97         stx     %fp, [PCB_REG + PCB_SP]
98         stx     %i7, [PCB_REG + PCB_PC]
99
100         /*
101          * Load the new thread's frame pointer and program counter, and set
102          * the current thread and pcb.
103          */
104 .Lsw1:
105 #if KTR_COMPILE & KTR_PROC
106         CATR(KTR_PROC, "cpu_switch: new td=%p pc=%#lx fp=%#lx"
107             , %g1, %g2, %g3, 7, 8, 9)
108         stx     %i0, [%g1 + KTR_PARM1]
109         ldx     [%i0 + TD_PCB], %g2
110         ldx     [%g2 + PCB_PC], %g3
111         stx     %g3, [%g1 + KTR_PARM2]
112         ldx     [%g2 + PCB_SP], %g3
113         stx     %g3, [%g1 + KTR_PARM3]
114 9:
115 #endif
116         ldx     [%i0 + TD_PCB], %i1
117
118         stx     %i0, [PCPU(CURTHREAD)]
119         stx     %i1, [PCPU(CURPCB)]
120
121         wrpr    %g0, PSTATE_NORMAL, %pstate
122         mov     %i1, PCB_REG
123         wrpr    %g0, PSTATE_ALT, %pstate
124         mov     %i1, PCB_REG
125         wrpr    %g0, PSTATE_KERNEL, %pstate
126
127         ldx     [PCB_REG + PCB_SP], %fp
128         ldx     [PCB_REG + PCB_PC], %i7
129         sub     %fp, CCFSZ, %sp
130
131         /*
132          * Point to the pmaps of the new process, and of the last non-kernel
133          * process to run.
134          */
135         ldx     [%i0 + TD_PROC], %i2
136         ldx     [PCPU(PMAP)], %l2
137         ldx     [%i2 + P_VMSPACE], %i5
138         add     %i5, VM_PMAP, %i2
139
140 #if KTR_COMPILE & KTR_PROC
141         CATR(KTR_PROC, "cpu_switch: new pmap=%p old pmap=%p"
142             , %g1, %g2, %g3, 7, 8, 9)
143         stx     %i2, [%g1 + KTR_PARM1]
144         stx     %l2, [%g1 + KTR_PARM2]
145 9:
146 #endif
147
148         /*
149          * If they are the same we are done.
150          */
151         cmp     %l2, %i2
152         be,a,pn %xcc, 5f
153          nop
154
155         /*
156          * If the new process is a kernel thread we can just leave the old
157          * context active and avoid recycling its context number.
158          */
159         SET(vmspace0, %i4, %i3)
160         cmp     %i5, %i3
161         be,a,pn %xcc, 5f
162          nop
163
164         /*
165          * If there was no non-kernel pmap, don't try to deactivate it.
166          */
167         brz,a,pn %l2, 3f
168          nop
169
170         /*
171          * Mark the pmap of the last non-kernel vmspace to run as no longer
172          * active on this CPU.
173          */
174         lduw    [%l2 + PM_ACTIVE], %l3
175         lduw    [PCPU(CPUMASK)], %l4
176         andn    %l3, %l4, %l3
177         stw     %l3, [%l2 + PM_ACTIVE]
178
179         /*
180          * Take away its context number.
181          */
182         lduw    [PCPU(CPUID)], %l3
183         sllx    %l3, INT_SHIFT, %l3
184         add     %l2, PM_CONTEXT, %l4
185         mov     -1, %l5
186         stw     %l5, [%l3 + %l4]
187
188         /*
189          * Find a new TLB context.  If we've run out we have to flush all
190          * user mappings from the TLB and reset the context numbers.
191          */
192 3:      lduw    [PCPU(TLB_CTX)], %i3
193         lduw    [PCPU(TLB_CTX_MAX)], %i4
194         cmp     %i3, %i4
195         bne,a,pt %xcc, 4f
196          nop
197         SET(tlb_flush_user, %i5, %i4)
198         ldx     [%i4], %i5
199         call    %i5
200          nop
201         lduw    [PCPU(TLB_CTX_MIN)], %i3
202
203         /*
204          * Advance next free context.
205          */
206 4:      add     %i3, 1, %i4
207         stw     %i4, [PCPU(TLB_CTX)]
208
209         /*
210          * Set the new context number in the pmap.
211          */
212         lduw    [PCPU(CPUID)], %i4
213         sllx    %i4, INT_SHIFT, %i4
214         add     %i2, PM_CONTEXT, %i5
215         stw     %i3, [%i4 + %i5]
216
217         /*
218          * Mark the pmap as active on this CPU.
219          */
220         lduw    [%i2 + PM_ACTIVE], %i4
221         lduw    [PCPU(CPUMASK)], %i5
222         or      %i4, %i5, %i4
223         stw     %i4, [%i2 + PM_ACTIVE]
224
225         /*
226          * Make note of the change in pmap.
227          */
228         stx     %i2, [PCPU(PMAP)]
229
230         /*
231          * Fiddle the hardware bits.  Set the TSB registers and install the
232          * new context number in the CPU.
233          */
234         ldx     [%i2 + PM_TSB], %i4
235         mov     AA_DMMU_TSB, %i5
236         stxa    %i4, [%i5] ASI_DMMU
237         mov     AA_IMMU_TSB, %i5
238         stxa    %i4, [%i5] ASI_IMMU
239         setx    TLB_PCXR_PGSZ_MASK, %i5, %i4
240         mov     AA_DMMU_PCXR, %i5
241         ldxa    [%i5] ASI_DMMU, %i2
242         and     %i2, %i4, %i2
243         or      %i3, %i2, %i3
244         sethi   %hi(KERNBASE), %i4
245         stxa    %i3, [%i5] ASI_DMMU
246         flush   %i4
247
248         /*
249          * Done, return and load the new process's window from the stack.
250          */
251 5:      ret
252          restore
253 END(cpu_switch)
254
255 ENTRY(savectx)
256         save    %sp, -CCFSZ, %sp
257         flushw
258         call    savefpctx
259          add    %i0, PCB_UFP, %o0
260         stx     %fp, [%i0 + PCB_SP]
261         stx     %i7, [%i0 + PCB_PC]
262         ret
263          restore %g0, 0, %o0
264 END(savectx)
265
266 /*
267  * void savefpctx(uint32_t *);
268  */
269 ENTRY(savefpctx)
270         wr      %g0, FPRS_FEF, %fprs
271         wr      %g0, ASI_BLK_S, %asi
272         stda    %f0, [%o0 + (0 * 64)] %asi
273         stda    %f16, [%o0 + (1 * 64)] %asi
274         stda    %f32, [%o0 + (2 * 64)] %asi
275         stda    %f48, [%o0 + (3 * 64)] %asi
276         membar  #Sync
277         retl
278          wr     %g0, 0, %fprs
279 END(savefpctx)