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(CPUMASK)], %l4
168
169 /*
170 * Mark the pmap of the last non-kernel vmspace to run as no longer
171 * active on this CPU.
172 */
173 lduw [%l2 + PM_ACTIVE], %l3
174 andn %l3, %l4, %l3
175 stw %l3, [%l2 + PM_ACTIVE]
176
177 /*
178 * Take away its context number.
179 */
180 lduw [PCPU(CPUID)], %l3
181 sllx %l3, INT_SHIFT, %l3
182 add %l2, PM_CONTEXT, %l4
183 mov -1, %l5
184 stw %l5, [%l3 + %l4]
185
186 3: cmp %i2, %g0
187 be,pn %xcc, 4f
188 lduw [PCPU(TLB_CTX_MAX)], %i4
189 stx %i2, [%i0 + TD_LOCK]
190
191 /*
192 * Find a new TLB context. If we've run out we have to flush all
193 * user mappings from the TLB and reset the context numbers.
194 */
195 4: lduw [PCPU(TLB_CTX)], %i3
196 cmp %i3, %i4
197 bne,a,pt %xcc, 5f
198 nop
199 SET(tlb_flush_user, %i5, %i4)
200 ldx [%i4], %i5
201 call %i5
202 lduw [PCPU(TLB_CTX_MIN)], %i3
203
204 /*
205 * Advance next free context.
206 */
207 5: add %i3, 1, %i4
208 stw %i4, [PCPU(TLB_CTX)]
209
210 /*
211 * Set the new context number in the pmap.
212 */
213 lduw [PCPU(CPUID)], %i4
214 sllx %i4, INT_SHIFT, %i4
215 add %l1, PM_CONTEXT, %i5
216 stw %i3, [%i4 + %i5]
217
218 /*
219 * Mark the pmap as active on this CPU.
220 */
221 lduw [%l1 + PM_ACTIVE], %i4
222 lduw [PCPU(CPUMASK)], %i5
223 or %i4, %i5, %i4
224 stw %i4, [%l1 + PM_ACTIVE]
225
226 /*
227 * Make note of the change in pmap.
228 */
229 stx %l1, [PCPU(PMAP)]
230
231 /*
232 * Fiddle the hardware bits. Set the TSB registers and install the
233 * new context number in the CPU.
234 */
235 ldx [%l1 + PM_TSB], %i4
236 mov AA_DMMU_TSB, %i5
237 stxa %i4, [%i5] ASI_DMMU
238 mov AA_IMMU_TSB, %i5
239 stxa %i4, [%i5] ASI_IMMU
240 setx TLB_CXR_PGSZ_MASK, %i5, %i4
241 mov AA_DMMU_PCXR, %i5
242 ldxa [%i5] ASI_DMMU, %l1
243 and %l1, %i4, %l1
244 or %i3, %l1, %i3
245 sethi %hi(KERNBASE), %i4
246 stxa %i3, [%i5] ASI_DMMU
247 flush %i4
248
249 /*
250 * Done, return and load the new process's window from the stack.
251 */
252
253 6: ret
254 restore
255
256 7: cmp %i2, %g0
257 be,a,pn %xcc, 6b
258 nop
259 stx %i2, [%i0 + TD_LOCK]
260 ret
261 restore
262 END(cpu_switch)
263
264 ENTRY(savectx)
265 save %sp, -CCFSZ, %sp
266 flushw
267 call savefpctx
268 add %i0, PCB_UFP, %o0
269 stx %fp, [%i0 + PCB_SP]
270 stx %i7, [%i0 + PCB_PC]
271 ret
272 restore %g0, 0, %o0
273 END(savectx)
274
275 /*
276 * void savefpctx(uint32_t *);
277 */
278 ENTRY(savefpctx)
279 wr %g0, FPRS_FEF, %fprs
280 wr %g0, ASI_BLK_S, %asi
281 stda %f0, [%o0 + (0 * 64)] %asi
282 stda %f16, [%o0 + (1 * 64)] %asi
283 stda %f32, [%o0 + (2 * 64)] %asi
284 stda %f48, [%o0 + (3 * 64)] %asi
285 membar #Sync
286 retl
287 wr %g0, 0, %fprs
288 END(savefpctx)
Cache object: fbc0242f80273c67987d56557f73f77c
|