2 * Copyright (c) 2014 Andrew Turner
3 * Copyright (c) 2014 The FreeBSD Foundation
6 * This software was developed by Andrew Turner under sponsorship from
7 * the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include "opt_kstack_pages.h"
34 #include "opt_sched.h"
36 #include <machine/asm.h>
37 #include <machine/armreg.h>
38 .macro clear_step_flag pcbflags, tmp
39 tbz \pcbflags, #PCB_SINGLE_STEP_SHIFT, 999f
41 bic \tmp, \tmp, #MDSCR_SS
47 .macro set_step_flag pcbflags, tmp
48 tbz \pcbflags, #PCB_SINGLE_STEP_SHIFT, 999f
50 orr \tmp, \tmp, #MDSCR_SS
57 * void cpu_throw(struct thread *old, struct thread *new)
60 /* Of old == NULL skip disabling stepping */
63 /* If we were single stepping, disable it */
65 ldr w5, [x4, #PCB_FLAGS]
66 clear_step_flag w5, x6
70 /* Backup the new thread pointer around a call to C code */
78 /* This returns the thread pointer so no need to save it */
83 /* This returns the thread pcb */
87 /* Update the per-thread stack canary pointer. */
88 add x19, x19, #(TD_MD_CANARY)
92 /* If we are single stepping, enable it */
93 ldr w5, [x4, #PCB_FLAGS]
96 /* Restore the registers */
97 ldp x5, x6, [x4, #PCB_SP]
100 ldr x6, [x4, #PCB_TPIDRRO]
102 ldp x19, x20, [x4, #PCB_REGS + (PCB_X19 + 0) * 8]
103 ldp x21, x22, [x4, #PCB_REGS + (PCB_X19 + 2) * 8]
104 ldp x23, x24, [x4, #PCB_REGS + (PCB_X19 + 4) * 8]
105 ldp x25, x26, [x4, #PCB_REGS + (PCB_X19 + 6) * 8]
106 ldp x27, x28, [x4, #PCB_REGS + (PCB_X19 + 8) * 8]
107 ldp x29, lr, [x4, #PCB_REGS + (PCB_X19 + 10) * 8]
113 * void cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx)
118 * x3 to x7, x16 and x17 are caller saved
122 * Save the old context.
124 ldr x4, [x0, #TD_PCB]
126 /* Store the callee-saved registers */
127 stp x19, x20, [x4, #PCB_REGS + (PCB_X19 + 0) * 8]
128 stp x21, x22, [x4, #PCB_REGS + (PCB_X19 + 2) * 8]
129 stp x23, x24, [x4, #PCB_REGS + (PCB_X19 + 4) * 8]
130 stp x25, x26, [x4, #PCB_REGS + (PCB_X19 + 6) * 8]
131 stp x27, x28, [x4, #PCB_REGS + (PCB_X19 + 8) * 8]
132 stp x29, lr, [x4, #PCB_REGS + (PCB_X19 + 10) * 8]
133 /* And the old stack pointer */
136 str x6, [x4, #PCB_TPIDRRO]
138 stp x5, x6, [x4, #PCB_SP]
140 /* If we were single stepping, disable it */
141 ldr w5, [x4, #PCB_FLAGS]
142 clear_step_flag w5, x6
149 /* Load the pcb address */
157 /* This returns the thread pointer so no need to save it */
159 /* This returns the thread pcb */
161 /* Move the new pcb out of the way */
168 /* Update the per-thread stack canary pointer. */
169 add x20, x20, #(TD_MD_CANARY)
174 * Release the old thread.
176 stlr x2, [x0, #TD_LOCK]
177 #if defined(SCHED_ULE) && defined(SMP)
178 /* Spin if TD_LOCK points to a blocked_lock */
179 ldr x2, =_C_LABEL(blocked_lock)
181 ldar x3, [x1, #TD_LOCK]
186 /* If we are single stepping, enable it */
187 ldr w5, [x4, #PCB_FLAGS]
190 /* Restore the registers */
191 ldp x5, x6, [x4, #PCB_SP]
194 ldr x6, [x4, #PCB_TPIDRRO]
196 ldp x19, x20, [x4, #PCB_REGS + (PCB_X19 + 0) * 8]
197 ldp x21, x22, [x4, #PCB_REGS + (PCB_X19 + 2) * 8]
198 ldp x23, x24, [x4, #PCB_REGS + (PCB_X19 + 4) * 8]
199 ldp x25, x26, [x4, #PCB_REGS + (PCB_X19 + 6) * 8]
200 ldp x27, x28, [x4, #PCB_REGS + (PCB_X19 + 8) * 8]
201 ldp x29, lr, [x4, #PCB_REGS + (PCB_X19 + 10) * 8]
206 ENTRY(fork_trampoline)
210 mov fp, #0 /* Stack traceback stops here. */
211 bl _C_LABEL(fork_exit)
214 * Disable interrupts as we are setting userspace specific
215 * state that we won't handle correctly in an interrupt while
218 msr daifset, #(DAIF_D | DAIF_INTR)
220 ldr x0, [x18, #PC_CURTHREAD]
223 /* Restore sp, lr, elr, and spsr */
224 ldp x18, lr, [sp, #TF_SP]
225 ldp x10, x11, [sp, #TF_ELR]
230 /* Restore the CPU registers */
231 ldp x0, x1, [sp, #TF_X + 0 * 8]
232 ldp x2, x3, [sp, #TF_X + 2 * 8]
233 ldp x4, x5, [sp, #TF_X + 4 * 8]
234 ldp x6, x7, [sp, #TF_X + 6 * 8]
235 ldp x8, x9, [sp, #TF_X + 8 * 8]
236 ldp x10, x11, [sp, #TF_X + 10 * 8]
237 ldp x12, x13, [sp, #TF_X + 12 * 8]
238 ldp x14, x15, [sp, #TF_X + 14 * 8]
239 ldp x16, x17, [sp, #TF_X + 16 * 8]
240 ldp x18, x19, [sp, #TF_X + 18 * 8]
241 ldp x20, x21, [sp, #TF_X + 20 * 8]
242 ldp x22, x23, [sp, #TF_X + 22 * 8]
243 ldp x24, x25, [sp, #TF_X + 24 * 8]
244 ldp x26, x27, [sp, #TF_X + 26 * 8]
245 ldp x28, x29, [sp, #TF_X + 28 * 8]
248 * No need for interrupts reenabling since PSR
249 * will be set to the desired value anyway.
256 /* Store the callee-saved registers */
257 stp x19, x20, [x0, #PCB_REGS + (PCB_X19 + 0) * 8]
258 stp x21, x22, [x0, #PCB_REGS + (PCB_X19 + 2) * 8]
259 stp x23, x24, [x0, #PCB_REGS + (PCB_X19 + 4) * 8]
260 stp x25, x26, [x0, #PCB_REGS + (PCB_X19 + 6) * 8]
261 stp x27, x28, [x0, #PCB_REGS + (PCB_X19 + 8) * 8]
262 stp x29, lr, [x0, #PCB_REGS + (PCB_X19 + 10) * 8]
263 /* And the old stack pointer */
266 str x6, [x0, #PCB_TPIDRRO]
268 stp x5, x6, [x0, #PCB_SP]
270 /* Store the VFP registers */
273 mov x1, x0 /* move pcb to the correct register */
274 mov x0, xzr /* td = NULL */