1/*- 2 * Copyright (c) 2014 Andrew Turner 3 * Copyright (c) 2014 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * This software was developed by Andrew Turner under sponsorship from 7 * the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 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. 17 * 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 28 * SUCH DAMAGE. 29 * 30 */ 31 32#include "assym.inc" 33#include "opt_kstack_pages.h" 34#include "opt_sched.h" 35 36#include <machine/asm.h> 37 38__FBSDID("$FreeBSD$"); 39 40.macro clear_step_flag pcbflags, tmp 41 tbz \pcbflags, #PCB_SINGLE_STEP_SHIFT, 999f 42 mrs \tmp, mdscr_el1 43 bic \tmp, \tmp, #1 44 msr mdscr_el1, \tmp 45 isb 46999: 47.endm 48 49.macro set_step_flag pcbflags, tmp 50 tbz \pcbflags, #PCB_SINGLE_STEP_SHIFT, 999f 51 mrs \tmp, mdscr_el1 52 orr \tmp, \tmp, #1 53 msr mdscr_el1, \tmp 54 isb 55999: 56.endm 57 58/* 59 * void cpu_throw(struct thread *old, struct thread *new) 60 */ 61ENTRY(cpu_throw) 62 /* Of old == NULL skip disabling stepping */ 63 cbz x0, 1f 64 65 /* If we were single stepping, disable it */ 66 ldr x4, [x0, #TD_PCB] 67 ldr w5, [x4, #PCB_FLAGS] 68 clear_step_flag w5, x6 691: 70 71#ifdef VFP 72 /* Backup the new thread pointer around a call to C code */ 73 mov x19, x0 74 mov x20, x1 75 bl vfp_discard 76 mov x1, x20 77 mov x0, x19 78#endif 79 80 bl pmap_switch 81 mov x4, x0 82 83 /* If we are single stepping, enable it */ 84 ldr w5, [x4, #PCB_FLAGS] 85 set_step_flag w5, x6 86 87 /* Restore the registers */ 88 ldp x5, x6, [x4, #PCB_SP] 89 mov sp, x5 90 msr tpidr_el0, x6 91 ldr x6, [x4, #PCB_TPIDRRO] 92 msr tpidrro_el0, x6 93 ldp x8, x9, [x4, #PCB_REGS + 8 * 8] 94 ldp x10, x11, [x4, #PCB_REGS + 10 * 8] 95 ldp x12, x13, [x4, #PCB_REGS + 12 * 8] 96 ldp x14, x15, [x4, #PCB_REGS + 14 * 8] 97 ldp x16, x17, [x4, #PCB_REGS + 16 * 8] 98 ldr x19, [x4, #PCB_REGS + 19 * 8] 99 ldp x20, x21, [x4, #PCB_REGS + 20 * 8] 100 ldp x22, x23, [x4, #PCB_REGS + 22 * 8] 101 ldp x24, x25, [x4, #PCB_REGS + 24 * 8] 102 ldp x26, x27, [x4, #PCB_REGS + 26 * 8] 103 ldp x28, x29, [x4, #PCB_REGS + 28 * 8] 104 ldr x30, [x4, #PCB_REGS + 30 * 8] 105 106 ret 107END(cpu_throw) 108 109/* 110 * void cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx) 111 * 112 * x0 = old 113 * x1 = new 114 * x2 = mtx 115 * x3 to x7, x16 and x17 are caller saved 116 */ 117ENTRY(cpu_switch) 118 /* 119 * Save the old context. 120 */ 121 ldr x4, [x0, #TD_PCB] 122 123 /* Store the callee-saved registers */ 124 stp x8, x9, [x4, #PCB_REGS + 8 * 8] 125 stp x10, x11, [x4, #PCB_REGS + 10 * 8] 126 stp x12, x13, [x4, #PCB_REGS + 12 * 8] 127 stp x14, x15, [x4, #PCB_REGS + 14 * 8] 128 stp x16, x17, [x4, #PCB_REGS + 16 * 8] 129 stp x18, x19, [x4, #PCB_REGS + 18 * 8] 130 stp x20, x21, [x4, #PCB_REGS + 20 * 8] 131 stp x22, x23, [x4, #PCB_REGS + 22 * 8] 132 stp x24, x25, [x4, #PCB_REGS + 24 * 8] 133 stp x26, x27, [x4, #PCB_REGS + 26 * 8] 134 stp x28, x29, [x4, #PCB_REGS + 28 * 8] 135 str x30, [x4, #PCB_REGS + 30 * 8] 136 /* And the old stack pointer */ 137 mov x5, sp 138 mrs x6, tpidrro_el0 139 str x6, [x4, #PCB_TPIDRRO] 140 mrs x6, tpidr_el0 141 stp x5, x6, [x4, #PCB_SP] 142 143 /* If we were single stepping, disable it */ 144 ldr w5, [x4, #PCB_FLAGS] 145 clear_step_flag w5, x6 146 147 mov x19, x0 148 mov x20, x1 149 mov x21, x2 150 151#ifdef VFP 152 /* Load the pcb address */ 153 mov x1, x4 154 bl vfp_save_state 155 mov x1, x20 156 mov x0, x19 157#endif 158 159 bl pmap_switch 160 /* Move the new pcb out of the way */ 161 mov x4, x0 162 163 mov x2, x21 164 mov x1, x20 165 mov x0, x19 166 167 /* 168 * Release the old thread. This doesn't need to be a store-release 169 * as the above dsb instruction will provide release semantics. 170 */ 171 str x2, [x0, #TD_LOCK] 172#if defined(SCHED_ULE) && defined(SMP) 173 /* Spin if TD_LOCK points to a blocked_lock */ 174 ldr x2, =_C_LABEL(blocked_lock) 1751: 176 ldar x3, [x1, #TD_LOCK] 177 cmp x3, x2 178 b.eq 1b 179#endif 180 181 /* If we are single stepping, enable it */ 182 ldr w5, [x4, #PCB_FLAGS] 183 set_step_flag w5, x6 184 185 /* Restore the registers */ 186 ldp x5, x6, [x4, #PCB_SP] 187 mov sp, x5 188 msr tpidr_el0, x6 189 ldr x6, [x4, #PCB_TPIDRRO] 190 msr tpidrro_el0, x6 191 ldp x8, x9, [x4, #PCB_REGS + 8 * 8] 192 ldp x10, x11, [x4, #PCB_REGS + 10 * 8] 193 ldp x12, x13, [x4, #PCB_REGS + 12 * 8] 194 ldp x14, x15, [x4, #PCB_REGS + 14 * 8] 195 ldp x16, x17, [x4, #PCB_REGS + 16 * 8] 196 ldr x19, [x4, #PCB_REGS + 19 * 8] 197 ldp x20, x21, [x4, #PCB_REGS + 20 * 8] 198 ldp x22, x23, [x4, #PCB_REGS + 22 * 8] 199 ldp x24, x25, [x4, #PCB_REGS + 24 * 8] 200 ldp x26, x27, [x4, #PCB_REGS + 26 * 8] 201 ldp x28, x29, [x4, #PCB_REGS + 28 * 8] 202 ldr x30, [x4, #PCB_REGS + 30 * 8] 203 204 str xzr, [x4, #PCB_REGS + 18 * 8] 205 ret 206.Lcpu_switch_panic_str: 207 .asciz "cpu_switch: %p\0" 208END(cpu_switch) 209 210ENTRY(fork_trampoline) 211 mov x0, x8 212 mov x1, x9 213 mov x2, sp 214 mov fp, #0 /* Stack traceback stops here. */ 215 bl _C_LABEL(fork_exit) 216 217 /* Restore the registers other than x0 and x1 */ 218 ldp x2, x3, [sp, #TF_X + 2 * 8] 219 ldp x4, x5, [sp, #TF_X + 4 * 8] 220 ldp x6, x7, [sp, #TF_X + 6 * 8] 221 ldp x8, x9, [sp, #TF_X + 8 * 8] 222 ldp x10, x11, [sp, #TF_X + 10 * 8] 223 ldp x12, x13, [sp, #TF_X + 12 * 8] 224 ldp x14, x15, [sp, #TF_X + 14 * 8] 225 ldp x16, x17, [sp, #TF_X + 16 * 8] 226 ldr x19, [sp, #TF_X + 19 * 8] 227 ldp x20, x21, [sp, #TF_X + 20 * 8] 228 ldp x22, x23, [sp, #TF_X + 22 * 8] 229 ldp x24, x25, [sp, #TF_X + 24 * 8] 230 ldp x26, x27, [sp, #TF_X + 26 * 8] 231 ldp x28, x29, [sp, #TF_X + 28 * 8] 232 233 /* 234 * Disable interrupts to avoid 235 * overwriting spsr_el1 and sp_el0 by an IRQ exception. 236 */ 237 msr daifset, #2 238 239 /* Restore sp and lr */ 240 ldp x0, x1, [sp] 241 msr sp_el0, x0 242 mov lr, x1 243 244 /* Restore elr and spsr */ 245 ldp x0, x1, [sp, #16] 246 msr elr_el1, x0 247 msr spsr_el1, x1 248 249 /* Finally x0 and x1 */ 250 ldp x0, x1, [sp, #TF_X + 0 * 8] 251 ldr x18, [sp, #TF_X + 18 * 8] 252 253 /* 254 * No need for interrupts reenabling since PSR 255 * will be set to the desired value anyway. 256 */ 257 eret 258 259END(fork_trampoline) 260 261ENTRY(savectx) 262 /* Store the callee-saved registers */ 263 stp x8, x9, [x0, #PCB_REGS + 8 * 8] 264 stp x10, x11, [x0, #PCB_REGS + 10 * 8] 265 stp x12, x13, [x0, #PCB_REGS + 12 * 8] 266 stp x14, x15, [x0, #PCB_REGS + 14 * 8] 267 stp x16, x17, [x0, #PCB_REGS + 16 * 8] 268 stp x18, x19, [x0, #PCB_REGS + 18 * 8] 269 stp x20, x21, [x0, #PCB_REGS + 20 * 8] 270 stp x22, x23, [x0, #PCB_REGS + 22 * 8] 271 stp x24, x25, [x0, #PCB_REGS + 24 * 8] 272 stp x26, x27, [x0, #PCB_REGS + 26 * 8] 273 stp x28, x29, [x0, #PCB_REGS + 28 * 8] 274 str x30, [x0, #PCB_REGS + 30 * 8] 275 /* And the old stack pointer */ 276 mov x5, sp 277 mrs x6, tpidrro_el0 278 str x6, [x0, #PCB_TPIDRRO] 279 mrs x6, tpidr_el0 280 stp x5, x6, [x0, #PCB_SP] 281 282 /* Store the VFP registers */ 283#ifdef VFP 284 mov x28, lr 285 mov x1, x0 /* move pcb to the correct register */ 286 mov x0, xzr /* td = NULL */ 287 bl vfp_save_state 288 mov lr, x28 289#endif 290 291 ret 292END(savectx) 293 294