1/* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */ 2/*- 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Digital Equipment Corporation and Ralph Campbell. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Copyright (C) 1989 Digital Equipment Corporation. 34 * Permission to use, copy, modify, and distribute this software and 35 * its documentation for any purpose and without fee is hereby granted, 36 * provided that the above copyright notice appears in all copies. 37 * Digital Equipment Corporation makes no representations about the 38 * suitability of this software for any purpose. It is provided "as is" 39 * without express or implied warranty. 40 * 41 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, 42 * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) 43 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, 44 * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) 45 * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, 46 * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) 47 * from: @(#)locore.s 8.5 (Berkeley) 1/4/94 48 * JNPR: exception.S,v 1.5 2007/01/08 04:58:37 katta 49 * $FreeBSD$ 50 */ 51 52/* 53 * Contains code that is the first executed at boot time plus 54 * assembly language support routines. 55 */ 56 57#include "opt_ddb.h" 58 59#include <machine/asm.h> 60#include <machine/cpu.h> 61#include <machine/regnum.h> 62#include <machine/cpuregs.h> 63#include <machine/pte.h> 64#include <machine/pcb.h> 65 66#include "assym.s" 67 68 .set noreorder # Noreorder is default style! 69 70#ifdef KDTRACE_HOOKS 71 .data 72 .globl dtrace_invop_calltrap_addr 73 .align 4 74 .type dtrace_invop_calltrap_addr, @object 75 .size dtrace_invop_calltrap_addr, 8 76dtrace_invop_calltrap_addr: 77 .word 0 78 .word 0 79 80 .text 81#endif 82 83/* 84 * Reasonable limit 85 */ 86#define INTRCNT_COUNT 256 87 88 89/* 90 *---------------------------------------------------------------------------- 91 * 92 * MipsTLBMiss -- 93 * 94 * Vector code for the TLB-miss exception vector 0x80000000. 95 * 96 * This code is copied to the TLB exception vector address to 97 * which the CPU jumps in response to an exception or a TLB miss. 98 * NOTE: This code must be position independent!!! 99 * 100 * 101 */ 102VECTOR(MipsTLBMiss, unknown) 103 .set push 104 .set noat 105 j MipsDoTLBMiss 106 MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address 107 .set pop 108VECTOR_END(MipsTLBMiss) 109 110/* 111 *---------------------------------------------------------------------------- 112 * 113 * MipsDoTLBMiss -- 114 * 115 * This is the real TLB Miss Handler code. 116 * 'segbase' points to the base of the segment table for user processes. 117 * 118 * Don't check for invalid pte's here. We load them as well and 119 * let the processor trap to load the correct value after service. 120 *---------------------------------------------------------------------------- 121 */ 122 .set push 123 .set noat 124MipsDoTLBMiss: 125 bltz k0, 1f #02: k0<0 -> 1f (kernel fault) 126 PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost) 127 128 GET_CPU_PCPU(k1) 129 PTR_L k1, PC_SEGBASE(k1) 130 beqz k1, 2f #05: make sure segbase is not null 131 andi k0, k0, PDEPTRMASK #06: k0=seg offset 132 PTR_ADDU k1, k0, k1 #07: k1=seg entry address 133 134 PTR_L k1, 0(k1) #08: k1=seg entry 135 MFC0 k0, MIPS_COP_0_BAD_VADDR #09: k0=bad address (again) 136 beq k1, zero, 2f #0a: ==0 -- no page table 137#ifdef __mips_n64 138 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN 139 andi k0, k0, PDEPTRMASK # k0=pde offset 140 PTR_ADDU k1, k0, k1 # k1=pde entry address 141 PTR_L k1, 0(k1) # k1=pde entry 142 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) 143 beq k1, zero, 2f # ==0 -- no page table 144#endif 145 PTR_SRL k0, PAGE_SHIFT - PTESHIFT #0b: k0=VPN (aka va>>10) 146 andi k0, k0, PTE2MASK #0c: k0=page tab offset 147 PTR_ADDU k1, k1, k0 #0d: k1=pte address 148 PTE_L k0, 0(k1) #0e: k0=lo0 pte 149 PTE_L k1, PTESIZE(k1) #0f: k1=lo0 pte 150 CLEAR_PTE_SWBITS(k0) 151 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded 152 COP0_SYNC 153 CLEAR_PTE_SWBITS(k1) 154 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded 155 COP0_SYNC 156 tlbwr #1a: write to tlb 157 HAZARD_DELAY 158 eret #1f: retUrn from exception 1591: j MipsTLBMissException #20: kernel exception 160 nop #21: branch delay slot 1612: j SlowFault #22: no page table present 162 nop #23: branch delay slot 163 .set pop 164 165/* 166 * This code is copied to the general exception vector address to 167 * handle all execptions except RESET and TLBMiss. 168 * NOTE: This code must be position independent!!! 169 */ 170VECTOR(MipsException, unknown) 171/* 172 * Find out what mode we came from and jump to the proper handler. 173 * 174 * Note: at turned off here because we cannot trash the at register 175 * in this exception code. Only k0 and k1 may be modified before 176 * we save registers. This is true of all functions called through 177 * the pointer magic: Mips{User,Kern}Intr, Mips{User,Kern}GenException 178 * and MipsTLBInvalidException 179 */ 180 .set noat 181 mfc0 k0, MIPS_COP_0_STATUS # Get the status register 182 mfc0 k1, MIPS_COP_0_CAUSE # Get the cause register value. 183 and k0, k0, MIPS_SR_KSU_USER # test for user mode 184 # sneaky but the bits are 185 # with us........ 186 sll k0, k0, 3 # shift user bit for cause index 187 and k1, k1, MIPS_CR_EXC_CODE # Mask out the cause bits. 188 or k1, k1, k0 # change index to user table 189#if defined(__mips_n64) 190 PTR_SLL k1, k1, 1 # shift to get 8-byte offset 191#endif 1921: 193 PTR_LA k0, _C_LABEL(machExceptionTable) # get base of the jump table 194 PTR_ADDU k0, k0, k1 # Get the address of the 195 # function entry. Note that 196 # the cause is already 197 # shifted left by 2 bits so 198 # we dont have to shift. 199 PTR_L k0, 0(k0) # Get the function address 200 nop 201 j k0 # Jump to the function. 202 nop 203 .set at 204VECTOR_END(MipsException) 205 206/* 207 * We couldn't find a TLB entry. 208 * Find out what mode we came from and call the appropriate handler. 209 */ 210SlowFault: 211 .set noat 212 mfc0 k0, MIPS_COP_0_STATUS 213 nop 214 and k0, k0, MIPS_SR_KSU_USER 215 bne k0, zero, _C_LABEL(MipsUserGenException) 216 nop 217 .set at 218/* 219 * Fall though ... 220 */ 221 222/*---------------------------------------------------------------------------- 223 * 224 * MipsKernGenException -- 225 * 226 * Handle an exception from kernel mode. 227 * 228 * Results: 229 * None. 230 * 231 * Side effects: 232 * None. 233 * 234 *---------------------------------------------------------------------------- 235 */ 236 237#define SAVE_REG(reg, offs, base) \ 238 REG_S reg, CALLFRAME_SIZ + (SZREG * offs) (base) 239 240#if defined(CPU_CNMIPS) 241#define CLEAR_STATUS \ 242 mfc0 a0, MIPS_COP_0_STATUS ;\ 243 li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \ 244 or a0, a0, a2 ; \ 245 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ 246 and a0, a0, a2 ; \ 247 mtc0 a0, MIPS_COP_0_STATUS ; \ 248 ITLBNOPFIX 249#elif defined(CPU_RMI) || defined(CPU_NLM) 250#define CLEAR_STATUS \ 251 mfc0 a0, MIPS_COP_0_STATUS ;\ 252 li a2, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) ; \ 253 or a0, a0, a2 ; \ 254 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ 255 and a0, a0, a2 ; \ 256 mtc0 a0, MIPS_COP_0_STATUS ; \ 257 ITLBNOPFIX 258#else 259#define CLEAR_STATUS \ 260 mfc0 a0, MIPS_COP_0_STATUS ;\ 261 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ 262 and a0, a0, a2 ; \ 263 mtc0 a0, MIPS_COP_0_STATUS ; \ 264 ITLBNOPFIX 265#endif 266 267/* 268 * Save CPU and CP0 register state. 269 * 270 * This is straightforward except for saving the exception program 271 * counter. The ddb backtrace code looks for the first instruction 272 * matching the form "sw ra, (off)sp" to figure out the address of the 273 * calling function. So we must make sure that we save the exception 274 * PC by staging it through 'ra' as opposed to any other register. 275 */ 276#define SAVE_CPU \ 277 SAVE_REG(AT, AST, sp) ;\ 278 .set at ; \ 279 SAVE_REG(v0, V0, sp) ;\ 280 SAVE_REG(v1, V1, sp) ;\ 281 SAVE_REG(a0, A0, sp) ;\ 282 SAVE_REG(a1, A1, sp) ;\ 283 SAVE_REG(a2, A2, sp) ;\ 284 SAVE_REG(a3, A3, sp) ;\ 285 SAVE_REG(t0, T0, sp) ;\ 286 SAVE_REG(t1, T1, sp) ;\ 287 SAVE_REG(t2, T2, sp) ;\ 288 SAVE_REG(t3, T3, sp) ;\ 289 SAVE_REG(ta0, TA0, sp) ;\ 290 SAVE_REG(ta1, TA1, sp) ;\ 291 SAVE_REG(ta2, TA2, sp) ;\ 292 SAVE_REG(ta3, TA3, sp) ;\ 293 SAVE_REG(t8, T8, sp) ;\ 294 SAVE_REG(t9, T9, sp) ;\ 295 SAVE_REG(gp, GP, sp) ;\ 296 SAVE_REG(s0, S0, sp) ;\ 297 SAVE_REG(s1, S1, sp) ;\ 298 SAVE_REG(s2, S2, sp) ;\ 299 SAVE_REG(s3, S3, sp) ;\ 300 SAVE_REG(s4, S4, sp) ;\ 301 SAVE_REG(s5, S5, sp) ;\ 302 SAVE_REG(s6, S6, sp) ;\ 303 SAVE_REG(s7, S7, sp) ;\ 304 SAVE_REG(s8, S8, sp) ;\ 305 mflo v0 ;\ 306 mfhi v1 ;\ 307 mfc0 a0, MIPS_COP_0_STATUS ;\ 308 mfc0 a1, MIPS_COP_0_CAUSE ;\ 309 MFC0 a2, MIPS_COP_0_BAD_VADDR;\ 310 MFC0 a3, MIPS_COP_0_EXC_PC ;\ 311 SAVE_REG(v0, MULLO, sp) ;\ 312 SAVE_REG(v1, MULHI, sp) ;\ 313 SAVE_REG(a0, SR, sp) ;\ 314 SAVE_REG(a1, CAUSE, sp) ;\ 315 SAVE_REG(a2, BADVADDR, sp) ;\ 316 move t0, ra ;\ 317 move ra, a3 ;\ 318 SAVE_REG(ra, PC, sp) ;\ 319 move ra, t0 ;\ 320 SAVE_REG(ra, RA, sp) ;\ 321 PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\ 322 SAVE_REG(v0, SP, sp) ;\ 323 CLEAR_STATUS ;\ 324 PTR_ADDU a0, sp, CALLFRAME_SIZ ;\ 325 ITLBNOPFIX 326 327#define RESTORE_REG(reg, offs, base) \ 328 REG_L reg, CALLFRAME_SIZ + (SZREG * offs) (base) 329 330#define RESTORE_CPU \ 331 CLEAR_STATUS ;\ 332 RESTORE_REG(k0, SR, sp) ;\ 333 RESTORE_REG(t0, MULLO, sp) ;\ 334 RESTORE_REG(t1, MULHI, sp) ;\ 335 mtlo t0 ;\ 336 mthi t1 ;\ 337 MTC0 v0, MIPS_COP_0_EXC_PC ;\ 338 .set noat ;\ 339 RESTORE_REG(AT, AST, sp) ;\ 340 RESTORE_REG(v0, V0, sp) ;\ 341 RESTORE_REG(v1, V1, sp) ;\ 342 RESTORE_REG(a0, A0, sp) ;\ 343 RESTORE_REG(a1, A1, sp) ;\ 344 RESTORE_REG(a2, A2, sp) ;\ 345 RESTORE_REG(a3, A3, sp) ;\ 346 RESTORE_REG(t0, T0, sp) ;\ 347 RESTORE_REG(t1, T1, sp) ;\ 348 RESTORE_REG(t2, T2, sp) ;\ 349 RESTORE_REG(t3, T3, sp) ;\ 350 RESTORE_REG(ta0, TA0, sp) ;\ 351 RESTORE_REG(ta1, TA1, sp) ;\ 352 RESTORE_REG(ta2, TA2, sp) ;\ 353 RESTORE_REG(ta3, TA3, sp) ;\ 354 RESTORE_REG(t8, T8, sp) ;\ 355 RESTORE_REG(t9, T9, sp) ;\ 356 RESTORE_REG(s0, S0, sp) ;\ 357 RESTORE_REG(s1, S1, sp) ;\ 358 RESTORE_REG(s2, S2, sp) ;\ 359 RESTORE_REG(s3, S3, sp) ;\ 360 RESTORE_REG(s4, S4, sp) ;\ 361 RESTORE_REG(s5, S5, sp) ;\ 362 RESTORE_REG(s6, S6, sp) ;\ 363 RESTORE_REG(s7, S7, sp) ;\ 364 RESTORE_REG(s8, S8, sp) ;\ 365 RESTORE_REG(gp, GP, sp) ;\ 366 RESTORE_REG(ra, RA, sp) ;\ 367 PTR_ADDU sp, sp, KERN_EXC_FRAME_SIZE;\ 368 mtc0 k0, MIPS_COP_0_STATUS 369 370 371/* 372 * The kernel exception stack contains 18 saved general registers, 373 * the status register and the multiply lo and high registers. 374 * In addition, we set this up for linkage conventions. 375 */ 376#define KERN_REG_SIZE (NUMSAVEREGS * SZREG) 377#define KERN_EXC_FRAME_SIZE (CALLFRAME_SIZ + KERN_REG_SIZE + 16) 378 379NESTED_NOPROFILE(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra) 380 .set noat 381 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE 382 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE) 383/* 384 * Save CPU state, building 'frame'. 385 */ 386 SAVE_CPU 387/* 388 * Call the exception handler. a0 points at the saved frame. 389 */ 390 PTR_LA gp, _C_LABEL(_gp) 391 PTR_LA k0, _C_LABEL(trap) 392 jalr k0 393 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging 394 395 /* 396 * Update interrupt and CPU mask in saved status register 397 * Some of interrupts could be disabled by 398 * intr filters if interrupts are enabled later 399 * in trap handler 400 */ 401 mfc0 a0, MIPS_COP_0_STATUS 402 and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) 403 RESTORE_REG(a1, SR, sp) 404 and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) 405 or a1, a1, a0 406 SAVE_REG(a1, SR, sp) 407 RESTORE_CPU # v0 contains the return address. 408 sync 409 eret 410 .set at 411END(MipsKernGenException) 412 413 414/*---------------------------------------------------------------------------- 415 * 416 * MipsUserGenException -- 417 * 418 * Handle an exception from user mode. 419 * 420 * Results: 421 * None. 422 * 423 * Side effects: 424 * None. 425 * 426 *---------------------------------------------------------------------------- 427 */ 428NESTED_NOPROFILE(MipsUserGenException, CALLFRAME_SIZ, ra) 429 .set noat 430 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 431/* 432 * Save all of the registers except for the kernel temporaries in u.u_pcb. 433 */ 434 GET_CPU_PCPU(k1) 435 PTR_L k1, PC_CURPCB(k1) 436 SAVE_U_PCB_REG(AT, AST, k1) 437 .set at 438 SAVE_U_PCB_REG(v0, V0, k1) 439 SAVE_U_PCB_REG(v1, V1, k1) 440 SAVE_U_PCB_REG(a0, A0, k1) 441 mflo v0 442 SAVE_U_PCB_REG(a1, A1, k1) 443 SAVE_U_PCB_REG(a2, A2, k1) 444 SAVE_U_PCB_REG(a3, A3, k1) 445 SAVE_U_PCB_REG(t0, T0, k1) 446 mfhi v1 447 SAVE_U_PCB_REG(t1, T1, k1) 448 SAVE_U_PCB_REG(t2, T2, k1) 449 SAVE_U_PCB_REG(t3, T3, k1) 450 SAVE_U_PCB_REG(ta0, TA0, k1) 451 mfc0 a0, MIPS_COP_0_STATUS # First arg is the status reg. 452 SAVE_U_PCB_REG(ta1, TA1, k1) 453 SAVE_U_PCB_REG(ta2, TA2, k1) 454 SAVE_U_PCB_REG(ta3, TA3, k1) 455 SAVE_U_PCB_REG(s0, S0, k1) 456 mfc0 a1, MIPS_COP_0_CAUSE # Second arg is the cause reg. 457 SAVE_U_PCB_REG(s1, S1, k1) 458 SAVE_U_PCB_REG(s2, S2, k1) 459 SAVE_U_PCB_REG(s3, S3, k1) 460 SAVE_U_PCB_REG(s4, S4, k1) 461 MFC0 a2, MIPS_COP_0_BAD_VADDR # Third arg is the fault addr 462 SAVE_U_PCB_REG(s5, S5, k1) 463 SAVE_U_PCB_REG(s6, S6, k1) 464 SAVE_U_PCB_REG(s7, S7, k1) 465 SAVE_U_PCB_REG(t8, T8, k1) 466 MFC0 a3, MIPS_COP_0_EXC_PC # Fourth arg is the pc. 467 SAVE_U_PCB_REG(t9, T9, k1) 468 SAVE_U_PCB_REG(gp, GP, k1) 469 SAVE_U_PCB_REG(sp, SP, k1) 470 SAVE_U_PCB_REG(s8, S8, k1) 471 PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP 472 SAVE_U_PCB_REG(ra, RA, k1) 473 SAVE_U_PCB_REG(v0, MULLO, k1) 474 SAVE_U_PCB_REG(v1, MULHI, k1) 475 SAVE_U_PCB_REG(a0, SR, k1) 476 SAVE_U_PCB_REG(a1, CAUSE, k1) 477 SAVE_U_PCB_REG(a2, BADVADDR, k1) 478 SAVE_U_PCB_REG(a3, PC, k1) 479 REG_S a3, CALLFRAME_RA(sp) # for debugging 480 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP 481# Turn off fpu and enter kernel mode 482 and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_KSU_MASK | MIPS_SR_INT_IE) 483#if defined(CPU_CNMIPS) 484 and t0, t0, ~(MIPS_SR_COP_2_BIT) 485 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX) 486#elif defined(CPU_RMI) || defined(CPU_NLM) 487 or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) 488#endif 489 mtc0 t0, MIPS_COP_0_STATUS 490 PTR_ADDU a0, k1, U_PCB_REGS 491 ITLBNOPFIX 492 493/* 494 * Call the exception handler. 495 */ 496 PTR_LA k0, _C_LABEL(trap) 497 jalr k0 498 nop 499 500/* 501 * Restore user registers and return. 502 * First disable interrupts and set exeption level. 503 */ 504 DO_AST 505 506 CLEAR_STATUS 507 508/* 509 * The use of k1 for storing the PCB pointer must be done only 510 * after interrupts are disabled. Otherwise it will get overwritten 511 * by the interrupt code. 512 */ 513 GET_CPU_PCPU(k1) 514 PTR_L k1, PC_CURPCB(k1) 515 516 /* 517 * Update interrupt mask in saved status register 518 * Some of interrupts could be enabled by ithread 519 * scheduled by ast() 520 */ 521 mfc0 a0, MIPS_COP_0_STATUS 522 and a0, a0, MIPS_SR_INT_MASK 523 RESTORE_U_PCB_REG(a1, SR, k1) 524 and a1, a1, ~MIPS_SR_INT_MASK 525 or a1, a1, a0 526 SAVE_U_PCB_REG(a1, SR, k1) 527 528 RESTORE_U_PCB_REG(t0, MULLO, k1) 529 RESTORE_U_PCB_REG(t1, MULHI, k1) 530 mtlo t0 531 mthi t1 532 RESTORE_U_PCB_REG(a0, PC, k1) 533 RESTORE_U_PCB_REG(v0, V0, k1) 534 MTC0 a0, MIPS_COP_0_EXC_PC # set return address 535 RESTORE_U_PCB_REG(v1, V1, k1) 536 RESTORE_U_PCB_REG(a0, A0, k1) 537 RESTORE_U_PCB_REG(a1, A1, k1) 538 RESTORE_U_PCB_REG(a2, A2, k1) 539 RESTORE_U_PCB_REG(a3, A3, k1) 540 RESTORE_U_PCB_REG(t0, T0, k1) 541 RESTORE_U_PCB_REG(t1, T1, k1) 542 RESTORE_U_PCB_REG(t2, T2, k1) 543 RESTORE_U_PCB_REG(t3, T3, k1) 544 RESTORE_U_PCB_REG(ta0, TA0, k1) 545 RESTORE_U_PCB_REG(ta1, TA1, k1) 546 RESTORE_U_PCB_REG(ta2, TA2, k1) 547 RESTORE_U_PCB_REG(ta3, TA3, k1) 548 RESTORE_U_PCB_REG(s0, S0, k1) 549 RESTORE_U_PCB_REG(s1, S1, k1) 550 RESTORE_U_PCB_REG(s2, S2, k1) 551 RESTORE_U_PCB_REG(s3, S3, k1) 552 RESTORE_U_PCB_REG(s4, S4, k1) 553 RESTORE_U_PCB_REG(s5, S5, k1) 554 RESTORE_U_PCB_REG(s6, S6, k1) 555 RESTORE_U_PCB_REG(s7, S7, k1) 556 RESTORE_U_PCB_REG(t8, T8, k1) 557 RESTORE_U_PCB_REG(t9, T9, k1) 558 RESTORE_U_PCB_REG(gp, GP, k1) 559 RESTORE_U_PCB_REG(sp, SP, k1) 560 RESTORE_U_PCB_REG(k0, SR, k1) 561 RESTORE_U_PCB_REG(s8, S8, k1) 562 RESTORE_U_PCB_REG(ra, RA, k1) 563 .set noat 564 RESTORE_U_PCB_REG(AT, AST, k1) 565 566 mtc0 k0, MIPS_COP_0_STATUS # still exception level 567 ITLBNOPFIX 568 sync 569 eret 570 .set at 571END(MipsUserGenException) 572 573 .set push 574 .set noat 575NESTED(mips_wait, CALLFRAME_SIZ, ra) 576 PTR_SUBU sp, sp, CALLFRAME_SIZ 577 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 578 REG_S ra, CALLFRAME_RA(sp) # save RA 579 mfc0 t0, MIPS_COP_0_STATUS 580 xori t1, t0, MIPS_SR_INT_IE 581 mtc0 t1, MIPS_COP_0_STATUS 582 COP0_SYNC 583 jal sched_runnable 584 nop 585 REG_L ra, CALLFRAME_RA(sp) 586 mfc0 t0, MIPS_COP_0_STATUS 587 ori t1, t0, MIPS_SR_INT_IE 588 .align 4 589GLOBAL(MipsWaitStart) # this is 16 byte aligned 590 mtc0 t1, MIPS_COP_0_STATUS 591 bnez v0, MipsWaitEnd 592 nop 593 wait 594GLOBAL(MipsWaitEnd) # MipsWaitStart + 16 595 jr ra 596 PTR_ADDU sp, sp, CALLFRAME_SIZ 597END(mips_wait) 598 .set pop 599 600/*---------------------------------------------------------------------------- 601 * 602 * MipsKernIntr -- 603 * 604 * Handle an interrupt from kernel mode. 605 * Interrupts use the standard kernel stack. 606 * switch_exit sets up a kernel stack after exit so interrupts won't fail. 607 * 608 * Results: 609 * None. 610 * 611 * Side effects: 612 * None. 613 * 614 *---------------------------------------------------------------------------- 615 */ 616 617NESTED_NOPROFILE(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra) 618 .set noat 619 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE 620 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE) 621 622/* 623 * Check for getting interrupts just before wait 624 */ 625 MFC0 k0, MIPS_COP_0_EXC_PC 626 ori k0, 0xf 627 xori k0, 0xf # 16 byte align 628 PTR_LA k1, MipsWaitStart 629 bne k0, k1, 1f 630 nop 631 PTR_ADDU k1, 16 # skip over wait 632 MTC0 k1, MIPS_COP_0_EXC_PC 6331: 634/* 635 * Save CPU state, building 'frame'. 636 */ 637 SAVE_CPU 638/* 639 * Call the interrupt handler. a0 points at the saved frame. 640 */ 641 PTR_LA gp, _C_LABEL(_gp) 642#ifdef INTRNG 643 PTR_LA k0, _C_LABEL(intr_irq_handler) 644#else 645 PTR_LA k0, _C_LABEL(cpu_intr) 646#endif 647 jalr k0 648 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging 649 650 /* 651 * Update interrupt and CPU mask in saved status register 652 * Some of interrupts could be disabled by 653 * intr filters if interrupts are enabled later 654 * in trap handler 655 */ 656 mfc0 a0, MIPS_COP_0_STATUS 657 and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) 658 RESTORE_REG(a1, SR, sp) 659 and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) 660 or a1, a1, a0 661 SAVE_REG(a1, SR, sp) 662 REG_L v0, CALLFRAME_RA + KERN_REG_SIZE(sp) 663 RESTORE_CPU # v0 contains the return address. 664 sync 665 eret 666 .set at 667END(MipsKernIntr) 668 669/*---------------------------------------------------------------------------- 670 * 671 * MipsUserIntr -- 672 * 673 * Handle an interrupt from user mode. 674 * Note: we save minimal state in the u.u_pcb struct and use the standard 675 * kernel stack since there has to be a u page if we came from user mode. 676 * If there is a pending software interrupt, then save the remaining state 677 * and call softintr(). This is all because if we call switch() inside 678 * interrupt(), not all the user registers have been saved in u.u_pcb. 679 * 680 * Results: 681 * None. 682 * 683 * Side effects: 684 * None. 685 * 686 *---------------------------------------------------------------------------- 687 */ 688NESTED_NOPROFILE(MipsUserIntr, CALLFRAME_SIZ, ra) 689 .set noat 690 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 691/* 692 * Save the relevant user registers into the u.u_pcb struct. 693 * We don't need to save s0 - s8 because the compiler does it for us. 694 */ 695 GET_CPU_PCPU(k1) 696 PTR_L k1, PC_CURPCB(k1) 697 SAVE_U_PCB_REG(AT, AST, k1) 698 .set at 699 SAVE_U_PCB_REG(v0, V0, k1) 700 SAVE_U_PCB_REG(v1, V1, k1) 701 SAVE_U_PCB_REG(a0, A0, k1) 702 SAVE_U_PCB_REG(a1, A1, k1) 703 SAVE_U_PCB_REG(a2, A2, k1) 704 SAVE_U_PCB_REG(a3, A3, k1) 705 SAVE_U_PCB_REG(t0, T0, k1) 706 SAVE_U_PCB_REG(t1, T1, k1) 707 SAVE_U_PCB_REG(t2, T2, k1) 708 SAVE_U_PCB_REG(t3, T3, k1) 709 SAVE_U_PCB_REG(ta0, TA0, k1) 710 SAVE_U_PCB_REG(ta1, TA1, k1) 711 SAVE_U_PCB_REG(ta2, TA2, k1) 712 SAVE_U_PCB_REG(ta3, TA3, k1) 713 SAVE_U_PCB_REG(t8, T8, k1) 714 SAVE_U_PCB_REG(t9, T9, k1) 715 SAVE_U_PCB_REG(gp, GP, k1) 716 SAVE_U_PCB_REG(sp, SP, k1) 717 SAVE_U_PCB_REG(ra, RA, k1) 718/* 719 * save remaining user state in u.u_pcb. 720 */ 721 SAVE_U_PCB_REG(s0, S0, k1) 722 SAVE_U_PCB_REG(s1, S1, k1) 723 SAVE_U_PCB_REG(s2, S2, k1) 724 SAVE_U_PCB_REG(s3, S3, k1) 725 SAVE_U_PCB_REG(s4, S4, k1) 726 SAVE_U_PCB_REG(s5, S5, k1) 727 SAVE_U_PCB_REG(s6, S6, k1) 728 SAVE_U_PCB_REG(s7, S7, k1) 729 SAVE_U_PCB_REG(s8, S8, k1) 730 731 mflo v0 # get lo/hi late to avoid stall 732 mfhi v1 733 mfc0 a0, MIPS_COP_0_STATUS 734 mfc0 a1, MIPS_COP_0_CAUSE 735 MFC0 a3, MIPS_COP_0_EXC_PC 736 SAVE_U_PCB_REG(v0, MULLO, k1) 737 SAVE_U_PCB_REG(v1, MULHI, k1) 738 SAVE_U_PCB_REG(a0, SR, k1) 739 SAVE_U_PCB_REG(a1, CAUSE, k1) 740 SAVE_U_PCB_REG(a3, PC, k1) # PC in a3, note used later! 741 PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP 742 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP 743 744# Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level. 745 and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS_SR_KSU_MASK) 746#ifdef CPU_CNMIPS 747 and t0, t0, ~(MIPS_SR_COP_2_BIT) 748 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX) 749#elif defined(CPU_RMI) || defined(CPU_NLM) 750 or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) 751#endif 752 mtc0 t0, MIPS_COP_0_STATUS 753 ITLBNOPFIX 754 PTR_ADDU a0, k1, U_PCB_REGS 755/* 756 * Call the interrupt handler. 757 */ 758#ifdef INTRNG 759 PTR_LA k0, _C_LABEL(intr_irq_handler) 760#else 761 PTR_LA k0, _C_LABEL(cpu_intr) 762#endif 763 jalr k0 764 REG_S a3, CALLFRAME_RA(sp) # for debugging 765 766/* 767 * Enable interrupts before doing ast(). 768 * 769 * On SMP kernels the AST processing might trigger IPI to other processors. 770 * If that processor is also doing AST processing with interrupts disabled 771 * then we may deadlock. 772 */ 773 mfc0 a0, MIPS_COP_0_STATUS 774 or a0, a0, MIPS_SR_INT_IE 775 mtc0 a0, MIPS_COP_0_STATUS 776 ITLBNOPFIX 777 778/* 779 * DO_AST enabled interrupts 780 */ 781 DO_AST 782 783/* 784 * Restore user registers and return. 785 */ 786 CLEAR_STATUS 787 788 GET_CPU_PCPU(k1) 789 PTR_L k1, PC_CURPCB(k1) 790 791 /* 792 * Update interrupt mask in saved status register 793 * Some of interrupts could be disabled by 794 * intr filters 795 */ 796 mfc0 a0, MIPS_COP_0_STATUS 797 and a0, a0, MIPS_SR_INT_MASK 798 RESTORE_U_PCB_REG(a1, SR, k1) 799 and a1, a1, ~MIPS_SR_INT_MASK 800 or a1, a1, a0 801 SAVE_U_PCB_REG(a1, SR, k1) 802 803 RESTORE_U_PCB_REG(s0, S0, k1) 804 RESTORE_U_PCB_REG(s1, S1, k1) 805 RESTORE_U_PCB_REG(s2, S2, k1) 806 RESTORE_U_PCB_REG(s3, S3, k1) 807 RESTORE_U_PCB_REG(s4, S4, k1) 808 RESTORE_U_PCB_REG(s5, S5, k1) 809 RESTORE_U_PCB_REG(s6, S6, k1) 810 RESTORE_U_PCB_REG(s7, S7, k1) 811 RESTORE_U_PCB_REG(s8, S8, k1) 812 RESTORE_U_PCB_REG(t0, MULLO, k1) 813 RESTORE_U_PCB_REG(t1, MULHI, k1) 814 RESTORE_U_PCB_REG(t2, PC, k1) 815 mtlo t0 816 mthi t1 817 MTC0 t2, MIPS_COP_0_EXC_PC # set return address 818 RESTORE_U_PCB_REG(v0, V0, k1) 819 RESTORE_U_PCB_REG(v1, V1, k1) 820 RESTORE_U_PCB_REG(a0, A0, k1) 821 RESTORE_U_PCB_REG(a1, A1, k1) 822 RESTORE_U_PCB_REG(a2, A2, k1) 823 RESTORE_U_PCB_REG(a3, A3, k1) 824 RESTORE_U_PCB_REG(t0, T0, k1) 825 RESTORE_U_PCB_REG(t1, T1, k1) 826 RESTORE_U_PCB_REG(t2, T2, k1) 827 RESTORE_U_PCB_REG(t3, T3, k1) 828 RESTORE_U_PCB_REG(ta0, TA0, k1) 829 RESTORE_U_PCB_REG(ta1, TA1, k1) 830 RESTORE_U_PCB_REG(ta2, TA2, k1) 831 RESTORE_U_PCB_REG(ta3, TA3, k1) 832 RESTORE_U_PCB_REG(t8, T8, k1) 833 RESTORE_U_PCB_REG(t9, T9, k1) 834 RESTORE_U_PCB_REG(gp, GP, k1) 835 RESTORE_U_PCB_REG(k0, SR, k1) 836 RESTORE_U_PCB_REG(sp, SP, k1) 837 RESTORE_U_PCB_REG(ra, RA, k1) 838 .set noat 839 RESTORE_U_PCB_REG(AT, AST, k1) 840 841 mtc0 k0, MIPS_COP_0_STATUS # SR with EXL set. 842 ITLBNOPFIX 843 sync 844 eret 845 .set at 846END(MipsUserIntr) 847 848LEAF_NOPROFILE(MipsTLBInvalidException) 849 .set push 850 .set noat 851 .set noreorder 852 853 MFC0 k0, MIPS_COP_0_BAD_VADDR 854 PTR_LI k1, VM_MAXUSER_ADDRESS 855 sltu k1, k0, k1 856 bnez k1, 1f 857 nop 858 859 /* Kernel address. */ 860 lui k1, %hi(kernel_segmap) # k1=hi of segbase 861 b 2f 862 PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base 863 8641: /* User address. */ 865 GET_CPU_PCPU(k1) 866 PTR_L k1, PC_SEGBASE(k1) 867 8682: /* Validate page directory pointer. */ 869 beqz k1, 3f 870 nop 871 872 PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost) 873 beq k1, zero, MipsKernGenException # ==0 -- no seg tab 874 andi k0, k0, PDEPTRMASK #06: k0=seg offset 875 PTR_ADDU k1, k0, k1 # k1=seg entry address 876 PTR_L k1, 0(k1) # k1=seg entry 877 878 /* Validate page table pointer. */ 879 beqz k1, 3f 880 nop 881 882#ifdef __mips_n64 883 MFC0 k0, MIPS_COP_0_BAD_VADDR 884 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=pde offset (almost) 885 beq k1, zero, MipsKernGenException # ==0 -- no pde tab 886 andi k0, k0, PDEPTRMASK # k0=pde offset 887 PTR_ADDU k1, k0, k1 # k1=pde entry address 888 PTR_L k1, 0(k1) # k1=pde entry 889 890 /* Validate pde table pointer. */ 891 beqz k1, 3f 892 nop 893#endif 894 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) 895 PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN 896 andi k0, k0, PTEMASK # k0=page tab offset 897 PTR_ADDU k1, k1, k0 # k1=pte address 898 PTE_L k0, 0(k1) # k0=this PTE 899 900 /* Validate page table entry. */ 901 andi k0, PTE_V 902 beqz k0, 3f 903 nop 904 905 /* Check whether this is an even or odd entry. */ 906 andi k0, k1, PTESIZE 907 bnez k0, odd_page 908 nop 909 910 PTE_L k0, 0(k1) 911 PTE_L k1, PTESIZE(k1) 912 CLEAR_PTE_SWBITS(k0) 913 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 914 COP0_SYNC 915 CLEAR_PTE_SWBITS(k1) 916 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 917 COP0_SYNC 918 919 b tlb_insert_entry 920 nop 921 922odd_page: 923 PTE_L k0, -PTESIZE(k1) 924 PTE_L k1, 0(k1) 925 CLEAR_PTE_SWBITS(k0) 926 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 927 COP0_SYNC 928 CLEAR_PTE_SWBITS(k1) 929 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 930 COP0_SYNC 931 932tlb_insert_entry: 933 tlbp 934 HAZARD_DELAY 935 mfc0 k0, MIPS_COP_0_TLB_INDEX 936 bltz k0, tlb_insert_random 937 nop 938 tlbwi 939 eret 940 ssnop 941 942tlb_insert_random: 943 tlbwr 944 eret 945 ssnop 946 9473: 948 /* 949 * Branch to the comprehensive exception processing. 950 */ 951 mfc0 k1, MIPS_COP_0_STATUS 952 andi k1, k1, MIPS_SR_KSU_USER 953 bnez k1, _C_LABEL(MipsUserGenException) 954 nop 955 956 /* 957 * Check for kernel stack overflow. 958 */ 959 GET_CPU_PCPU(k1) 960 PTR_L k0, PC_CURTHREAD(k1) 961 PTR_L k0, TD_KSTACK(k0) 962 sltu k0, k0, sp 963 bnez k0, _C_LABEL(MipsKernGenException) 964 nop 965 966 /* 967 * Kernel stack overflow. 968 * 969 * Move to a valid stack before we call panic. We use the boot stack 970 * for this purpose. 971 */ 972 GET_CPU_PCPU(k1) 973 lw k1, PC_CPUID(k1) 974 sll k1, k1, PAGE_SHIFT + 1 975 976 PTR_LA k0, _C_LABEL(pcpu_space) 977 PTR_ADDU k0, PAGE_SIZE * 2 978 PTR_ADDU k0, k0, k1 979 980 /* 981 * Stash the original value of 'sp' so we can update trapframe later. 982 * We assume that SAVE_CPU does not trash 'k1'. 983 */ 984 move k1, sp 985 986 move sp, k0 987 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE 988 989 move k0, ra 990 move ra, zero 991 REG_S ra, CALLFRAME_RA(sp) /* stop the ddb backtrace right here */ 992 REG_S zero, CALLFRAME_SP(sp) 993 move ra, k0 994 995 SAVE_CPU 996 997 /* 998 * Now restore the value of 'sp' at the time of the tlb exception in 999 * the trapframe. 1000 */ 1001 SAVE_REG(k1, SP, sp) 1002 1003 /* 1004 * Squelch any more overflow checks by setting the stack base to 0. 1005 */ 1006 GET_CPU_PCPU(k1) 1007 PTR_L k0, PC_CURTHREAD(k1) 1008 PTR_S zero, TD_KSTACK(k0) 1009 1010 move a1, a0 1011 PANIC("kernel stack overflow - trapframe at %p") 1012 1013 /* 1014 * This nop is necessary so that the 'ra' remains within the bounds 1015 * of this handler. Otherwise the ddb backtrace code will think that 1016 * the panic() was called from MipsTLBMissException. 1017 */ 1018 nop 1019 1020 .set pop 1021END(MipsTLBInvalidException) 1022 1023/*---------------------------------------------------------------------------- 1024 * 1025 * MipsTLBMissException -- 1026 * 1027 * Handle a TLB miss exception from kernel mode in kernel space. 1028 * The BaddVAddr, Context, and EntryHi registers contain the failed 1029 * virtual address. 1030 * 1031 * Results: 1032 * None. 1033 * 1034 * Side effects: 1035 * None. 1036 * 1037 *---------------------------------------------------------------------------- 1038 */ 1039LEAF_NOPROFILE(MipsTLBMissException) 1040 .set noat 1041 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address 1042 PTR_LI k1, VM_MAX_KERNEL_ADDRESS # check fault address against 1043 sltu k1, k1, k0 # upper bound of kernel_segmap 1044 bnez k1, MipsKernGenException # out of bound 1045 lui k1, %hi(kernel_segmap) # k1=hi of segbase 1046 PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost) 1047 PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base 1048 beq k1, zero, MipsKernGenException # ==0 -- no seg tab 1049 andi k0, k0, PDEPTRMASK #06: k0=seg offset 1050 PTR_ADDU k1, k0, k1 # k1=seg entry address 1051 PTR_L k1, 0(k1) # k1=seg entry 1052 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) 1053 beq k1, zero, MipsKernGenException # ==0 -- no page table 1054#ifdef __mips_n64 1055 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN 1056 andi k0, k0, PDEPTRMASK # k0=pde offset 1057 PTR_ADDU k1, k0, k1 # k1=pde entry address 1058 PTR_L k1, 0(k1) # k1=pde entry 1059 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) 1060 beq k1, zero, MipsKernGenException # ==0 -- no page table 1061#endif 1062 PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN 1063 andi k0, k0, PTE2MASK # k0=page tab offset 1064 PTR_ADDU k1, k1, k0 # k1=pte address 1065 PTE_L k0, 0(k1) # k0=lo0 pte 1066 PTE_L k1, PTESIZE(k1) # k1=lo1 pte 1067 CLEAR_PTE_SWBITS(k0) 1068 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 # lo0 is loaded 1069 COP0_SYNC 1070 CLEAR_PTE_SWBITS(k1) 1071 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded 1072 COP0_SYNC 1073 tlbwr # write to tlb 1074 HAZARD_DELAY 1075 eret # return from exception 1076 .set at 1077END(MipsTLBMissException) 1078 1079/*---------------------------------------------------------------------------- 1080 * 1081 * MipsFPTrap -- 1082 * 1083 * Handle a floating point Trap. 1084 * 1085 * MipsFPTrap(statusReg, causeReg, pc) 1086 * unsigned statusReg; 1087 * unsigned causeReg; 1088 * unsigned pc; 1089 * 1090 * Results: 1091 * None. 1092 * 1093 * Side effects: 1094 * None. 1095 * 1096 *---------------------------------------------------------------------------- 1097 */ 1098NESTED(MipsFPTrap, CALLFRAME_SIZ, ra) 1099 PTR_SUBU sp, sp, CALLFRAME_SIZ 1100 mfc0 t0, MIPS_COP_0_STATUS 1101 REG_S ra, CALLFRAME_RA(sp) 1102 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 1103 1104 or t1, t0, MIPS_SR_COP_1_BIT 1105 mtc0 t1, MIPS_COP_0_STATUS 1106 ITLBNOPFIX 1107 cfc1 t1, MIPS_FPU_CSR # stall til FP done 1108 cfc1 t1, MIPS_FPU_CSR # now get status 1109 nop 1110 sll t2, t1, (31 - 17) # unimplemented operation? 1111 bgez t2, 3f # no, normal trap 1112 nop 1113/* 1114 * We got an unimplemented operation trap so 1115 * fetch the instruction, compute the next PC and emulate the instruction. 1116 */ 1117 bgez a1, 1f # Check the branch delay bit. 1118 nop 1119/* 1120 * The instruction is in the branch delay slot so the branch will have to 1121 * be emulated to get the resulting PC. 1122 */ 1123 PTR_S a2, CALLFRAME_SIZ + 8(sp) 1124 GET_CPU_PCPU(a0) 1125#mips64 unsafe? 1126 PTR_L a0, PC_CURPCB(a0) 1127 PTR_ADDU a0, a0, U_PCB_REGS # first arg is ptr to CPU registers 1128 move a1, a2 # second arg is instruction PC 1129 move a2, t1 # third arg is floating point CSR 1130 PTR_LA t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch 1131 jalr t3 # compute PC after branch 1132 move a3, zero # fourth arg is FALSE 1133/* 1134 * Now load the floating-point instruction in the branch delay slot 1135 * to be emulated. 1136 */ 1137 PTR_L a2, CALLFRAME_SIZ + 8(sp) # restore EXC pc 1138 b 2f 1139 lw a0, 4(a2) # a0 = coproc instruction 1140/* 1141 * This is not in the branch delay slot so calculate the resulting 1142 * PC (epc + 4) into v0 and continue to MipsEmulateFP(). 1143 */ 11441: 1145 lw a0, 0(a2) # a0 = coproc instruction 1146#xxx mips64 unsafe? 1147 PTR_ADDU v0, a2, 4 # v0 = next pc 11482: 1149 GET_CPU_PCPU(t2) 1150 PTR_L t2, PC_CURPCB(t2) 1151 SAVE_U_PCB_REG(v0, PC, t2) # save new pc 1152/* 1153 * Check to see if the instruction to be emulated is a floating-point 1154 * instruction. 1155 */ 1156 srl a3, a0, MIPS_OPCODE_SHIFT 1157 beq a3, MIPS_OPCODE_C1, 4f # this should never fail 1158 nop 1159/* 1160 * Send a floating point exception signal to the current process. 1161 */ 11623: 1163 GET_CPU_PCPU(a0) 1164 PTR_L a0, PC_CURTHREAD(a0) # get current thread 1165 cfc1 a2, MIPS_FPU_CSR # code = FP execptions 1166 ctc1 zero, MIPS_FPU_CSR # Clear exceptions 1167 PTR_LA t3, _C_LABEL(trapsignal) 1168 jalr t3 1169 li a1, SIGFPE 1170 b FPReturn 1171 nop 1172 1173/* 1174 * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate. 1175 */ 11764: 1177 PTR_LA t3, _C_LABEL(MipsEmulateFP) 1178 jalr t3 1179 nop 1180 1181/* 1182 * Turn off the floating point coprocessor and return. 1183 */ 1184FPReturn: 1185 mfc0 t0, MIPS_COP_0_STATUS 1186 PTR_L ra, CALLFRAME_RA(sp) 1187 and t0, t0, ~MIPS_SR_COP_1_BIT 1188 mtc0 t0, MIPS_COP_0_STATUS 1189 ITLBNOPFIX 1190 j ra 1191 PTR_ADDU sp, sp, CALLFRAME_SIZ 1192END(MipsFPTrap) 1193 1194#ifndef INTRNG 1195/* 1196 * Interrupt counters for vmstat. 1197 */ 1198 .data 1199 .globl intrcnt 1200 .globl sintrcnt 1201 .globl intrnames 1202 .globl sintrnames 1203intrnames: 1204 .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 1205sintrnames: 1206#ifdef __mips_n64 1207 .quad INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 1208#else 1209 .int INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 1210#endif 1211 1212 .align (_MIPS_SZLONG / 8) 1213intrcnt: 1214 .space INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 1215sintrcnt: 1216#ifdef __mips_n64 1217 .quad INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 1218#else 1219 .int INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 1220#endif 1221#endif /* INTRNG */ 1222 1223 1224/* 1225 * Vector to real handler in KSEG1. 1226 */ 1227 .text 1228VECTOR(MipsCache, unknown) 1229 PTR_LA k0, _C_LABEL(MipsCacheException) 1230 li k1, MIPS_KSEG0_PHYS_MASK 1231 and k0, k1 1232 PTR_LI k1, MIPS_KSEG1_START 1233 or k0, k1 1234 j k0 1235 nop 1236VECTOR_END(MipsCache) 1237 1238 .set at 1239 1240 1241/* 1242 * Panic on cache errors. A lot more could be done to recover 1243 * from some types of errors but it is tricky. 1244 */ 1245NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra) 1246 .set noat 1247 .mask 0x80000000, -4 1248 PTR_LA k0, _C_LABEL(panic) # return to panic 1249 PTR_LA a0, 9f # panicstr 1250 MFC0 a1, MIPS_COP_0_ERROR_PC 1251 mfc0 a2, MIPS_COP_0_CACHE_ERR # 3rd arg cache error 1252 1253 MTC0 k0, MIPS_COP_0_ERROR_PC # set return address 1254 1255 mfc0 k0, MIPS_COP_0_STATUS # restore status 1256 li k1, MIPS_SR_DIAG_PE # ignore further errors 1257 or k0, k1 1258 mtc0 k0, MIPS_COP_0_STATUS # restore status 1259 COP0_SYNC 1260 1261 eret 1262 1263 MSG("cache error @ EPC 0x%x CachErr 0x%x"); 1264 .set at 1265END(MipsCacheException) 1266