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/asi.h>
31 #include <machine/asmacros.h>
32 #include <machine/fsr.h>
33 #include <machine/hypervisorvar.h>
34 #include <machine/ktr.h>
35 #include <machine/pcb.h>
36 #include <machine/tstate.h>
40 .register %g2, #ignore
41 .register %g3, #ignore
45 #define MEMBAR_PRE membar #LoadStore|#StoreStore
46 #define MEMBAR_POST membar #LoadLoad
48 #define ATOMIC_CLEAR_INT_BIT(addr, old, bit, new, label) \
51 label: andn old, bit, new ; \
52 cas [addr], old, new ; \
54 bne,a,pn %icc, label ## b ; \
58 #define ATOMIC_SET_INT_BIT(addr, old, bit, new, label) \
61 label: or old, bit, new ; \
62 cas [addr], old, new ; \
64 bne,a,pn %icc, label ## b ; \
68 * void cpu_throw(struct thread *old, struct thread *new)
78 * void cpu_switch(struct thread *old, struct thread *new)
82 ldx [PCPU(CURPCB)], PCB_REG
86 * If the current thread was using floating point in the kernel, save
87 * its context. The userland floating point context has already been
91 andcc %l2, FPRS_FEF, %g0
95 add PCB_REG, PCB_KFP, %o0
100 * If the current thread was using floating point in userland, save
103 1: sub PCB_REG, TF_SIZEOF, %l2
104 ldx [%l2 + TF_FPRS], %l3
105 andcc %l3, FPRS_FEF, %g0
109 add PCB_REG, PCB_UFP, %o0
110 andn %l3, FPRS_FEF, %l3
111 stx %l3, [%l2 + TF_FPRS]
113 ldx [PCB_REG + PCB_FLAGS], %l3
115 stx %l3, [PCB_REG + PCB_FLAGS]
118 * Flush the windows out to the stack and save the current frame
119 * pointer and program counter.
122 stx %fp, [PCB_REG + PCB_SP]
123 stx %i7, [PCB_REG + PCB_PC]
127 * Load the new thread's frame pointer and program counter, and set
128 * the current thread and pcb.
131 #if KTR_COMPILE & KTR_PROC & 0
132 CATR(KTR_PROC, "cpu_switch: new td=%p pc=%#lx fp=%#lx"
133 , %g1, %g2, %g3, 7, 8, 9)
134 stx %i0, [%g1 + KTR_PARM1]
135 ldx [%i0 + TD_PCB], %g2
136 ldx [%g2 + PCB_PC], %g3
137 stx %g3, [%g1 + KTR_PARM2]
138 ldx [%g2 + PCB_SP], %g3
139 stx %g3, [%g1 + KTR_PARM3]
143 ldx [%i0 + TD_PCB], %i1
145 stx %i0, [PCPU(CURTHREAD)]
146 stx %i1, [PCPU(CURPCB)]
148 mov %i1, PCB_REG ! load in new PCB
150 ldx [PCB_REG + PCB_SP], %fp
151 ldx [PCB_REG + PCB_PC], %i7
155 * Point to the pmaps of the new process, and of the last non-kernel
158 ldx [%i0 + TD_PROC], %i2
159 ldx [PCPU(PMAP)], %l2
160 ldx [%i2 + P_VMSPACE], %i5
161 add %i5, VM_PMAP, %i2
163 #if KTR_COMPILE & KTR_PROC & 0
164 CATR(KTR_PROC, "cpu_switch: new pmap=%p old pmap=%p"
165 , %g1, %g2, %g3, 7, 8, 9)
166 stx %i2, [%g1 + KTR_PARM1]
167 stx %l2, [%g1 + KTR_PARM2]
171 * If they are the same we are done.
173 cmp %l2, %i2 ! current pmap == new pmap?
176 ldx [%i2 + PM_CONTEXT], %l5 ! new context
177 ldx [%l2 + PM_CONTEXT], %l3 ! old context
179 be,pn %xcc, 5f ! new context == kernel?
180 ld [PCPU(CPUMASK)], %l4
182 brz %l3, 10f ! old context == kernel?
186 * Mark the old pmap as no longer active on this CPU
188 add %l2, PM_ACTIVE, %l2
189 ATOMIC_CLEAR_INT_BIT(%l2, %l3, %l4, %l6, 8)
192 add %i2, PM_ACTIVE, %i3
193 ATOMIC_SET_INT_BIT(%i3, %l3, %l4, %l6, 11)
195 add %i2, PM_TLBACTIVE, %i3
196 ATOMIC_SET_INT_BIT(%i3, %l3, %l4, %l6, 12)
198 mov SCRATCH_REG_HASH_USER, %l6
199 mov SCRATCH_REG_TSB_USER, %l7
200 ldx [%i2 + PM_HASHSCRATCH], %l3
201 ldx [%i2 + PM_TSBSCRATCH], %l4
202 stx %i2, [PCPU(PMAP)]
204 SET_SCRATCH(%l6,%l3) ! XXX we're assuming the
205 SET_SCRATCH(%l7,%l4) ! scratch values <= 32 bits
208 ldx [%i2 + PM_TSB_RA], %l3
214 mov MMU_TSB_CTXNON0, %o5
223 * install the new secondary context number in the cpu.
226 SET_MMU_CONTEXT(%l6, %l5)
229 * Done. Return and load the new process's window from the stack.
236 save %sp, -CCFSZ, %sp
239 add %i0, PCB_UFP, %o0
240 stx %fp, [%i0 + PCB_SP]
241 stx %i7, [%i0 + PCB_PC]
247 * void savefpctx(uint32_t *);
250 wr %g0, FPRS_FEF, %fprs
251 std %f0, [%o0 + (0 * 64)]
252 std %f16, [%o0 + (1 * 64)]
253 std %f32, [%o0 + (2 * 64)]
254 std %f48, [%o0 + (3 * 64)]