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/6.0/sys/sparc64/sparc64/swtch.S 129749 2004-05-26 12:06:52Z tmm $");
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 pmaps of the new process, and of the last non-kernel
131 * process to run.
132 */
133 ldx [%i0 + TD_PROC], %i2
134 ldx [PCPU(PMAP)], %l2
135 ldx [%i2 + P_VMSPACE], %i5
136 add %i5, VM_PMAP, %i2
137
138 #if KTR_COMPILE & KTR_PROC
139 CATR(KTR_PROC, "cpu_switch: new pmap=%p old pmap=%p"
140 , %g1, %g2, %g3, 7, 8, 9)
141 stx %i2, [%g1 + KTR_PARM1]
142 stx %l2, [%g1 + KTR_PARM2]
143 9:
144 #endif
145
146 /*
147 * If they are the same we are done.
148 */
149 cmp %l2, %i2
150 be,a,pn %xcc, 5f
151 nop
152
153 /*
154 * If the new process is a kernel thread we can just leave the old
155 * context active and avoid recycling its context number.
156 */
157 SET(vmspace0, %i4, %i3)
158 cmp %i5, %i3
159 be,a,pn %xcc, 5f
160 nop
161
162 /*
163 * If there was no non-kernel pmap, don't try to deactivate it.
164 */
165 brz,a,pn %l2, 3f
166 nop
167
168 /*
169 * Mark the pmap of the last non-kernel vmspace to run as no longer
170 * active on this cpu.
171 */
172 lduw [%l2 + PM_ACTIVE], %l3
173 lduw [PCPU(CPUMASK)], %l4
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 /*
187 * Find a new tlb context. If we've run out we have to flush all user
188 * mappings from the tlb and reset the context numbers.
189 */
190 3: lduw [PCPU(TLB_CTX)], %i3
191 lduw [PCPU(TLB_CTX_MAX)], %i4
192 cmp %i3, %i4
193 bne,a,pt %xcc, 4f
194 nop
195 SET(tlb_flush_user, %i5, %i4)
196 ldx [%i4], %i5
197 call %i5
198 nop
199 lduw [PCPU(TLB_CTX_MIN)], %i3
200
201 /*
202 * Advance next free context.
203 */
204 4: add %i3, 1, %i4
205 stw %i4, [PCPU(TLB_CTX)]
206
207 /*
208 * Set the new context number in the pmap.
209 */
210 lduw [PCPU(CPUID)], %i4
211 sllx %i4, INT_SHIFT, %i4
212 add %i2, PM_CONTEXT, %i5
213 stw %i3, [%i4 + %i5]
214
215 /*
216 * Mark the pmap as active on this cpu.
217 */
218 lduw [%i2 + PM_ACTIVE], %i4
219 lduw [PCPU(CPUMASK)], %i5
220 or %i4, %i5, %i4
221 stw %i4, [%i2 + PM_ACTIVE]
222
223 /*
224 * Make note of the change in pmap.
225 */
226 stx %i2, [PCPU(PMAP)]
227
228 /*
229 * Fiddle the hardware bits. Set the tsb registers and install the
230 * new context number in the cpu.
231 */
232 ldx [%i2 + PM_TSB], %i4
233 mov AA_DMMU_TSB, %i5
234 stxa %i4, [%i5] ASI_DMMU
235 mov AA_IMMU_TSB, %i5
236 stxa %i4, [%i5] ASI_IMMU
237 mov AA_DMMU_PCXR, %i5
238 stxa %i3, [%i5] ASI_DMMU
239 membar #Sync
240
241 /*
242 * Done. Return and load the new process's window from the stack.
243 */
244 5: ret
245 restore
246 END(cpu_switch)
247
248 ENTRY(savectx)
249 save %sp, -CCFSZ, %sp
250 flushw
251 call savefpctx
252 add %i0, PCB_UFP, %o0
253 stx %fp, [%i0 + PCB_SP]
254 stx %i7, [%i0 + PCB_PC]
255 ret
256 restore %g0, 0, %o0
257 END(savectx)
258
259 /*
260 * void savefpctx(uint32_t *);
261 */
262 ENTRY(savefpctx)
263 wr %g0, FPRS_FEF, %fprs
264 wr %g0, ASI_BLK_S, %asi
265 stda %f0, [%o0 + (0 * 64)] %asi
266 stda %f16, [%o0 + (1 * 64)] %asi
267 stda %f32, [%o0 + (2 * 64)] %asi
268 stda %f48, [%o0 + (3 * 64)] %asi
269 membar #Sync
270 retl
271 wr %g0, 0, %fprs
272 END(savefpctx)
Cache object: 1a438dba4f7fd29e031fdbe25d6ab39c
|