2 * Copyright (c) 2001 Jake Burkholder.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <machine/asm.h>
28 __FBSDID("$FreeBSD$");
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>
39 .register %g2, #ignore
40 .register %g3, #ignore
43 * void cpu_throw(struct thread *old, struct thread *new)
53 * void cpu_switch(struct thread *old, struct thread *new)
60 * If the current thread was using floating point in the kernel, save
61 * its context. The userland floating point context has already been
65 andcc %l2, FPRS_FEF, %g0
69 add PCB_REG, PCB_KFP, %o0
74 * If the current thread was using floating point in userland, save
77 1: sub PCB_REG, TF_SIZEOF, %l2
78 ldx [%l2 + TF_FPRS], %l3
79 andcc %l3, FPRS_FEF, %g0
83 add PCB_REG, PCB_UFP, %o0
84 andn %l3, FPRS_FEF, %l3
85 stx %l3, [%l2 + TF_FPRS]
87 ldx [PCB_REG + PCB_FLAGS], %l3
89 stx %l3, [PCB_REG + PCB_FLAGS]
92 * Flush the windows out to the stack and save the current frame
93 * pointer and program counter.
96 wrpr %g0, 0, %cleanwin
97 stx %fp, [PCB_REG + PCB_SP]
98 stx %i7, [PCB_REG + PCB_PC]
101 * Load the new thread's frame pointer and program counter, and set
102 * the current thread and pcb.
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]
116 ldx [%i0 + TD_PCB], %i1
118 stx %i0, [PCPU(CURTHREAD)]
119 stx %i1, [PCPU(CURPCB)]
121 wrpr %g0, PSTATE_NORMAL, %pstate
123 wrpr %g0, PSTATE_ALT, %pstate
125 wrpr %g0, PSTATE_KERNEL, %pstate
127 ldx [PCB_REG + PCB_SP], %fp
128 ldx [PCB_REG + PCB_PC], %i7
132 * Point to the pmaps of the new process, and of the last non-kernel
135 ldx [%i0 + TD_PROC], %i2
136 ldx [PCPU(PMAP)], %l2
137 ldx [%i2 + P_VMSPACE], %i5
138 add %i5, VM_PMAP, %i2
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]
149 * If they are the same we are done.
156 * If the new process is a kernel thread we can just leave the old
157 * context active and avoid recycling its context number.
159 SET(vmspace0, %i4, %i3)
165 * If there was no non-kernel pmap, don't try to deactivate it.
171 * Mark the pmap of the last non-kernel vmspace to run as no longer
172 * active on this cpu.
174 lduw [%l2 + PM_ACTIVE], %l3
175 lduw [PCPU(CPUMASK)], %l4
177 stw %l3, [%l2 + PM_ACTIVE]
180 * Take away its context number.
182 lduw [PCPU(CPUID)], %l3
183 sllx %l3, INT_SHIFT, %l3
184 add %l2, PM_CONTEXT, %l4
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.
192 3: lduw [PCPU(TLB_CTX)], %i3
193 lduw [PCPU(TLB_CTX_MAX)], %i4
197 SET(tlb_flush_user, %i5, %i4)
201 lduw [PCPU(TLB_CTX_MIN)], %i3
204 * Advance next free context.
207 stw %i4, [PCPU(TLB_CTX)]
210 * Set the new context number in the pmap.
212 lduw [PCPU(CPUID)], %i4
213 sllx %i4, INT_SHIFT, %i4
214 add %i2, PM_CONTEXT, %i5
218 * Mark the pmap as active on this cpu.
220 lduw [%i2 + PM_ACTIVE], %i4
221 lduw [PCPU(CPUMASK)], %i5
223 stw %i4, [%i2 + PM_ACTIVE]
226 * Make note of the change in pmap.
228 stx %i2, [PCPU(PMAP)]
231 * Fiddle the hardware bits. Set the tsb registers and install the
232 * new context number in the cpu.
234 ldx [%i2 + PM_TSB], %i4
236 stxa %i4, [%i5] ASI_DMMU
238 stxa %i4, [%i5] ASI_IMMU
239 mov AA_DMMU_PCXR, %i5
240 stxa %i3, [%i5] ASI_DMMU
244 * Done. Return and load the new process's window from the stack.
251 save %sp, -CCFSZ, %sp
254 add %i0, PCB_UFP, %o0
255 stx %fp, [%i0 + PCB_SP]
256 stx %i7, [%i0 + PCB_PC]
262 * void savefpctx(uint32_t *);
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