1 /* $NetBSD: switch_subr.s,v 1.46 2026/03/29 13:41:37 thorpej 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 #include <machine/asm.h> 46 47 #include "assym.h" 48 49 .file "switch_subr.s" 50 .text 51 52 .data 53 GLOBAL(curpcb) 54 GLOBAL(masterpaddr) | XXXcompatibility (debuggers) 55 .long 0 56 57 /* 58 * When no processes are on the runq, Swtch branches to Idle 59 * to wait for something to come ready. 60 */ 61 ASENTRY_NOPROFILE(cpu_idle) 62 stop #PSL_LOWIPL 63 GLOBAL(_Idle) /* For sun2/sun3's clock.c ... */ 64 rts 65 66 /* 67 * struct lwp *cpu_switchto(struct lwp *oldlwp, struct lwp *newlwp) 68 * 69 * Switch to the specific next LWP. 70 */ 71 ENTRY(cpu_switchto) 72 movl 4(%sp),%a1 | fetch outgoing lwp 73 /* 74 * Save state of previous process in its pcb. 75 */ 76 movl L_PCB(%a1),%a1 77 moveml %d2-%d7/%a2-%a7,PCB_REGS(%a1) | save non-scratch registers 78 movl %usp,%a2 | grab USP (a2 has been saved) 79 movl %a2,PCB_USP(%a1) | and save it 80 81 #ifdef M68K_FPCOPROC 82 tstl _C_LABEL(fputype) | Do we have an FPU? 83 jeq .Lcpu_switch_nofpsave | No Then don't attempt save. 84 85 lea PCB_FPCTX(%a1),%a2 | pointer to FP save area 86 fsave (%a2) | save FP state 87 #if defined(M68020) || defined(M68030) || defined(M68040) 88 #if defined(M68060) 89 cmpl #FPU_68060,_C_LABEL(fputype) 90 jeq .Lcpu_switch_savfp60 91 #endif 92 tstb (%a2) | null state frame? 93 jeq .Lcpu_switch_nofpsave | yes, all done 94 fmovem %fp0-%fp7,FPF_REGS(%a2) | save FP general registers 95 fmovem %fpcr/%fpsr/%fpi,FPF_FPCR(%a2) | save FP control registers 96 #if defined(M68060) 97 jra .Lcpu_switch_nofpsave 98 #endif 99 #endif 100 #if defined(M68060) 101 .Lcpu_switch_savfp60: 102 tstb 2(%a2) | null state frame? 103 jeq .Lcpu_switch_nofpsave | yes, all done 104 fmovem %fp0-%fp7,FPF_REGS(%a2) | save FP general registers 105 fmovem %fpcr,FPF_FPCR(%a2) | save FP control registers 106 fmovem %fpsr,FPF_FPSR(%a2) 107 fmovem %fpi,FPF_FPI(%a2) 108 #endif 109 .Lcpu_switch_nofpsave: 110 #endif /* M68K_FPCOPROC */ 111 112 movl 8(%sp),%a0 | get newlwp 113 movl %a0,_C_LABEL(curlwp) | curlwp = new lwp 114 movl L_PCB(%a0),%a1 | get its pcb 115 movl %a1,_C_LABEL(curpcb) | curpcb = new pcb 116 117 /* 118 * Check for restartable atomic sequences (RAS) 119 */ 120 movl L_PROC(%a0),%a2 121 tstl P_RASLIST(%a2) | p->p_raslist == NULL? 122 jeq 2f | yes, skip it. 123 movl L_MD_REGS(%a0),%a1 124 movl TF_PC(%a1),-(%sp) | push return PC 125 movl %a2,-(%sp) | push proc 126 jbsr _C_LABEL(ras_lookup) | a0 = ras_lookup(p, pc) 127 addql #8,%sp 128 movql #-1,%d0 129 cmpl %a0,%d0 | a0 == -1? 130 jeq 1f | yes, skip it. 131 movl _C_LABEL(curlwp),%a1 132 movl L_MD_REGS(%a1),%a1 133 movl %a0,TF_PC(%a1) | fixup return PC 134 1: 135 movl _C_LABEL(curlwp),%a0 | recover new lwp 136 movl _C_LABEL(curpcb),%a1 | recover new pcb 137 2: 138 movl %a0,%d0 | free up %a0 139 movl 4(%sp),%d1 | get oldlwp for return value 140 lea _ASM_LABEL(tmpstk),%sp | switch to tmp stack in case of NMI 141 142 moveml PCB_REGS(%a1),%d2-%d7/%a2-%a7 | restore registers 143 movl PCB_USP(%a1),%a0 144 movl %a0,%usp | and USP 145 146 #ifdef M68K_FPCOPROC 147 tstl _C_LABEL(fputype) | Do we have an FPU? 148 jeq .Lcpu_switch_nofprest | No Then don't attempt restore. 149 150 lea PCB_FPCTX(%a1),%a0 | pointer to FP save area 151 #if defined(M68020) || defined(M68030) || defined(M68040) 152 #if defined(M68060) 153 cmpl #FPU_68060,_C_LABEL(fputype) 154 jeq .Lcpu_switch_resfp60rest1 155 #endif 156 tstb (%a0) | null state frame? 157 jeq .Lcpu_switch_resfprest | yes, easy 158 fmovem FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers 159 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 160 #if defined(M68060) 161 jra .Lcpu_switch_resfprest 162 #endif 163 #endif 164 165 #if defined(M68060) 166 .Lcpu_switch_resfp60rest1: 167 tstb 2(%a0) | null state frame? 168 jeq .Lcpu_switch_resfprest | yes, easy 169 fmovem FPF_FPCR(%a0),%fpcr | restore FP control registers 170 fmovem FPF_FPSR(%a0),%fpsr 171 fmovem FPF_FPI(%a0),%fpi 172 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 173 #endif 174 .Lcpu_switch_resfprest: 175 frestore (%a0) | restore state 176 #endif /* M68K_FPCOPROC */ 177 178 .Lcpu_switch_nofprest: 179 movl %d1,%d0 | return outgoing lwp 180 movl %d0,%a0 | (in a0, too) 181 rts 182 183 /* 184 * savectx(pcb) 185 * Update pcb, saving current processor state. 186 */ 187 ENTRY(savectx) 188 movl 4(%sp),%a1 189 movw %sr,PCB_PS(%a1) 190 movl %usp,%a0 | grab USP 191 movl %a0,PCB_USP(%a1) | and save it 192 moveml %d2-%d7/%a2-%a7,PCB_REGS(%a1) | save non-scratch registers 193 194 #ifdef M68K_FPCOPROC 195 tstl _C_LABEL(fputype) | Do we have FPU? 196 jeq .Lsavectx_nofpsave | No? Then don't save state. 197 198 lea PCB_FPCTX(%a1),%a0 | pointer to FP save area 199 fsave (%a0) | save FP state 200 #if defined(M68020) || defined(M68030) || defined(M68040) 201 #if defined(M68060) 202 cmpl #FPU_68060,_C_LABEL(fputype) 203 jeq .Lsavectx_savfp60 204 #endif 205 tstb (%a0) | null state frame? 206 jeq .Lsavectx_nofpsave | yes, all done 207 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 208 fmovem %fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers 209 #if defined(M68060) 210 jra .Lsavectx_nofpsave 211 #endif 212 #endif 213 #if defined(M68060) 214 .Lsavectx_savfp60: 215 tstb 2(%a0) | null state frame? 216 jeq .Lsavectx_nofpsave | yes, all done 217 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 218 fmovem %fpcr,FPF_FPCR(%a0) | save FP control registers 219 fmovem %fpsr,FPF_FPSR(%a0) 220 fmovem %fpi,FPF_FPI(%a0) 221 #endif 222 .Lsavectx_nofpsave: 223 #endif /* M68K_FPCOPROC */ 224 moveq #0,%d0 | return 0 225 rts 226 227 #ifdef M68K_FPCOPROC 228 /* 229 * void m68k_make_fpu_idle_frame(void) 230 * 231 * On machines with an FPU, generate an "idle" state frame to be 232 * used by cpu_setmcontext(). 233 * 234 * Before calling, make sure the machine actually has an FPU ... 235 */ 236 ENTRY(m68k_make_fpu_idle_frame) 237 clrl -(%sp) 238 fnop 239 240 frestore (%sp) | Effectively `resets' the FPU 241 fnop 242 243 /* Loading '0.0' will change FPU to "idle". */ 244 fmove.d #0,%fp0 245 fnop 246 247 /* Save the resulting idle frame into the buffer */ 248 lea _C_LABEL(m68k_cached_fpu_idle_frame),%a0 249 fsave (%a0) 250 fnop 251 252 /* Reset the FPU again */ 253 frestore (%sp) 254 fnop 255 addql #4,%sp 256 rts 257 258 /* 259 * Save and restore 68881 state. 260 */ 261 ENTRY(m68881_save) 262 movl 4(%sp),%a0 | save area pointer 263 fsave (%a0) | save state 264 #if defined(M68020) || defined(M68030) || defined(M68040) 265 #if defined(M68060) 266 cmpl #FPU_68060,_C_LABEL(fputype) 267 jeq .Lm68060fpsave 268 #endif 269 .Lm68881fpsave: 270 tstb (%a0) | null state frame? 271 jeq .Lm68881sdone | yes, all done 272 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 273 fmovem %fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers 274 .Lm68881sdone: 275 rts 276 #endif 277 #if defined(M68060) 278 .Lm68060fpsave: 279 tstb 2(%a0) | null state frame? 280 jeq .Lm68060sdone | yes, all done 281 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 282 fmovem %fpcr,FPF_FPCR(%a0) | save FP control registers 283 fmovem %fpsr,FPF_FPSR(%a0) 284 fmovem %fpi,FPF_FPI(%a0) 285 .Lm68060sdone: 286 rts 287 #endif 288 289 ENTRY(m68881_restore) 290 movl 4(%sp),%a0 | save area pointer 291 #if defined(M68020) || defined(M68030) || defined(M68040) 292 #if defined(M68060) 293 cmpl #FPU_68060,_C_LABEL(fputype) 294 jeq .Lm68060fprestore 295 #endif 296 .Lm68881fprestore: 297 tstb (%a0) | null state frame? 298 jeq .Lm68881rdone | yes, easy 299 fmovem FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers 300 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 301 .Lm68881rdone: 302 frestore (%a0) | restore state 303 rts 304 #endif 305 #if defined(M68060) 306 .Lm68060fprestore: 307 tstb 2(%a0) | null state frame? 308 jeq .Lm68060fprdone | yes, easy 309 fmovem FPF_FPCR(%a0),%fpcr | restore FP control registers 310 fmovem FPF_FPSR(%a0),%fpsr 311 fmovem FPF_FPI(%a0),%fpi 312 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 313 .Lm68060fprdone: 314 frestore (%a0) | restore state 315 rts 316 #endif 317 318 #else /* ! M68K_FPCOPROC */ 319 320 #ifdef DIAGNOSTIC 321 .L68881panic: 322 .asciz "m68881 save/restore" 323 .even 324 #endif 325 326 ENTRY_NOPROFILE(m68881_save) 327 GLOBAL(m68881_restore) 328 #ifdef DIAGNOSTIC 329 pea .L68881panic 330 jbsr _C_LABEL(panic) 331 /*NOTREACHED*/ 332 #endif 333 rts 334 335 #endif /* M68K_FPCOPROC */ 336 337 /* 338 * lwp_trampoline: call function in register %a2 with %a3 as an arg 339 * and then rei. 340 * %a0 will have old lwp from cpu_switchto(), and %a4 is new lwp 341 */ 342 ENTRY_NOPROFILE(lwp_trampoline) 343 movl %a4,-(%sp) | new lwp 344 movl %a0,-(%sp) | old lpw 345 jbsr _C_LABEL(lwp_startup) 346 addql #8,%sp 347 movl %a3,-(%sp) | push function arg 348 jbsr (%a2) | call function 349 addql #4,%sp | pop arg 350 movl FR_SP(%sp),%a0 | grab and load 351 movl %a0,%usp | user SP 352 moveml (%sp)+,#0x7FFF | restore most user regs 353 addql #8,%sp | toss SP and stack adjust 354 jra _ASM_LABEL(rei) | and return 355