1/* $OpenBSD: context.S,v 1.66 2023/10/24 13:20:10 claudio Exp $ */ 2 3/* 4 * Copyright (c) 2002-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28#include <sys/errno.h> 29#include <sys/syscall.h> 30 31#include <machine/param.h> 32#include <machine/asm.h> 33#include <machine/cpu.h> 34#include <machine/pte.h> 35#include <machine/regnum.h> 36#include <mips64/mips_cpu.h> 37#include <machine/cpustate.h> 38#ifdef CPU_LOONGSON2 39#include <machine/loongson2.h> 40#endif 41 42#include "assym.h" 43 44 .set mips3 45 .set noreorder # Noreorder is default style! 46 47/* 48 * Save registers and state used by reboot to take snapshot. 49 */ 50LEAF(savectx, 0) 51 REG_S s0, PCB_CONTEXT+0*REGSZ(a0) 52 REG_S s1, PCB_CONTEXT+1*REGSZ(a0) 53 REG_S s2, PCB_CONTEXT+2*REGSZ(a0) 54 REG_S s3, PCB_CONTEXT+3*REGSZ(a0) 55 MFC0 v0, COP_0_STATUS_REG 56 MFC0_HAZARD 57 REG_S s4, PCB_CONTEXT+4*REGSZ(a0) 58 REG_S s5, PCB_CONTEXT+5*REGSZ(a0) 59 REG_S s6, PCB_CONTEXT+6*REGSZ(a0) 60 REG_S s7, PCB_CONTEXT+7*REGSZ(a0) 61 REG_S sp, PCB_CONTEXT+8*REGSZ(a0) 62 REG_S s8, PCB_CONTEXT+9*REGSZ(a0) 63 REG_S ra, PCB_CONTEXT+10*REGSZ(a0) 64 REG_S v0, PCB_CONTEXT+11*REGSZ(a0) 65 j ra 66 move v0, zero 67END(savectx) 68 69LEAF(cpu_idle_cycle_nop, 0) 70 j ra 71 NOP 72END(cpu_idle_cycle_nop) 73 74LEAF(cpu_idle_cycle_wait, 0) 75 wait 76 j ra 77 NOP 78END(cpu_idle_cycle_wait) 79 80/* 81 * cpu_switchto_asm(struct proc *oldproc, struct proc *newproc) 82 */ 83NON_LEAF(cpu_switchto_asm, FRAMESZ(CF_SZ), ra) 84 GET_CPU_INFO(t1, t3) 85 PTR_L t3, CI_CURPROCPADDR(t1) 86 REG_S sp, PCB_CONTEXT+8*REGSZ(t3) # save old sp 87 88 PTR_SUBU sp, sp, FRAMESZ(CF_SZ) 89 REG_S ra, CF_RA_OFFS(sp) 90 .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ)) 91 92 beqz a0, 1f 93 MFC0 v0, COP_0_STATUS_REG 94 95 REG_S s0, PCB_CONTEXT+0*REGSZ(t3) # do a 'savectx()' 96 REG_S s1, PCB_CONTEXT+1*REGSZ(t3) 97 REG_S s2, PCB_CONTEXT+2*REGSZ(t3) 98 REG_S s3, PCB_CONTEXT+3*REGSZ(t3) 99 REG_S s4, PCB_CONTEXT+4*REGSZ(t3) 100 REG_S s5, PCB_CONTEXT+5*REGSZ(t3) 101 REG_S s6, PCB_CONTEXT+6*REGSZ(t3) 102 REG_S s7, PCB_CONTEXT+7*REGSZ(t3) 103 REG_S s8, PCB_CONTEXT+9*REGSZ(t3) 104 REG_S ra, PCB_CONTEXT+10*REGSZ(t3) 105 REG_S v0, PCB_CONTEXT+11*REGSZ(t3) 106 1071: 108 /* 109 * Switch to new context 110 */ 111 move s0, a1 # save p 112 move s1, v0 # save status register 113 jal pmap_activate 114 move a0, s0 115 116 /* 117 * Disable interrupts 118 */ 119 ori s1, SR_INT_ENAB 120 xori s1, SR_INT_ENAB 121 MTC0 s1, COP_0_STATUS_REG 122 MTC0_SR_IE_HAZARD 123 124 PTR_L t3, P_ADDR(s0) # get uarea pointer. 125 GET_CPU_INFO(t1, t0) 126 PTR_S s0, CI_CURPROC(t1) # set curproc 127 PTR_S t3, CI_CURPROCPADDR(t1) 128 129#ifdef MULTIPROCESSOR 130 PTR_S t1, P_CPU(s0) 131#endif 132 li t1, SONPROC 133 sb t1, P_STAT(s0) # set to onproc. 134 135 /* get process ASID */ 136 PTR_L t0, P_VMSPACE(s0) # p->p_vmspace 137 PTR_L t1, VMSPACE_PMAP(t0) # ->vm_map.pmap 138#ifdef MULTIPROCESSOR 139 GET_CPU_INFO(v0, t2) 140 PTR_L v0, CI_CPUID(v0) 141 PTR_SLL v0, v0, 0x3 # size of pmap_asid_info 142 PTR_ADDU t1, t1, v0 143#endif 144 lw v0, PM_ASID(t1) # ->pm_asid[cpuid].pma_asid 145 146#if UPAGES > 1 /* { */ 147 or v0, t3 148 dmtc0 v0, COP_0_TLB_HI # init high entry (tlbid) 149 150 /* 151 * We need to wire the process kernel stack mapping so there 152 * will be no tlb misses in exception handlers. This is done 153 * by invalidating any tlb entries mapping the U-area and 154 * put valid mappings in tlb entries 0 and 1. 155 */ 156 157 LA t1, CKSEG0_BASE 158 PTR_SUBU t2, t3, t1 159 bgez t2, ctx3 # in CKSEG0 160 LA t1, VM_MIN_KERNEL_ADDRESS # (safe if expands to > 1 insn) 161 PTR_SUBU t2, t3, t1 162 bltz t2, ctx3 # not mapped. 163 PTR_SRL t2, PGSHIFT+1 164 PTR_L t1, Sysmap 165 TLB_HAZARD 166 tlbp 167 TLB_HAZARD # necessary? 168 PTR_SLL t2, PTE_LOG + 1 169 PTR_ADDU t1, t2 # t1 now points at ptes. 170 mfc0 t0, COP_0_TLB_INDEX 171 nop 172 bltz t0, ctx1 # not in tlb 173 LA t2, CKSEG0_BASE # safe if expands to > 1 insn 174 175 dmtc0 t2, COP_0_TLB_HI # invalidate it. 176 dmtc0 zero, COP_0_TLB_LO0 177 dmtc0 zero, COP_0_TLB_LO1 178 TLB_HAZARD 179 tlbwi 180 TLB_HAZARD 181 182ctx1: 183 mtc0 zero, COP_0_TLB_INDEX 184 dmtc0 v0, COP_0_TLB_HI 185 PTE_LOAD ta0, 0(t1) 186 PTE_LOAD ta1, PTE_OFFS(t1) 187 PTE_CLEAR_SWBITS(ta0) 188 PTE_CLEAR_SWBITS(ta1) 189 dmtc0 ta0, COP_0_TLB_LO0 190 dmtc0 ta1, COP_0_TLB_LO1 191 PTR_ADDU v0, 2*PAGE_SIZE 192 TLB_HAZARD 193 tlbwi 194 TLB_HAZARD 195 196#if UPAGES > 2 /* { */ 197 dmtc0 v0, COP_0_TLB_HI # init high entry (tlbid) 198 PTE_LOAD ta0, (2*PTE_OFFS)(t1) 199 PTE_LOAD ta1, (3*PTE_OFFS)(t1) 200 PTE_CLEAR_SWBITS(ta0) 201 TLB_HAZARD 202 tlbp 203 TLB_HAZARD # necessary? 204 PTE_CLEAR_SWBITS(ta1) 205 mfc0 t0, COP_0_TLB_INDEX 206 nop 207 bltz t0, ctx2 # not in tlb 208 li t2, 1 209 210 dmtc0 t2, COP_0_TLB_HI # invalidate it. 211 dmtc0 zero, COP_0_TLB_LO0 212 dmtc0 zero, COP_0_TLB_LO1 213 TLB_HAZARD 214 tlbwi 215 TLB_HAZARD 216 217ctx2: 218 mtc0 t2, COP_0_TLB_INDEX 219 dmtc0 v0, COP_0_TLB_HI 220 dmtc0 ta0, COP_0_TLB_LO0 221 dmtc0 ta1, COP_0_TLB_LO1 222 TLB_HAZARD 223 tlbwi 224 TLB_HAZARD 225#endif /* } UPAGES > 2 */ 226ctx3: 227#else /* } UPAGES > 1 { */ 228#if PG_ASID_SHIFT != 0 229 dsll v0, PG_ASID_SHIFT 230#endif 231 DMTC0 v0, COP_0_TLB_HI # init high entry (tlbid) 232 MTC0_HAZARD 233#endif /* } UPAGES > 1 */ 234 235#ifdef CPU_LOONGSON2 236 li v0, COP_0_DIAG_ITLB_CLEAR | COP_0_DIAG_BTB_CLEAR | COP_0_DIAG_RAS_DISABLE 237 dmtc0 v0, COP_0_DIAG 238#endif 239 240#ifdef CPU_MIPS64R2 241 /* 242 * Restore UserLocal register. 243 */ 244 lw t1, cpu_has_userlocal 245 beq t1, zero, 1f 246 nop 247 .set push 248 .set mips64r2 249 ld t0, P_TCB(s0) 250 dmtc0 t0, COP_0_USERLOCAL 251 .set pop 2521: 253#endif /* CPU_MIPS64R2 */ 254 255 /* 256 * Restore registers and return. 257 */ 258 259 REG_L s0, PCB_CONTEXT+0*REGSZ(t3) 260 REG_L s1, PCB_CONTEXT+1*REGSZ(t3) 261 REG_L s2, PCB_CONTEXT+2*REGSZ(t3) 262 REG_L s3, PCB_CONTEXT+3*REGSZ(t3) 263 REG_L s4, PCB_CONTEXT+4*REGSZ(t3) 264 REG_L s5, PCB_CONTEXT+5*REGSZ(t3) 265 REG_L s6, PCB_CONTEXT+6*REGSZ(t3) 266 REG_L s7, PCB_CONTEXT+7*REGSZ(t3) 267 REG_L sp, PCB_CONTEXT+8*REGSZ(t3) 268 REG_L s8, PCB_CONTEXT+9*REGSZ(t3) 269 REG_L ra, PCB_CONTEXT+10*REGSZ(t3) 270 REG_L v0, PCB_CONTEXT+11*REGSZ(t3) 271 ori v0, v0, SR_INT_ENAB 272 MTC0 v0, COP_0_STATUS_REG 273 MTC0_SR_IE_HAZARD 274 j ra 275 NOP 276END(cpu_switchto_asm) 277 278/*-------------------------------------------------------------- proc_trampoline 279 * Setup for and return to user. 280 */ 281LEAF(proc_trampoline, 0) 282#ifdef DDB 283 move zero, ra 284#endif 285 jal proc_trampoline_mi 286 NOP 287 jal updateimask # Make sure SR imask is updated 288 xor a0, a0 # and interrupts enabled 289 290 jal s0 291 move a0,s1 # invoke callback. 292 293 MFC0 t0, COP_0_STATUS_REG 294 MFC0_HAZARD 295 LI t1, ~SR_INT_ENAB 296 and t0, t0, t1 297 MTC0 t0, COP_0_STATUS_REG 298 MTC0_SR_IE_HAZARD 299 300 ori t0, SR_EXL # restoring to user mode. 301 MTC0 t0, COP_0_STATUS_REG # must set exception level bit. 302 MTC0_SR_IE_HAZARD 303 304 .set noat 305 GET_CPU_INFO(k1, k0) 306 PTR_L k0, CI_CURPROCPADDR(k1) 307 RESTORE_CPU_SREG(k0, 0) 308 RESTORE_REG(a0, PC, k0, 0) 309 RESTORE_CPU(k0, 0) 310 RESTORE_REG(sp, SP, k0, 0) 311 LI k0, 0 312 LI k1, 0 313 ERET 314 .set at 315END(proc_trampoline) 316