1/* $NetBSD: switch_subr.s,v 1.38 2024/10/31 07:30:28 isaki Exp $ */ 2 3/* 4 * Copyright (c) 2001 The NetBSD Foundation. 5 * Copyright (c) 1988 University of Utah. 6 * Copyright (c) 1980, 1990, 1993 7 * The Regents of the University of California. All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * the Systems Programming Group of the University of Utah Computer 11 * Science Department. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * Split from: Utah $Hdr: locore.s 1.66 92/12/22$ 38 */ 39 40#include "opt_fpu_emulate.h" 41#include "opt_lockdebug.h" 42#include "opt_pmap_debug.h" 43#include "opt_m68k_arch.h" 44 45/* 46 * NOTICE: This is not a standalone file. To use it, #include it in 47 * your port's locore.s, like so: 48 * 49 * #include <m68k/m68k/switch_subr.s> 50 * 51 * If your port uses one or more non-motorola FPU devices, you must use: 52 * 53 * #define _M68K_CUSTOM_FPU_CTX 1 54 * 55 * before including this file. In this case, you must also provide 56 * two assembly sub-routines for saving and restoring FPU context: 57 * 58 * ASENTRY(m68k_fpuctx_save) 59 * %a1 -> The PCB of the outgoing thread where fpu state should be saved 60 * 61 * %a0 and %a1 must be preserved across the call, but all other 62 * registers are available for use. 63 * 64 * ASENTRY(m68k_fpuctx_restore) 65 * %a1 -> The PCB of the incoming thread where fpu state is saved 66 * 67 * All registers except %d0, %d1 and %a0 must be preserved across 68 * the call. 69 */ 70 71 .data 72GLOBAL(curpcb) 73GLOBAL(masterpaddr) | XXXcompatibility (debuggers) 74 .long 0 75 76/* 77 * When no processes are on the runq, Swtch branches to Idle 78 * to wait for something to come ready. 79 */ 80ASENTRY_NOPROFILE(cpu_idle) 81 stop #PSL_LOWIPL 82GLOBAL(_Idle) /* For sun2/sun3's clock.c ... */ 83 rts 84 85/* 86 * struct lwp *cpu_switchto(struct lwp *oldlwp, struct lwp *newlwp) 87 * 88 * Switch to the specific next LWP. 89 */ 90ENTRY(cpu_switchto) 91 movl 4(%sp),%a1 | fetch outgoing lwp 92 /* 93 * Save state of previous process in its pcb. 94 */ 95 movl L_PCB(%a1),%a1 96 moveml %d2-%d7/%a2-%a7,PCB_REGS(%a1) | save non-scratch registers 97 movl %usp,%a2 | grab USP (a2 has been saved) 98 movl %a2,PCB_USP(%a1) | and save it 99 100#ifdef _M68K_CUSTOM_FPU_CTX 101 jbsr _ASM_LABEL(m68k_fpuctx_save) 102#else 103#ifdef FPCOPROC 104 tstl _C_LABEL(fputype) | Do we have an FPU? 105 jeq .Lcpu_switch_nofpsave | No Then don't attempt save. 106 107 lea PCB_FPCTX(%a1),%a2 | pointer to FP save area 108 fsave (%a2) | save FP state 109#if defined(M68020) || defined(M68030) || defined(M68040) 110#if defined(M68060) 111 cmpl #FPU_68060,_C_LABEL(fputype) 112 jeq .Lcpu_switch_savfp60 113#endif 114 tstb (%a2) | null state frame? 115 jeq .Lcpu_switch_nofpsave | yes, all done 116 fmovem %fp0-%fp7,FPF_REGS(%a2) | save FP general registers 117 fmovem %fpcr/%fpsr/%fpi,FPF_FPCR(%a2) | save FP control registers 118#if defined(M68060) 119 jra .Lcpu_switch_nofpsave 120#endif 121#endif 122#if defined(M68060) 123.Lcpu_switch_savfp60: 124 tstb 2(%a2) | null state frame? 125 jeq .Lcpu_switch_nofpsave | yes, all done 126 fmovem %fp0-%fp7,FPF_REGS(%a2) | save FP general registers 127 fmovem %fpcr,FPF_FPCR(%a2) | save FP control registers 128 fmovem %fpsr,FPF_FPSR(%a2) 129 fmovem %fpi,FPF_FPI(%a2) 130#endif 131.Lcpu_switch_nofpsave: 132#endif /* FPCOPROC */ 133#endif /* !_M68K_CUSTOM_FPU_CTX */ 134 135 movl 8(%sp),%a0 | get newlwp 136 movl %a0,_C_LABEL(curlwp) | curlwp = new lwp 137 movl L_PCB(%a0),%a1 | get its pcb 138 movl %a1,_C_LABEL(curpcb) | curpcb = new pcb 139 140 /* 141 * Check for restartable atomic sequences (RAS) 142 */ 143 movl L_PROC(%a0),%a2 144 tstl P_RASLIST(%a2) | p->p_raslist == NULL? 145 jeq 2f | yes, skip it. 146 movl L_MD_REGS(%a0),%a1 147 movl TF_PC(%a1),-(%sp) | push return PC 148 movl %a2,-(%sp) | push proc 149 jbsr _C_LABEL(ras_lookup) | a0 = ras_lookup(p, pc) 150 addql #8,%sp 151 movql #-1,%d0 152 cmpl %a0,%d0 | a0 == -1? 153 jeq 1f | yes, skip it. 154 movl _C_LABEL(curlwp),%a1 155 movl L_MD_REGS(%a1),%a1 156 movl %a0,TF_PC(%a1) | fixup return PC 1571: 158 movl _C_LABEL(curlwp),%a0 | recover new lwp 159 movl _C_LABEL(curpcb),%a1 | recover new pcb 1602: 161 movl %a0,%d0 | free up %a0 162 movl 4(%sp),%d1 | get oldlwp for return value 163 lea _ASM_LABEL(tmpstk),%sp | switch to tmp stack in case of NMI 164 165 moveml PCB_REGS(%a1),%d2-%d7/%a2-%a7 | restore registers 166 movl PCB_USP(%a1),%a0 167 movl %a0,%usp | and USP 168 169#ifdef _M68K_CUSTOM_FPU_CTX 170 moveml %d0/%d1,-(%sp) 171 jbsr _ASM_LABEL(m68k_fpuctx_restore) 172 moveml (%sp)+,%d0/%d1 173#else 174#ifdef FPCOPROC 175 tstl _C_LABEL(fputype) | Do we have an FPU? 176 jeq .Lcpu_switch_nofprest | No Then don't attempt restore. 177 178 lea PCB_FPCTX(%a1),%a0 | pointer to FP save area 179#if defined(M68020) || defined(M68030) || defined(M68040) 180#if defined(M68060) 181 cmpl #FPU_68060,_C_LABEL(fputype) 182 jeq .Lcpu_switch_resfp60rest1 183#endif 184 tstb (%a0) | null state frame? 185 jeq .Lcpu_switch_resfprest | yes, easy 186 fmovem FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers 187 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 188#if defined(M68060) 189 jra .Lcpu_switch_resfprest 190#endif 191#endif 192 193#if defined(M68060) 194.Lcpu_switch_resfp60rest1: 195 tstb 2(%a0) | null state frame? 196 jeq .Lcpu_switch_resfprest | yes, easy 197 fmovem FPF_FPCR(%a0),%fpcr | restore FP control registers 198 fmovem FPF_FPSR(%a0),%fpsr 199 fmovem FPF_FPI(%a0),%fpi 200 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 201#endif 202.Lcpu_switch_resfprest: 203 frestore (%a0) | restore state 204#endif /* FPCOPROC */ 205#endif /* !_M68K_CUSTOM_FPU_CTX */ 206 207.Lcpu_switch_nofprest: 208 movl %d1,%d0 | return outgoing lwp 209 movl %d0,%a0 | (in a0, too) 210 rts 211 212/* 213 * savectx(pcb) 214 * Update pcb, saving current processor state. 215 */ 216ENTRY(savectx) 217 movl 4(%sp),%a1 218 movw %sr,PCB_PS(%a1) 219 movl %usp,%a0 | grab USP 220 movl %a0,PCB_USP(%a1) | and save it 221 moveml %d2-%d7/%a2-%a7,PCB_REGS(%a1) | save non-scratch registers 222 223#ifdef _M68K_CUSTOM_FPU_CTX 224 jbsr _ASM_LABEL(m68k_fpuctx_save) 225#else 226#ifdef FPCOPROC 227 tstl _C_LABEL(fputype) | Do we have FPU? 228 jeq .Lsavectx_nofpsave | No? Then don't save state. 229 230 lea PCB_FPCTX(%a1),%a0 | pointer to FP save area 231 fsave (%a0) | save FP state 232#if defined(M68020) || defined(M68030) || defined(M68040) 233#if defined(M68060) 234 cmpl #FPU_68060,_C_LABEL(fputype) 235 jeq .Lsavectx_savfp60 236#endif 237 tstb (%a0) | null state frame? 238 jeq .Lsavectx_nofpsave | yes, all done 239 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 240 fmovem %fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers 241#if defined(M68060) 242 jra .Lsavectx_nofpsave 243#endif 244#endif 245#if defined(M68060) 246.Lsavectx_savfp60: 247 tstb 2(%a0) | null state frame? 248 jeq .Lsavectx_nofpsave | yes, all done 249 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 250 fmovem %fpcr,FPF_FPCR(%a0) | save FP control registers 251 fmovem %fpsr,FPF_FPSR(%a0) 252 fmovem %fpi,FPF_FPI(%a0) 253#endif 254.Lsavectx_nofpsave: 255#endif /* FPCOPROC */ 256#endif /* !_M68K_CUSTOM_FPU_CTX */ 257 moveq #0,%d0 | return 0 258 rts 259 260#if !defined(M68010) 261/* 262 * void m68k_make_fpu_idle_frame(void) 263 * 264 * On machines with an FPU, generate an "idle" state frame to be 265 * used by cpu_setmcontext(). 266 * 267 * Before calling, make sure the machine actually has an FPU ... 268 */ 269ENTRY(m68k_make_fpu_idle_frame) 270 clrl -(%sp) 271 fnop 272 273 frestore (%sp) | Effectively `resets' the FPU 274 fnop 275 276 /* Loading '0.0' will change FPU to "idle". */ 277 fmove.d #0,%fp0 278 fnop 279 280 /* Save the resulting idle frame into the buffer */ 281 lea _C_LABEL(m68k_cached_fpu_idle_frame),%a0 282 fsave (%a0) 283 fnop 284 285 /* Reset the FPU again */ 286 frestore (%sp) 287 fnop 288 addql #4,%sp 289 rts 290#endif 291 292/* 293 * Save and restore 68881 state. 294 */ 295#ifdef FPCOPROC 296ENTRY(m68881_save) 297 movl 4(%sp),%a0 | save area pointer 298 fsave (%a0) | save state 299#if defined(M68020) || defined(M68030) || defined(M68040) 300#if defined(M68060) 301 cmpl #FPU_68060,_C_LABEL(fputype) 302 jeq .Lm68060fpsave 303#endif 304.Lm68881fpsave: 305 tstb (%a0) | null state frame? 306 jeq .Lm68881sdone | yes, all done 307 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 308 fmovem %fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers 309.Lm68881sdone: 310 rts 311#endif 312#if defined(M68060) 313.Lm68060fpsave: 314 tstb 2(%a0) | null state frame? 315 jeq .Lm68060sdone | yes, all done 316 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 317 fmovem %fpcr,FPF_FPCR(%a0) | save FP control registers 318 fmovem %fpsr,FPF_FPSR(%a0) 319 fmovem %fpi,FPF_FPI(%a0) 320.Lm68060sdone: 321 rts 322#endif 323 324ENTRY(m68881_restore) 325 movl 4(%sp),%a0 | save area pointer 326#if defined(M68020) || defined(M68030) || defined(M68040) 327#if defined(M68060) 328 cmpl #FPU_68060,_C_LABEL(fputype) 329 jeq .Lm68060fprestore 330#endif 331.Lm68881fprestore: 332 tstb (%a0) | null state frame? 333 jeq .Lm68881rdone | yes, easy 334 fmovem FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers 335 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 336.Lm68881rdone: 337 frestore (%a0) | restore state 338 rts 339#endif 340#if defined(M68060) 341.Lm68060fprestore: 342 tstb 2(%a0) | null state frame? 343 jeq .Lm68060fprdone | yes, easy 344 fmovem FPF_FPCR(%a0),%fpcr | restore FP control registers 345 fmovem FPF_FPSR(%a0),%fpsr 346 fmovem FPF_FPI(%a0),%fpi 347 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 348.Lm68060fprdone: 349 frestore (%a0) | restore state 350 rts 351#endif 352#endif 353 354/* 355 * lwp_trampoline: call function in register %a2 with %a3 as an arg 356 * and then rei. 357 * %a0 will have old lwp from cpu_switchto(), and %a4 is new lwp 358 */ 359ENTRY_NOPROFILE(lwp_trampoline) 360 movl %a4,-(%sp) | new lwp 361 movl %a0,-(%sp) | old lpw 362 jbsr _C_LABEL(lwp_startup) 363 addql #8,%sp 364 movl %a3,-(%sp) | push function arg 365 jbsr (%a2) | call function 366 addql #4,%sp | pop arg 367 movl FR_SP(%sp),%a0 | grab and load 368 movl %a0,%usp | user SP 369 moveml (%sp)+,#0x7FFF | restore most user regs 370 addql #8,%sp | toss SP and stack adjust 371 jra _ASM_LABEL(rei) | and return 372