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 user
190 * 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 mov AA_DMMU_PCXR, %i5
240 stxa %i3, [%i5] ASI_DMMU
241 membar #Sync
242
243 /*
244 * Done. Return and load the new process's window from the stack.
245 */
246 5: ret
247 restore
248 END(cpu_switch)
249
250 ENTRY(savectx)
251 save %sp, -CCFSZ, %sp
252 flushw
253 call savefpctx
254 add %i0, PCB_UFP, %o0
255 stx %fp, [%i0 + PCB_SP]
256 stx %i7, [%i0 + PCB_PC]
257 ret
258 restore %g0, 0, %o0
259 END(savectx)
260
261 /*
262 * void savefpctx(uint32_t *);
263 */
264 ENTRY(savefpctx)
265 wr %g0, FPRS_FEF, %fprs
266 wr %g0, ASI_BLK_S, %asi
267 stda %f0, [%o0 + (0 * 64)] %asi
268 stda %f16, [%o0 + (1 * 64)] %asi
269 stda %f32, [%o0 + (2 * 64)] %asi
270 stda %f48, [%o0 + (3 * 64)] %asi
271 membar #Sync
272 retl
273 wr %g0, 0, %fprs
274 END(savefpctx)
Cache object: c2c94911844014942b4fef5348831f9e
|