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