1/* $OpenBSD: exception.S,v 1.43 2021/05/01 16:11:11 visa 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 29/* 30 * This code handles exceptions and dispatches to the 31 * correct handler depending on the exception type. 32 * 33 * Exceptions are directed to the following addresses: 34 * 0xffffffffbfc00000 Reset, NMI etc. Not handled by the kernel. 35 * 0xffffffff80000000 TLB refill, not in exception. 36 * 0xffffffff80000080 XTLB refill, not in exception. 37 * 0xffffffffa0000100 Cache errors. 38 * 0xffffffff80000180 Interrupts. Same as next. 39 * 0xffffffff80000180 Everything else... 40 */ 41 42#include <machine/param.h> 43#include <machine/asm.h> 44#include <machine/cpu.h> 45#include <mips64/mips_cpu.h> 46#include <machine/regnum.h> 47#include <machine/cpustate.h> 48#ifdef CPU_LOONGSON2 49#include <machine/loongson2.h> 50#endif 51 52#include "assym.h" 53 54 .set mips3 55 56 .text 57 58k_exception_table: 59 PTR_VAL k_intr /* T_INT */ 60 PTR_VAL k_general /* T_TLB_MOD */ 61 PTR_VAL k_tlb_inv /* T_TLB_LD_MISS */ 62 PTR_VAL k_tlb_inv /* T_TLB_ST_MISS */ 63 PTR_VAL k_general /* T_ADDR_ERR_LD */ 64 PTR_VAL k_general /* T_ADDR_ERR_ST */ 65 PTR_VAL k_general /* T_BUS_ERR_IFETCH */ 66 PTR_VAL k_general /* T_BUS_ERR_LD_ST */ 67 PTR_VAL k_general /* T_SYSCALL */ 68 PTR_VAL k_general /* T_BREAK */ 69 PTR_VAL k_general /* T_RES_INST */ 70 PTR_VAL k_general /* T_COP_UNUSABLE */ 71 PTR_VAL k_general /* T_OVFLOW */ 72 PTR_VAL k_general /* T_TRAP */ 73 PTR_VAL k_general /* T_VCEI */ 74 PTR_VAL k_general /* T_FPE */ 75 PTR_VAL k_general /* T_IWATCH */ 76 PTR_VAL k_general 77 PTR_VAL k_general /* T_C2E */ 78 PTR_VAL k_general 79 PTR_VAL k_general 80 PTR_VAL k_general 81 PTR_VAL k_general /* T_MDMX */ 82 PTR_VAL k_general /* T_DWATCH */ 83 PTR_VAL k_general /* T_MCHECK */ 84 PTR_VAL k_general 85 PTR_VAL k_general 86 PTR_VAL k_general 87 PTR_VAL k_general 88 PTR_VAL k_general 89 PTR_VAL k_general /* T_CACHEERR */ 90 PTR_VAL k_general /* T_VCED */ 91 92u_exception_table: 93 PTR_VAL u_intr /* T_INT */ 94 PTR_VAL u_general /* T_TLB_MOD */ 95 PTR_VAL u_general /* T_TLB_LD_MISS */ 96 PTR_VAL u_general /* T_TLB_ST_MISS */ 97 PTR_VAL u_general /* T_ADDR_ERR_LD */ 98 PTR_VAL u_general /* T_ADDR_ERR_ST */ 99 PTR_VAL u_general /* T_BUS_ERR_IFETCH */ 100 PTR_VAL u_general /* T_BUS_ERR_LD_ST */ 101 PTR_VAL u_general /* T_SYSCALL */ 102 PTR_VAL u_general /* T_BREAK */ 103 PTR_VAL u_general /* T_RES_INST */ 104 PTR_VAL u_general /* T_COP_UNUSABLE */ 105 PTR_VAL u_general /* T_OVFLOW */ 106 PTR_VAL u_general /* T_TRAP */ 107 PTR_VAL u_general /* T_VCEI */ 108 PTR_VAL u_general /* T_FPE */ 109 PTR_VAL u_general /* T_IWATCH */ 110 PTR_VAL u_general 111 PTR_VAL u_general /* T_C2E */ 112 PTR_VAL u_general 113 PTR_VAL u_general 114 PTR_VAL u_general 115 PTR_VAL u_general /* T_MDMX */ 116 PTR_VAL u_general /* T_DWATCH */ 117 PTR_VAL u_general /* T_MCHECK */ 118 PTR_VAL u_general 119 PTR_VAL u_general 120 PTR_VAL u_general 121 PTR_VAL u_general 122 PTR_VAL u_general 123 PTR_VAL u_general /* T_CACHEERR */ 124 PTR_VAL u_general /* T_VCED */ 125 126 .set noreorder # Noreorder is default style! 127 128/*---------------------------------------------------------------- exception 129 * General exception handler dispatcher. This code is copied 130 * to the vector area and must thus be PIC and less than 128 131 * bytes long to fit. Only k0 and k1 may be used at this time. 132 */ 133 .globl exception 134exception: 135 .set noat 136#ifdef CPU_LOONGSON2 137 /* 138 * To work around a branch prediction issue on earlier LS2F 139 * chips, it is necessary to clear the BTB upon 140 * userland->kernel boundaries. 141 */ 142 li k0, COP_0_DIAG_BTB_CLEAR | COP_0_DIAG_RAS_DISABLE 143 dmtc0 k0, COP_0_DIAG 144#endif 145 MFC0 k0, COP_0_STATUS_REG 146 MFC0 k1, COP_0_CAUSE_REG 147 and k0, k0, SR_KSU_USER 148 beqz k0, k_exception # Kernel mode mode 149 and k1, k1, CR_EXC_CODE 150 151 LA k0, u_exception_table 152 PTR_ADDU k0, k0, k1 153 PTR_ADDU k0, k0, k1 # yes, twice... 154 PTR_L k0, 0(k0) 155 j k0 156 nop 157 158k_exception: 159 LA k0, k_exception_table 160 PTR_ADDU k0, k0, k1 161 PTR_ADDU k0, k0, k1 # yes, twice... 162 PTR_L k0, 0(k0) 163 j k0 164 nop 165 .set at 166 .globl e_exception 167e_exception: 168 169 170/*---------------------------------------------------------------- k_intr 171 * Handle an interrupt in kernel mode. This is easy since we 172 * just need to save away the 'save' registers and state. 173 * State is saved on kernel stack. 174 */ 175 176NNON_LEAF(k_intr, FRAMESZ(KERN_EXC_FRAME_SIZE), ra) 177 .set noat 178 .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(KERN_EXC_FRAME_SIZE)) 179 PTR_SUB k0, sp, FRAMESZ(KERN_EXC_FRAME_SIZE) 180 SAVE_CPU(k0, CF_RA_OFFS) 181 .set at 182 move sp, k0 # Already on kernel stack 183 and t0, a1, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK) 184 MTC0 t0, COP_0_STATUS_REG 185 MTC0_SR_IE_HAZARD 186 PTR_S a0, 0(sp) 187 jal interrupt 188 PTR_S a3, CF_RA_OFFS + KERN_REG_SIZE(sp) 189 190 PTR_L a0, CF_RA_OFFS + KERN_REG_SIZE(sp) 191 .set noat 192 RESTORE_CPU(sp, CF_RA_OFFS) 193 PTR_ADDU sp, sp, FRAMESZ(KERN_EXC_FRAME_SIZE) 194 ERET 195 .set at 196END(k_intr) 197 198/*---------------------------------------------------------------- u_intr 199 * Handle an interrupt in user mode. Save the relevant user 200 * registers into the u.u_pcb struct. This will allow us 201 * to preempt the interrupted process. Full save is held 202 * off though until a switch() really is required. 203 */ 204NNON_LEAF(u_intr, FRAMESZ(CF_SZ), ra) 205 .set noat 206 .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ)) 207 GET_CPU_INFO(k1, k0) 208 PTR_L k0, CI_CURPROCPADDR(k1) 209 SAVE_CPU(k0, 0) 210 PTR_ADDU sp, k0, USPACE-FRAMESZ(CF_SZ) 211 .set at 212 and t0, a1, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK) 213 MTC0 t0, COP_0_STATUS_REG 214 MTC0_SR_IE_HAZARD 215 PTR_S a0, 0(sp) 216 jal interrupt 217 PTR_S a3, CF_RA_OFFS(sp) # for debugging 218 219 GET_CPU_INFO(t1, t0) 2200: 221 MFC0 t0, COP_0_STATUS_REG # disable interrupts for checking AST 222 LI v0, ~SR_INT_ENAB 223 and t0, t0, v0 224 MTC0 t0, COP_0_STATUS_REG 225 MTC0_SR_IE_HAZARD 226 227 PTR_L v1, CI_CURPROC(t1) 228 lw v0, P_ASTPENDING(v1) # any pending AST? 229 beq v0, zero, 4f 230 nop 231 232 ori t0, SR_INT_ENAB # enable interrupts for handling AST 233 MTC0 t0, COP_0_STATUS_REG 234 MTC0_SR_IE_HAZARD 235 236 PTR_L t0, CI_CURPROCPADDR(t1) # curprocpaddr 237 SAVE_CPU_SREG(t0, 0) 238 239 jal ast 240 nop 241 242/* 243 * Restore user registers and return. NOTE: interrupts are enabled. 244 */ 245 GET_CPU_INFO(t1, t0) 246 PTR_L t0, CI_CURPROCPADDR(t1) 247 RESTORE_CPU_SREG(t0, 0) 248 249 b 0b 250 nop 251 2524: 253 # t0 is status register from earlier 254 ori t0, SR_EXL # restoring to user mode. 255 MTC0 t0, COP_0_STATUS_REG # must set exception level bit. 256 MTC0_SR_IE_HAZARD 257 258 # t1 is curcpu() from earlier 259 move k1, t1 260 PTR_L k0, CI_CURPROCPADDR(k1) 261 RESTORE_REG(a3, CPL, k0, 0) 262 sw a3, CI_IPL(k1) 263 .set noat 264 RESTORE_REG(a0, PC, k0, 0) 265 RESTORE_CPU(k0, 0) 266 RESTORE_REG(sp, SP, k0, 0) 267 LI k0, 0 268 LI k1, 0 269 ERET 270 .set at 271END(u_intr) 272 273/*---------------------------------------------------------------- k_general 274 * Handle a kernel general trap. This is very much like 275 * k_intr except that we call ktrap instead of interrupt. 276 */ 277 278NNON_LEAF(k_general, FRAMESZ(KERN_EXC_FRAME_SIZE), ra) 279 .set noat 280 .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(KERN_EXC_FRAME_SIZE)) 281 PTR_SUB k0, sp, FRAMESZ(KERN_EXC_FRAME_SIZE) 282 SAVE_CPU(k0, CF_RA_OFFS) 283#if defined(DDB) 284 SAVE_CPU_SREG(k0, CF_RA_OFFS) 285#endif 286 .set at 287 move sp, k0 # Already on kernel stack 288 and t0, a1, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK) 289 MTC0 t0, COP_0_STATUS_REG 290 MTC0_SR_IE_HAZARD 291 PTR_S a0, 0(sp) 292 jal trap 293 PTR_S a3, CF_RA_OFFS + KERN_REG_SIZE(sp) 294 295 MFC0 t0, COP_0_STATUS_REG # disable interrupts 296 LI t1, ~SR_INT_ENAB 297 and t0, t0, t1 298 MTC0 t0, COP_0_STATUS_REG 299 MTC0_SR_IE_HAZARD 300 301 .set noat 302 RESTORE_REG(a0, PC, sp, CF_RA_OFFS) 303 RESTORE_CPU(sp, CF_RA_OFFS) 304 PTR_ADDU sp, sp, FRAMESZ(KERN_EXC_FRAME_SIZE) 305 ERET 306 .set at 307END(k_general) 308 309/*---------------------------------------------------------------- u_general 310 * Handle a user general trap. 311 */ 312NNON_LEAF(u_general, FRAMESZ(CF_SZ), ra) 313 .set noat 314 .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ)) 315 316 GET_CPU_INFO(k1, k0) 317 PTR_L k0, CI_CURPROCPADDR(k1) 318 SAVE_CPU(k0, 0) 319 SAVE_CPU_SREG(k0, 0) 320 PTR_ADDU sp, k0, USPACE-FRAMESZ(CF_SZ) 321 .set at 322 and t0, a1, ~(SR_COP_1_BIT | SR_EXL | SR_INT_ENAB | SR_KSU_MASK) 323 MTC0 t0, COP_0_STATUS_REG 324 MTC0_SR_IE_HAZARD 325 326 jal trap 327 PTR_S a3, CF_RA_OFFS(sp) # for debugging 328 3290: 330 MFC0 t0, COP_0_STATUS_REG # disable interrupts for checking AST 331 LI t1, ~SR_INT_ENAB 332 and t0, t0, t1 333 MTC0 t0, COP_0_STATUS_REG 334 MTC0_SR_IE_HAZARD 335 336 GET_CPU_INFO(t1, v0) 337 PTR_L v1, CI_CURPROC(t1) 338 lw v0, P_ASTPENDING(v1) # any pending AST? 339 beq v0, zero, 4f 340 nop 341 342 ori t0, SR_INT_ENAB # enable interrupts for handling AST 343 MTC0 t0, COP_0_STATUS_REG 344 MTC0_SR_IE_HAZARD 345 346 jal ast 347 nop 348 349 b 0b 350 nop 351 3524: 353 # t0 is status register from earlier 354 ori t0, SR_EXL # restoring to user mode. 355 MTC0 t0, COP_0_STATUS_REG # must set exception level bit. 356 MTC0_SR_IE_HAZARD 357 358 # t1 is curcpu() from earlier 359 move k1, t1 360 PTR_L k0, CI_CURPROCPADDR(k1) 361 RESTORE_REG(a3, CPL, k0, 0) 362 sw a3, CI_IPL(k1) 363 .set noat 364 RESTORE_CPU_SREG(k0, 0) 365 RESTORE_REG(a0, PC, k0, 0) 366 RESTORE_CPU(k0, 0) 367 RESTORE_REG(sp, SP, k0, 0) 368 LI k0, 0 369 LI k1, 0 370 ERET 371 .set at 372END(u_general) 373