1/* $NetBSD: switch_subr.s,v 1.34 2020/01/08 20:59:18 skrll 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 `current' 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) 137 movl L_PCB(%a0),%a1 | get its pcb 138 movl %a1,_C_LABEL(curpcb) 139 140#if defined(sun2) || defined(sun3) 141 movl L_PROC(%a0),%a2 142 movl P_VMSPACE(%a2),%a2 | vm = p->p_vmspace 143#if defined(DIAGNOSTIC) && !defined(sun2) 144 tstl %a2 | vm == VM_MAP_NULL? 145 jeq .Lcpu_switch_badsw | panic 146#endif 147 pea (%a0) | save newlwp 148#if !defined(_SUN3X_) || defined(PMAP_DEBUG) 149 movl VM_PMAP(%a2),-(%sp) | push vm->vm_map.pmap 150 jbsr _C_LABEL(_pmap_switch) | _pmap_switch(pmap) 151 addql #4,%sp 152 movl _C_LABEL(curpcb),%a1 | restore curpcb 153| Note: _pmap_switch() will clear the cache if needed. 154#else 155 /* Use this inline version on sun3x when not debugging the pmap. */ 156 lea _C_LABEL(kernel_crp),%a3 | our CPU Root Ptr. (CRP) 157 movl VM_PMAP(%a2),%a2 | pmap = vm->vm_map.pmap 158 movl PM_A_PHYS(%a2),%d0 | phys = pmap->pm_a_phys 159 cmpl 4(%a3),%d0 | == kernel_crp.rp_addr ? 160 jeq .Lsame_mmuctx | skip loadcrp/flush 161 /* OK, it is a new MMU context. Load it up. */ 162 movl %d0,4(%a3) 163 movl #CACHE_CLR,%d0 164 movc %d0,%cacr | invalidate cache(s) 165 pflusha | flush entire TLB 166 pmove (%a3),%crp | load new user root pointer 167.Lsame_mmuctx: 168#endif /* !defined(_SUN3X_) || defined(PMAP_DEBUG) */ 169#else /* !defined(sun2) && !defined(sun3) */ 170 /* 171 * Activate process's address space. 172 * XXX Should remember the last USTP value loaded, and call this 173 * XXX only of it has changed. 174 */ 175 pea (%a0) | push newlwp 176 jbsr _C_LABEL(pmap_activate) | pmap_activate(newlwp) 177 /* Note that newlwp will be popped off the stack later. */ 178#endif 179 180 /* 181 * Check for restartable atomic sequences (RAS) 182 */ 183 movl _C_LABEL(curlwp),%a0 184 movl L_PROC(%a0),%a2 185 tstl P_RASLIST(%a2) 186 jeq 1f 187 movl L_MD_REGS(%a0),%a1 188 movl TF_PC(%a1),-(%sp) 189 movl %a2,-(%sp) 190 jbsr _C_LABEL(ras_lookup) 191 addql #8,%sp 192 movql #-1,%d0 193 cmpl %a0,%d0 194 jeq 1f 195 movl _C_LABEL(curlwp),%a1 196 movl L_MD_REGS(%a1),%a1 197 movl %a0,TF_PC(%a1) 1981: 199 movl (%sp)+,%d0 | restore newlwp 200 movl _C_LABEL(curpcb),%a1 | restore pcb 201 202 movl 4(%sp),%d1 | restore oldlwp for a return value 203 lea _ASM_LABEL(tmpstk),%sp | now goto a tmp stack for NMI 204 205 moveml PCB_REGS(%a1),%d2-%d7/%a2-%a7 | and registers 206 movl PCB_USP(%a1),%a0 207 movl %a0,%usp | and USP 208 209#ifdef _M68K_CUSTOM_FPU_CTX 210 moveml %d0/%d1,-(%sp) 211 jbsr _ASM_LABEL(m68k_fpuctx_restore) 212 moveml (%sp)+,%d0/%d1 213#else 214#ifdef FPCOPROC 215 tstl _C_LABEL(fputype) | Do we have an FPU? 216 jeq .Lcpu_switch_nofprest | No Then don't attempt restore. 217 218 lea PCB_FPCTX(%a1),%a0 | pointer to FP save area 219#if defined(M68020) || defined(M68030) || defined(M68040) 220#if defined(M68060) 221 cmpl #FPU_68060,_C_LABEL(fputype) 222 jeq .Lcpu_switch_resfp60rest1 223#endif 224 tstb (%a0) | null state frame? 225 jeq .Lcpu_switch_resfprest | yes, easy 226 fmovem FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers 227 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 228#if defined(M68060) 229 jra .Lcpu_switch_resfprest 230#endif 231#endif 232 233#if defined(M68060) 234.Lcpu_switch_resfp60rest1: 235 tstb 2(%a0) | null state frame? 236 jeq .Lcpu_switch_resfprest | yes, easy 237 fmovem FPF_FPCR(%a0),%fpcr | restore FP control registers 238 fmovem FPF_FPSR(%a0),%fpsr 239 fmovem FPF_FPI(%a0),%fpi 240 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 241#endif 242.Lcpu_switch_resfprest: 243 frestore (%a0) | restore state 244#endif /* FPCOPROC */ 245#endif /* !_M68K_CUSTOM_FPU_CTX */ 246 247.Lcpu_switch_nofprest: 248 movl %d1,%d0 249 movl %d0,%a0 250 rts 251 252.Lcpu_switch_badsw: 253 PANIC("switch") 254 /*NOTREACHED*/ 255 256/* 257 * savectx(pcb) 258 * Update pcb, saving current processor state. 259 */ 260ENTRY(savectx) 261 movl 4(%sp),%a1 262 movw %sr,PCB_PS(%a1) 263 movl %usp,%a0 | grab USP 264 movl %a0,PCB_USP(%a1) | and save it 265 moveml %d2-%d7/%a2-%a7,PCB_REGS(%a1) | save non-scratch registers 266 267#ifdef _M68K_CUSTOM_FPU_CTX 268 jbsr _ASM_LABEL(m68k_fpuctx_save) 269#else 270#ifdef FPCOPROC 271 tstl _C_LABEL(fputype) | Do we have FPU? 272 jeq .Lsavectx_nofpsave | No? Then don't save state. 273 274 lea PCB_FPCTX(%a1),%a0 | pointer to FP save area 275 fsave (%a0) | save FP state 276#if defined(M68020) || defined(M68030) || defined(M68040) 277#if defined(M68060) 278 cmpl #FPU_68060,_C_LABEL(fputype) 279 jeq .Lsavectx_savfp60 280#endif 281 tstb (%a0) | null state frame? 282 jeq .Lsavectx_nofpsave | yes, all done 283 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 284 fmovem %fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers 285#if defined(M68060) 286 jra .Lsavectx_nofpsave 287#endif 288#endif 289#if defined(M68060) 290.Lsavectx_savfp60: 291 tstb 2(%a0) | null state frame? 292 jeq .Lsavectx_nofpsave | yes, all done 293 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 294 fmovem %fpcr,FPF_FPCR(%a0) | save FP control registers 295 fmovem %fpsr,FPF_FPSR(%a0) 296 fmovem %fpi,FPF_FPI(%a0) 297#endif 298.Lsavectx_nofpsave: 299#endif /* FPCOPROC */ 300#endif /* !_M68K_CUSTOM_FPU_CTX */ 301 moveq #0,%d0 | return 0 302 rts 303 304#if !defined(M68010) 305/* 306 * void m68k_make_fpu_idle_frame(void) 307 * 308 * On machines with an FPU, generate an "idle" state frame to be 309 * used by cpu_setmcontext(). 310 * 311 * Before calling, make sure the machine actually has an FPU ... 312 */ 313ENTRY(m68k_make_fpu_idle_frame) 314 clrl -(%sp) 315 fnop 316 317 frestore (%sp) | Effectively `resets' the FPU 318 fnop 319 320 /* Loading '0.0' will change FPU to "idle". */ 321 fmove.d #0,%fp0 322 fnop 323 324 /* Save the resulting idle frame into the buffer */ 325 lea _C_LABEL(m68k_cached_fpu_idle_frame),%a0 326 fsave (%a0) 327 fnop 328 329 /* Reset the FPU again */ 330 frestore (%sp) 331 fnop 332 addql #4,%sp 333 rts 334#endif 335 336/* 337 * Save and restore 68881 state. 338 */ 339#ifdef FPCOPROC 340ENTRY(m68881_save) 341 movl 4(%sp),%a0 | save area pointer 342 fsave (%a0) | save state 343#if defined(M68020) || defined(M68030) || defined(M68040) 344#if defined(M68060) 345 cmpl #FPU_68060,_C_LABEL(fputype) 346 jeq .Lm68060fpsave 347#endif 348.Lm68881fpsave: 349 tstb (%a0) | null state frame? 350 jeq .Lm68881sdone | yes, all done 351 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 352 fmovem %fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers 353.Lm68881sdone: 354 rts 355#endif 356#if defined(M68060) 357.Lm68060fpsave: 358 tstb 2(%a0) | null state frame? 359 jeq .Lm68060sdone | yes, all done 360 fmovem %fp0-%fp7,FPF_REGS(%a0) | save FP general registers 361 fmovem %fpcr,FPF_FPCR(%a0) | save FP control registers 362 fmovem %fpsr,FPF_FPSR(%a0) 363 fmovem %fpi,FPF_FPI(%a0) 364.Lm68060sdone: 365 rts 366#endif 367 368ENTRY(m68881_restore) 369 movl 4(%sp),%a0 | save area pointer 370#if defined(M68020) || defined(M68030) || defined(M68040) 371#if defined(M68060) 372 cmpl #FPU_68060,_C_LABEL(fputype) 373 jeq .Lm68060fprestore 374#endif 375.Lm68881fprestore: 376 tstb (%a0) | null state frame? 377 jeq .Lm68881rdone | yes, easy 378 fmovem FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers 379 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 380.Lm68881rdone: 381 frestore (%a0) | restore state 382 rts 383#endif 384#if defined(M68060) 385.Lm68060fprestore: 386 tstb 2(%a0) | null state frame? 387 jeq .Lm68060fprdone | yes, easy 388 fmovem FPF_FPCR(%a0),%fpcr | restore FP control registers 389 fmovem FPF_FPSR(%a0),%fpsr 390 fmovem FPF_FPI(%a0),%fpi 391 fmovem FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers 392.Lm68060fprdone: 393 frestore (%a0) | restore state 394 rts 395#endif 396#endif 397 398/* 399 * lwp_trampoline: call function in register %a2 with %a3 as an arg 400 * and then rei. 401 * %a0 will have old lwp from cpu_switchto(), and %a4 is new lwp 402 */ 403ENTRY_NOPROFILE(lwp_trampoline) 404 movl %a4,-(%sp) | new lwp 405 movl %a0,-(%sp) | old lpw 406 jbsr _C_LABEL(lwp_startup) 407 addql #8,%sp 408 movl %a3,-(%sp) | push function arg 409 jbsr (%a2) | call function 410 addql #4,%sp | pop arg 411 movl FR_SP(%sp),%a0 | grab and load 412 movl %a0,%usp | user SP 413 moveml (%sp)+,#0x7FFF | restore most user regs 414 addql #8,%sp | toss SP and stack adjust 415 jra _ASM_LABEL(rei) | and return 416