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 * 3. 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.inc" 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 *---------------------------------------------------------------------------- 85 * 86 * MipsTLBMiss -- 87 * 88 * Vector code for the TLB-miss exception vector 0x80000000. 89 * 90 * This code is copied to the TLB exception vector address to 91 * which the CPU jumps in response to an exception or a TLB miss. 92 * NOTE: This code must be position independent!!! 93 * 94 * 95 */ 96VECTOR(MipsTLBMiss, unknown) 97 .set push 98 .set noat 99 j MipsDoTLBMiss 100 MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address 101 .set pop 102VECTOR_END(MipsTLBMiss) 103 104/* 105 *---------------------------------------------------------------------------- 106 * 107 * MipsDoTLBMiss -- 108 * 109 * This is the real TLB Miss Handler code. 110 * 'segbase' points to the base of the segment table for user processes. 111 * 112 * Don't check for invalid pte's here. We load them as well and 113 * let the processor trap to load the correct value after service. 114 *---------------------------------------------------------------------------- 115 */ 116 .set push 117 .set noat 118MipsDoTLBMiss: 119 bltz k0, 1f #02: k0<0 -> 1f (kernel fault) 120 PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost) 121 122 GET_CPU_PCPU(k1) 123 PTR_L k1, PC_SEGBASE(k1) 124 beqz k1, 2f #05: make sure segbase is not null 125 andi k0, k0, PDEPTRMASK #06: k0=seg offset 126 PTR_ADDU k1, k0, k1 #07: k1=seg entry address 127 128 PTR_L k1, 0(k1) #08: k1=seg entry 129 MFC0 k0, MIPS_COP_0_BAD_VADDR #09: k0=bad address (again) 130 beq k1, zero, 2f #0a: ==0 -- no page table 131#ifdef __mips_n64 132 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN 133 andi k0, k0, PDEPTRMASK # k0=pde offset 134 PTR_ADDU k1, k0, k1 # k1=pde entry address 135 PTR_L k1, 0(k1) # k1=pde entry 136 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) 137 beq k1, zero, 2f # ==0 -- no page table 138#endif 139 PTR_SRL k0, PAGE_SHIFT - PTESHIFT #0b: k0=VPN (aka va>>10) 140 andi k0, k0, PTE2MASK #0c: k0=page tab offset 141 PTR_ADDU k1, k1, k0 #0d: k1=pte address 142 PTE_L k0, 0(k1) #0e: k0=lo0 pte 143 PTE_L k1, PTESIZE(k1) #0f: k1=lo0 pte 144 CLEAR_PTE_SWBITS(k0) 145 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded 146 COP0_SYNC 147 CLEAR_PTE_SWBITS(k1) 148 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded 149 COP0_SYNC 150 tlbwr #1a: write to tlb 151 HAZARD_DELAY 152 eret #1f: retUrn from exception 1531: j MipsTLBMissException #20: kernel exception 154 nop #21: branch delay slot 1552: j SlowFault #22: no page table present 156 nop #23: branch delay slot 157 .set pop 158 159/* 160 * This code is copied to the general exception vector address to 161 * handle all execptions except RESET and TLBMiss. 162 * NOTE: This code must be position independent!!! 163 */ 164VECTOR(MipsException, unknown) 165/* 166 * Find out what mode we came from and jump to the proper handler. 167 * 168 * Note: at turned off here because we cannot trash the at register 169 * in this exception code. Only k0 and k1 may be modified before 170 * we save registers. This is true of all functions called through 171 * the pointer magic: Mips{User,Kern}Intr, Mips{User,Kern}GenException 172 * and MipsTLBInvalidException 173 */ 174 .set noat 175 mfc0 k0, MIPS_COP_0_STATUS # Get the status register 176 mfc0 k1, MIPS_COP_0_CAUSE # Get the cause register value. 177 and k0, k0, MIPS_SR_KSU_USER # test for user mode 178 # sneaky but the bits are 179 # with us........ 180 sll k0, k0, 3 # shift user bit for cause index 181 and k1, k1, MIPS_CR_EXC_CODE # Mask out the cause bits. 182 or k1, k1, k0 # change index to user table 183#if defined(__mips_n64) 184 PTR_SLL k1, k1, 1 # shift to get 8-byte offset 185#endif 1861: 187 PTR_LA k0, _C_LABEL(machExceptionTable) # get base of the jump table 188 PTR_ADDU k0, k0, k1 # Get the address of the 189 # function entry. Note that 190 # the cause is already 191 # shifted left by 2 bits so 192 # we dont have to shift. 193 PTR_L k0, 0(k0) # Get the function address 194 nop 195 j k0 # Jump to the function. 196 nop 197 .set at 198VECTOR_END(MipsException) 199 200/* 201 * We couldn't find a TLB entry. 202 * Find out what mode we came from and call the appropriate handler. 203 */ 204SlowFault: 205 .set noat 206 mfc0 k0, MIPS_COP_0_STATUS 207 nop 208 and k0, k0, MIPS_SR_KSU_USER 209 bne k0, zero, _C_LABEL(MipsUserGenException) 210 nop 211 .set at 212/* 213 * Fall though ... 214 */ 215 216/*---------------------------------------------------------------------------- 217 * 218 * MipsKernGenException -- 219 * 220 * Handle an exception from kernel mode. 221 * 222 * Results: 223 * None. 224 * 225 * Side effects: 226 * None. 227 * 228 *---------------------------------------------------------------------------- 229 */ 230 231#define SAVE_REG(reg, offs, base) \ 232 REG_S reg, CALLFRAME_SIZ + (SZREG * offs) (base) 233 234#if defined(CPU_CNMIPS) 235#define CLEAR_STATUS \ 236 mfc0 a0, MIPS_COP_0_STATUS ;\ 237 li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \ 238 or a0, a0, a2 ; \ 239 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ 240 and a0, a0, a2 ; \ 241 mtc0 a0, MIPS_COP_0_STATUS ; \ 242 ITLBNOPFIX 243#elif defined(CPU_RMI) || defined(CPU_NLM) 244#define CLEAR_STATUS \ 245 mfc0 a0, MIPS_COP_0_STATUS ;\ 246 li a2, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) ; \ 247 or a0, a0, a2 ; \ 248 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ 249 and a0, a0, a2 ; \ 250 mtc0 a0, MIPS_COP_0_STATUS ; \ 251 ITLBNOPFIX 252#else 253#define CLEAR_STATUS \ 254 mfc0 a0, MIPS_COP_0_STATUS ;\ 255 li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ 256 and a0, a0, a2 ; \ 257 mtc0 a0, MIPS_COP_0_STATUS ; \ 258 ITLBNOPFIX 259#endif 260 261/* 262 * Save CPU and CP0 register state. 263 * 264 * This is straightforward except for saving the exception program 265 * counter. The ddb backtrace code looks for the first instruction 266 * matching the form "sw ra, (off)sp" to figure out the address of the 267 * calling function. So we must make sure that we save the exception 268 * PC by staging it through 'ra' as opposed to any other register. 269 */ 270#define SAVE_CPU \ 271 SAVE_REG(AT, AST, sp) ;\ 272 .set at ; \ 273 SAVE_REG(v0, V0, sp) ;\ 274 SAVE_REG(v1, V1, sp) ;\ 275 SAVE_REG(a0, A0, sp) ;\ 276 SAVE_REG(a1, A1, sp) ;\ 277 SAVE_REG(a2, A2, sp) ;\ 278 SAVE_REG(a3, A3, sp) ;\ 279 SAVE_REG(t0, T0, sp) ;\ 280 SAVE_REG(t1, T1, sp) ;\ 281 SAVE_REG(t2, T2, sp) ;\ 282 SAVE_REG(t3, T3, sp) ;\ 283 SAVE_REG(ta0, TA0, sp) ;\ 284 SAVE_REG(ta1, TA1, sp) ;\ 285 SAVE_REG(ta2, TA2, sp) ;\ 286 SAVE_REG(ta3, TA3, sp) ;\ 287 SAVE_REG(t8, T8, sp) ;\ 288 SAVE_REG(t9, T9, sp) ;\ 289 SAVE_REG(gp, GP, sp) ;\ 290 SAVE_REG(s0, S0, sp) ;\ 291 SAVE_REG(s1, S1, sp) ;\ 292 SAVE_REG(s2, S2, sp) ;\ 293 SAVE_REG(s3, S3, sp) ;\ 294 SAVE_REG(s4, S4, sp) ;\ 295 SAVE_REG(s5, S5, sp) ;\ 296 SAVE_REG(s6, S6, sp) ;\ 297 SAVE_REG(s7, S7, sp) ;\ 298 SAVE_REG(s8, S8, sp) ;\ 299 mflo v0 ;\ 300 mfhi v1 ;\ 301 mfc0 a0, MIPS_COP_0_STATUS ;\ 302 mfc0 a1, MIPS_COP_0_CAUSE ;\ 303 MFC0 a2, MIPS_COP_0_BAD_VADDR;\ 304 MFC0 a3, MIPS_COP_0_EXC_PC ;\ 305 SAVE_REG(v0, MULLO, sp) ;\ 306 SAVE_REG(v1, MULHI, sp) ;\ 307 SAVE_REG(a0, SR, sp) ;\ 308 SAVE_REG(a1, CAUSE, sp) ;\ 309 SAVE_REG(a2, BADVADDR, sp) ;\ 310 move t0, ra ;\ 311 move ra, a3 ;\ 312 SAVE_REG(ra, PC, sp) ;\ 313 move ra, t0 ;\ 314 SAVE_REG(ra, RA, sp) ;\ 315 PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\ 316 SAVE_REG(v0, SP, sp) ;\ 317 CLEAR_STATUS ;\ 318 PTR_ADDU a0, sp, CALLFRAME_SIZ ;\ 319 ITLBNOPFIX 320 321#define RESTORE_REG(reg, offs, base) \ 322 REG_L reg, CALLFRAME_SIZ + (SZREG * offs) (base) 323 324#define RESTORE_CPU \ 325 CLEAR_STATUS ;\ 326 RESTORE_REG(k0, SR, sp) ;\ 327 RESTORE_REG(t0, MULLO, sp) ;\ 328 RESTORE_REG(t1, MULHI, sp) ;\ 329 mtlo t0 ;\ 330 mthi t1 ;\ 331 MTC0 v0, MIPS_COP_0_EXC_PC ;\ 332 .set noat ;\ 333 RESTORE_REG(AT, AST, sp) ;\ 334 RESTORE_REG(v0, V0, sp) ;\ 335 RESTORE_REG(v1, V1, sp) ;\ 336 RESTORE_REG(a0, A0, sp) ;\ 337 RESTORE_REG(a1, A1, sp) ;\ 338 RESTORE_REG(a2, A2, sp) ;\ 339 RESTORE_REG(a3, A3, sp) ;\ 340 RESTORE_REG(t0, T0, sp) ;\ 341 RESTORE_REG(t1, T1, sp) ;\ 342 RESTORE_REG(t2, T2, sp) ;\ 343 RESTORE_REG(t3, T3, sp) ;\ 344 RESTORE_REG(ta0, TA0, sp) ;\ 345 RESTORE_REG(ta1, TA1, sp) ;\ 346 RESTORE_REG(ta2, TA2, sp) ;\ 347 RESTORE_REG(ta3, TA3, sp) ;\ 348 RESTORE_REG(t8, T8, sp) ;\ 349 RESTORE_REG(t9, T9, sp) ;\ 350 RESTORE_REG(s0, S0, sp) ;\ 351 RESTORE_REG(s1, S1, sp) ;\ 352 RESTORE_REG(s2, S2, sp) ;\ 353 RESTORE_REG(s3, S3, sp) ;\ 354 RESTORE_REG(s4, S4, sp) ;\ 355 RESTORE_REG(s5, S5, sp) ;\ 356 RESTORE_REG(s6, S6, sp) ;\ 357 RESTORE_REG(s7, S7, sp) ;\ 358 RESTORE_REG(s8, S8, sp) ;\ 359 RESTORE_REG(gp, GP, sp) ;\ 360 RESTORE_REG(ra, RA, sp) ;\ 361 PTR_ADDU sp, sp, KERN_EXC_FRAME_SIZE;\ 362 mtc0 k0, MIPS_COP_0_STATUS 363 364 365/* 366 * The kernel exception stack contains 18 saved general registers, 367 * the status register and the multiply lo and high registers. 368 * In addition, we set this up for linkage conventions. 369 */ 370#define KERN_REG_SIZE (NUMSAVEREGS * SZREG) 371#define KERN_EXC_FRAME_SIZE (CALLFRAME_SIZ + KERN_REG_SIZE + 16) 372 373NESTED_NOPROFILE(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra) 374 .set noat 375 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE 376 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE) 377/* 378 * Save CPU state, building 'frame'. 379 */ 380 SAVE_CPU 381/* 382 * Call the exception handler. a0 points at the saved frame. 383 */ 384 PTR_LA gp, _C_LABEL(_gp) 385 PTR_LA k0, _C_LABEL(trap) 386 jalr k0 387 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging 388 389 /* 390 * Update interrupt and CPU mask in saved status register 391 * Some of interrupts could be disabled by 392 * intr filters if interrupts are enabled later 393 * in trap handler 394 */ 395 mfc0 a0, MIPS_COP_0_STATUS 396 and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) 397 RESTORE_REG(a1, SR, sp) 398 and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) 399 or a1, a1, a0 400 SAVE_REG(a1, SR, sp) 401 RESTORE_CPU # v0 contains the return address. 402 sync 403 eret 404 .set at 405END(MipsKernGenException) 406 407 408/*---------------------------------------------------------------------------- 409 * 410 * MipsUserGenException -- 411 * 412 * Handle an exception from user mode. 413 * 414 * Results: 415 * None. 416 * 417 * Side effects: 418 * None. 419 * 420 *---------------------------------------------------------------------------- 421 */ 422NESTED_NOPROFILE(MipsUserGenException, CALLFRAME_SIZ, ra) 423 .set noat 424 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 425/* 426 * Save all of the registers except for the kernel temporaries in u.u_pcb. 427 */ 428 GET_CPU_PCPU(k1) 429 PTR_L k1, PC_CURPCB(k1) 430 SAVE_U_PCB_REG(AT, AST, k1) 431 .set at 432 SAVE_U_PCB_REG(v0, V0, k1) 433 SAVE_U_PCB_REG(v1, V1, k1) 434 SAVE_U_PCB_REG(a0, A0, k1) 435 mflo v0 436 SAVE_U_PCB_REG(a1, A1, k1) 437 SAVE_U_PCB_REG(a2, A2, k1) 438 SAVE_U_PCB_REG(a3, A3, k1) 439 SAVE_U_PCB_REG(t0, T0, k1) 440 mfhi v1 441 SAVE_U_PCB_REG(t1, T1, k1) 442 SAVE_U_PCB_REG(t2, T2, k1) 443 SAVE_U_PCB_REG(t3, T3, k1) 444 SAVE_U_PCB_REG(ta0, TA0, k1) 445 mfc0 a0, MIPS_COP_0_STATUS # First arg is the status reg. 446 SAVE_U_PCB_REG(ta1, TA1, k1) 447 SAVE_U_PCB_REG(ta2, TA2, k1) 448 SAVE_U_PCB_REG(ta3, TA3, k1) 449 SAVE_U_PCB_REG(s0, S0, k1) 450 mfc0 a1, MIPS_COP_0_CAUSE # Second arg is the cause reg. 451 SAVE_U_PCB_REG(s1, S1, k1) 452 SAVE_U_PCB_REG(s2, S2, k1) 453 SAVE_U_PCB_REG(s3, S3, k1) 454 SAVE_U_PCB_REG(s4, S4, k1) 455 MFC0 a2, MIPS_COP_0_BAD_VADDR # Third arg is the fault addr 456 SAVE_U_PCB_REG(s5, S5, k1) 457 SAVE_U_PCB_REG(s6, S6, k1) 458 SAVE_U_PCB_REG(s7, S7, k1) 459 SAVE_U_PCB_REG(t8, T8, k1) 460 MFC0 a3, MIPS_COP_0_EXC_PC # Fourth arg is the pc. 461 SAVE_U_PCB_REG(t9, T9, k1) 462 SAVE_U_PCB_REG(gp, GP, k1) 463 SAVE_U_PCB_REG(sp, SP, k1) 464 SAVE_U_PCB_REG(s8, S8, k1) 465 PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP 466 SAVE_U_PCB_REG(ra, RA, k1) 467 SAVE_U_PCB_REG(v0, MULLO, k1) 468 SAVE_U_PCB_REG(v1, MULHI, k1) 469 SAVE_U_PCB_REG(a0, SR, k1) 470 SAVE_U_PCB_REG(a1, CAUSE, k1) 471 SAVE_U_PCB_REG(a2, BADVADDR, k1) 472 SAVE_U_PCB_REG(a3, PC, k1) 473 REG_S a3, CALLFRAME_RA(sp) # for debugging 474 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP 475# Turn off fpu and enter kernel mode 476 and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_KSU_MASK | MIPS_SR_INT_IE) 477#if defined(CPU_CNMIPS) 478 and t0, t0, ~(MIPS_SR_COP_2_BIT) 479 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX) 480#elif defined(CPU_RMI) || defined(CPU_NLM) 481 or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) 482#endif 483 mtc0 t0, MIPS_COP_0_STATUS 484 PTR_ADDU a0, k1, U_PCB_REGS 485 ITLBNOPFIX 486 487/* 488 * Call the exception handler. 489 */ 490 PTR_LA k0, _C_LABEL(trap) 491 jalr k0 492 nop 493 494/* 495 * Restore user registers and return. 496 * First disable interrupts and set exeption level. 497 */ 498 DO_AST 499 500 CLEAR_STATUS 501 502/* 503 * The use of k1 for storing the PCB pointer must be done only 504 * after interrupts are disabled. Otherwise it will get overwritten 505 * by the interrupt code. 506 */ 507 GET_CPU_PCPU(k1) 508 PTR_L k1, PC_CURPCB(k1) 509 510 /* 511 * Update interrupt mask in saved status register 512 * Some of interrupts could be enabled by ithread 513 * scheduled by ast() 514 */ 515 mfc0 a0, MIPS_COP_0_STATUS 516 and a0, a0, MIPS_SR_INT_MASK 517 RESTORE_U_PCB_REG(a1, SR, k1) 518 and a1, a1, ~MIPS_SR_INT_MASK 519 or a1, a1, a0 520 SAVE_U_PCB_REG(a1, SR, k1) 521 522 RESTORE_U_PCB_REG(t0, MULLO, k1) 523 RESTORE_U_PCB_REG(t1, MULHI, k1) 524 mtlo t0 525 mthi t1 526 RESTORE_U_PCB_REG(a0, PC, k1) 527 RESTORE_U_PCB_REG(v0, V0, k1) 528 MTC0 a0, MIPS_COP_0_EXC_PC # set return address 529 RESTORE_U_PCB_REG(v1, V1, k1) 530 RESTORE_U_PCB_REG(a0, A0, k1) 531 RESTORE_U_PCB_REG(a1, A1, k1) 532 RESTORE_U_PCB_REG(a2, A2, k1) 533 RESTORE_U_PCB_REG(a3, A3, k1) 534 RESTORE_U_PCB_REG(t0, T0, k1) 535 RESTORE_U_PCB_REG(t1, T1, k1) 536 RESTORE_U_PCB_REG(t2, T2, k1) 537 RESTORE_U_PCB_REG(t3, T3, k1) 538 RESTORE_U_PCB_REG(ta0, TA0, k1) 539 RESTORE_U_PCB_REG(ta1, TA1, k1) 540 RESTORE_U_PCB_REG(ta2, TA2, k1) 541 RESTORE_U_PCB_REG(ta3, TA3, k1) 542 RESTORE_U_PCB_REG(s0, S0, k1) 543 RESTORE_U_PCB_REG(s1, S1, k1) 544 RESTORE_U_PCB_REG(s2, S2, k1) 545 RESTORE_U_PCB_REG(s3, S3, k1) 546 RESTORE_U_PCB_REG(s4, S4, k1) 547 RESTORE_U_PCB_REG(s5, S5, k1) 548 RESTORE_U_PCB_REG(s6, S6, k1) 549 RESTORE_U_PCB_REG(s7, S7, k1) 550 RESTORE_U_PCB_REG(t8, T8, k1) 551 RESTORE_U_PCB_REG(t9, T9, k1) 552 RESTORE_U_PCB_REG(gp, GP, k1) 553 RESTORE_U_PCB_REG(sp, SP, k1) 554 RESTORE_U_PCB_REG(k0, SR, k1) 555 RESTORE_U_PCB_REG(s8, S8, k1) 556 RESTORE_U_PCB_REG(ra, RA, k1) 557 .set noat 558 RESTORE_U_PCB_REG(AT, AST, k1) 559 560 mtc0 k0, MIPS_COP_0_STATUS # still exception level 561 ITLBNOPFIX 562 sync 563 eret 564 .set at 565END(MipsUserGenException) 566 567 .set push 568 .set noat 569NESTED(mips_wait, CALLFRAME_SIZ, ra) 570 PTR_SUBU sp, sp, CALLFRAME_SIZ 571 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 572 REG_S ra, CALLFRAME_RA(sp) # save RA 573 mfc0 t0, MIPS_COP_0_STATUS 574 xori t1, t0, MIPS_SR_INT_IE 575 mtc0 t1, MIPS_COP_0_STATUS 576 COP0_SYNC 577 jal sched_runnable 578 nop 579 REG_L ra, CALLFRAME_RA(sp) 580 mfc0 t0, MIPS_COP_0_STATUS 581 ori t1, t0, MIPS_SR_INT_IE 582 .align 4 583GLOBAL(MipsWaitStart) # this is 16 byte aligned 584 mtc0 t1, MIPS_COP_0_STATUS 585 bnez v0, MipsWaitEnd 586 nop 587#if defined(CPU_XBURST) && defined(SMP) 588 nop 589#else 590 wait 591#endif 592GLOBAL(MipsWaitEnd) # MipsWaitStart + 16 593 jr ra 594 PTR_ADDU sp, sp, CALLFRAME_SIZ 595END(mips_wait) 596 .set pop 597 598/*---------------------------------------------------------------------------- 599 * 600 * MipsKernIntr -- 601 * 602 * Handle an interrupt from kernel mode. 603 * Interrupts use the standard kernel stack. 604 * switch_exit sets up a kernel stack after exit so interrupts won't fail. 605 * 606 * Results: 607 * None. 608 * 609 * Side effects: 610 * None. 611 * 612 *---------------------------------------------------------------------------- 613 */ 614 615NESTED_NOPROFILE(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra) 616 .set noat 617 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE 618 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE) 619 620/* 621 * Check for getting interrupts just before wait 622 */ 623 MFC0 k0, MIPS_COP_0_EXC_PC 624 ori k0, 0xf 625 xori k0, 0xf # 16 byte align 626 PTR_LA k1, MipsWaitStart 627 bne k0, k1, 1f 628 nop 629 PTR_ADDU k1, 16 # skip over wait 630 MTC0 k1, MIPS_COP_0_EXC_PC 6311: 632/* 633 * Save CPU state, building 'frame'. 634 */ 635 SAVE_CPU 636/* 637 * Call the interrupt handler. a0 points at the saved frame. 638 */ 639 PTR_LA gp, _C_LABEL(_gp) 640#ifdef INTRNG 641 PTR_LA k0, _C_LABEL(intr_irq_handler) 642#else 643 PTR_LA k0, _C_LABEL(cpu_intr) 644#endif 645 jalr k0 646 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging 647 648 /* 649 * Update interrupt and CPU mask in saved status register 650 * Some of interrupts could be disabled by 651 * intr filters if interrupts are enabled later 652 * in trap handler 653 */ 654 mfc0 a0, MIPS_COP_0_STATUS 655 and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) 656 RESTORE_REG(a1, SR, sp) 657 and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) 658 or a1, a1, a0 659 SAVE_REG(a1, SR, sp) 660 REG_L v0, CALLFRAME_RA + KERN_REG_SIZE(sp) 661 RESTORE_CPU # v0 contains the return address. 662 sync 663 eret 664 .set at 665END(MipsKernIntr) 666 667/*---------------------------------------------------------------------------- 668 * 669 * MipsUserIntr -- 670 * 671 * Handle an interrupt from user mode. 672 * Note: we save minimal state in the u.u_pcb struct and use the standard 673 * kernel stack since there has to be a u page if we came from user mode. 674 * If there is a pending software interrupt, then save the remaining state 675 * and call softintr(). This is all because if we call switch() inside 676 * interrupt(), not all the user registers have been saved in u.u_pcb. 677 * 678 * Results: 679 * None. 680 * 681 * Side effects: 682 * None. 683 * 684 *---------------------------------------------------------------------------- 685 */ 686NESTED_NOPROFILE(MipsUserIntr, CALLFRAME_SIZ, ra) 687 .set noat 688 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 689/* 690 * Save the relevant user registers into the u.u_pcb struct. 691 * We don't need to save s0 - s8 because the compiler does it for us. 692 */ 693 GET_CPU_PCPU(k1) 694 PTR_L k1, PC_CURPCB(k1) 695 SAVE_U_PCB_REG(AT, AST, k1) 696 .set at 697 SAVE_U_PCB_REG(v0, V0, k1) 698 SAVE_U_PCB_REG(v1, V1, k1) 699 SAVE_U_PCB_REG(a0, A0, k1) 700 SAVE_U_PCB_REG(a1, A1, k1) 701 SAVE_U_PCB_REG(a2, A2, k1) 702 SAVE_U_PCB_REG(a3, A3, k1) 703 SAVE_U_PCB_REG(t0, T0, k1) 704 SAVE_U_PCB_REG(t1, T1, k1) 705 SAVE_U_PCB_REG(t2, T2, k1) 706 SAVE_U_PCB_REG(t3, T3, k1) 707 SAVE_U_PCB_REG(ta0, TA0, k1) 708 SAVE_U_PCB_REG(ta1, TA1, k1) 709 SAVE_U_PCB_REG(ta2, TA2, k1) 710 SAVE_U_PCB_REG(ta3, TA3, k1) 711 SAVE_U_PCB_REG(t8, T8, k1) 712 SAVE_U_PCB_REG(t9, T9, k1) 713 SAVE_U_PCB_REG(gp, GP, k1) 714 SAVE_U_PCB_REG(sp, SP, k1) 715 SAVE_U_PCB_REG(ra, RA, k1) 716/* 717 * save remaining user state in u.u_pcb. 718 */ 719 SAVE_U_PCB_REG(s0, S0, k1) 720 SAVE_U_PCB_REG(s1, S1, k1) 721 SAVE_U_PCB_REG(s2, S2, k1) 722 SAVE_U_PCB_REG(s3, S3, k1) 723 SAVE_U_PCB_REG(s4, S4, k1) 724 SAVE_U_PCB_REG(s5, S5, k1) 725 SAVE_U_PCB_REG(s6, S6, k1) 726 SAVE_U_PCB_REG(s7, S7, k1) 727 SAVE_U_PCB_REG(s8, S8, k1) 728 729 mflo v0 # get lo/hi late to avoid stall 730 mfhi v1 731 mfc0 a0, MIPS_COP_0_STATUS 732 mfc0 a1, MIPS_COP_0_CAUSE 733 MFC0 a3, MIPS_COP_0_EXC_PC 734 SAVE_U_PCB_REG(v0, MULLO, k1) 735 SAVE_U_PCB_REG(v1, MULHI, k1) 736 SAVE_U_PCB_REG(a0, SR, k1) 737 SAVE_U_PCB_REG(a1, CAUSE, k1) 738 SAVE_U_PCB_REG(a3, PC, k1) # PC in a3, note used later! 739 PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP 740 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP 741 742# Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level. 743 and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS_SR_KSU_MASK) 744#ifdef CPU_CNMIPS 745 and t0, t0, ~(MIPS_SR_COP_2_BIT) 746 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX) 747#elif defined(CPU_RMI) || defined(CPU_NLM) 748 or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) 749#endif 750 mtc0 t0, MIPS_COP_0_STATUS 751 ITLBNOPFIX 752 PTR_ADDU a0, k1, U_PCB_REGS 753/* 754 * Call the interrupt handler. 755 */ 756#ifdef INTRNG 757 PTR_LA k0, _C_LABEL(intr_irq_handler) 758#else 759 PTR_LA k0, _C_LABEL(cpu_intr) 760#endif 761 jalr k0 762 REG_S a3, CALLFRAME_RA(sp) # for debugging 763 764/* 765 * Enable interrupts before doing ast(). 766 * 767 * On SMP kernels the AST processing might trigger IPI to other processors. 768 * If that processor is also doing AST processing with interrupts disabled 769 * then we may deadlock. 770 */ 771 mfc0 a0, MIPS_COP_0_STATUS 772 or a0, a0, MIPS_SR_INT_IE 773 mtc0 a0, MIPS_COP_0_STATUS 774 ITLBNOPFIX 775 776/* 777 * DO_AST enabled interrupts 778 */ 779 DO_AST 780 781/* 782 * Restore user registers and return. 783 */ 784 CLEAR_STATUS 785 786 GET_CPU_PCPU(k1) 787 PTR_L k1, PC_CURPCB(k1) 788 789 /* 790 * Update interrupt mask in saved status register 791 * Some of interrupts could be disabled by 792 * intr filters 793 */ 794 mfc0 a0, MIPS_COP_0_STATUS 795 and a0, a0, MIPS_SR_INT_MASK 796 RESTORE_U_PCB_REG(a1, SR, k1) 797 and a1, a1, ~MIPS_SR_INT_MASK 798 or a1, a1, a0 799 SAVE_U_PCB_REG(a1, SR, k1) 800 801 RESTORE_U_PCB_REG(s0, S0, k1) 802 RESTORE_U_PCB_REG(s1, S1, k1) 803 RESTORE_U_PCB_REG(s2, S2, k1) 804 RESTORE_U_PCB_REG(s3, S3, k1) 805 RESTORE_U_PCB_REG(s4, S4, k1) 806 RESTORE_U_PCB_REG(s5, S5, k1) 807 RESTORE_U_PCB_REG(s6, S6, k1) 808 RESTORE_U_PCB_REG(s7, S7, k1) 809 RESTORE_U_PCB_REG(s8, S8, k1) 810 RESTORE_U_PCB_REG(t0, MULLO, k1) 811 RESTORE_U_PCB_REG(t1, MULHI, k1) 812 RESTORE_U_PCB_REG(t2, PC, k1) 813 mtlo t0 814 mthi t1 815 MTC0 t2, MIPS_COP_0_EXC_PC # set return address 816 RESTORE_U_PCB_REG(v0, V0, k1) 817 RESTORE_U_PCB_REG(v1, V1, k1) 818 RESTORE_U_PCB_REG(a0, A0, k1) 819 RESTORE_U_PCB_REG(a1, A1, k1) 820 RESTORE_U_PCB_REG(a2, A2, k1) 821 RESTORE_U_PCB_REG(a3, A3, k1) 822 RESTORE_U_PCB_REG(t0, T0, k1) 823 RESTORE_U_PCB_REG(t1, T1, k1) 824 RESTORE_U_PCB_REG(t2, T2, k1) 825 RESTORE_U_PCB_REG(t3, T3, k1) 826 RESTORE_U_PCB_REG(ta0, TA0, k1) 827 RESTORE_U_PCB_REG(ta1, TA1, k1) 828 RESTORE_U_PCB_REG(ta2, TA2, k1) 829 RESTORE_U_PCB_REG(ta3, TA3, k1) 830 RESTORE_U_PCB_REG(t8, T8, k1) 831 RESTORE_U_PCB_REG(t9, T9, k1) 832 RESTORE_U_PCB_REG(gp, GP, k1) 833 RESTORE_U_PCB_REG(k0, SR, k1) 834 RESTORE_U_PCB_REG(sp, SP, k1) 835 RESTORE_U_PCB_REG(ra, RA, k1) 836 .set noat 837 RESTORE_U_PCB_REG(AT, AST, k1) 838 839 mtc0 k0, MIPS_COP_0_STATUS # SR with EXL set. 840 ITLBNOPFIX 841 sync 842 eret 843 .set at 844END(MipsUserIntr) 845 846LEAF_NOPROFILE(MipsTLBInvalidException) 847 .set push 848 .set noat 849 .set noreorder 850 851 MFC0 k0, MIPS_COP_0_BAD_VADDR 852 PTR_LI k1, VM_MAXUSER_ADDRESS 853 sltu k1, k0, k1 854 bnez k1, 1f 855 nop 856 857 /* Kernel address. */ 858 lui k1, %hi(kernel_segmap) # k1=hi of segbase 859 b 2f 860 PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base 861 8621: /* User address. */ 863 GET_CPU_PCPU(k1) 864 PTR_L k1, PC_SEGBASE(k1) 865 8662: /* Validate page directory pointer. */ 867 beqz k1, 3f 868 nop 869 870 PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost) 871 beq k1, zero, MipsKernGenException # ==0 -- no seg tab 872 andi k0, k0, PDEPTRMASK #06: k0=seg offset 873 PTR_ADDU k1, k0, k1 # k1=seg entry address 874 PTR_L k1, 0(k1) # k1=seg entry 875 876 /* Validate page table pointer. */ 877 beqz k1, 3f 878 nop 879 880#ifdef __mips_n64 881 MFC0 k0, MIPS_COP_0_BAD_VADDR 882 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=pde offset (almost) 883 beq k1, zero, MipsKernGenException # ==0 -- no pde tab 884 andi k0, k0, PDEPTRMASK # k0=pde offset 885 PTR_ADDU k1, k0, k1 # k1=pde entry address 886 PTR_L k1, 0(k1) # k1=pde entry 887 888 /* Validate pde table pointer. */ 889 beqz k1, 3f 890 nop 891#endif 892 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) 893 PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN 894 andi k0, k0, PTEMASK # k0=page tab offset 895 PTR_ADDU k1, k1, k0 # k1=pte address 896 PTE_L k0, 0(k1) # k0=this PTE 897 898 /* Validate page table entry. */ 899 andi k0, PTE_V 900 beqz k0, 3f 901 nop 902 903 /* Check whether this is an even or odd entry. */ 904 andi k0, k1, PTESIZE 905 bnez k0, odd_page 906 nop 907 908 PTE_L k0, 0(k1) 909 PTE_L k1, PTESIZE(k1) 910 CLEAR_PTE_SWBITS(k0) 911 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 912 COP0_SYNC 913 CLEAR_PTE_SWBITS(k1) 914 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 915 COP0_SYNC 916 917 b tlb_insert_entry 918 nop 919 920odd_page: 921 PTE_L k0, -PTESIZE(k1) 922 PTE_L k1, 0(k1) 923 CLEAR_PTE_SWBITS(k0) 924 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 925 COP0_SYNC 926 CLEAR_PTE_SWBITS(k1) 927 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 928 COP0_SYNC 929 930tlb_insert_entry: 931 tlbp 932 HAZARD_DELAY 933 mfc0 k0, MIPS_COP_0_TLB_INDEX 934 bltz k0, tlb_insert_random 935 nop 936 tlbwi 937 eret 938 ssnop 939 940tlb_insert_random: 941 tlbwr 942 eret 943 ssnop 944 9453: 946 /* 947 * Branch to the comprehensive exception processing. 948 */ 949 mfc0 k1, MIPS_COP_0_STATUS 950 andi k1, k1, MIPS_SR_KSU_USER 951 bnez k1, _C_LABEL(MipsUserGenException) 952 nop 953 954 /* 955 * Check for kernel stack overflow. 956 */ 957 GET_CPU_PCPU(k1) 958 PTR_L k0, PC_CURTHREAD(k1) 959 PTR_L k0, TD_KSTACK(k0) 960 sltu k0, k0, sp 961 bnez k0, _C_LABEL(MipsKernGenException) 962 nop 963 964 /* 965 * Kernel stack overflow. 966 * 967 * Move to a valid stack before we call panic. We use the boot stack 968 * for this purpose. 969 */ 970 GET_CPU_PCPU(k1) 971 lw k1, PC_CPUID(k1) 972 sll k1, k1, PAGE_SHIFT + 1 973 974 PTR_LA k0, _C_LABEL(pcpu_space) 975 PTR_ADDU k0, PAGE_SIZE * 2 976 PTR_ADDU k0, k0, k1 977 978 /* 979 * Stash the original value of 'sp' so we can update trapframe later. 980 * We assume that SAVE_CPU does not trash 'k1'. 981 */ 982 move k1, sp 983 984 move sp, k0 985 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE 986 987 move k0, ra 988 move ra, zero 989 REG_S ra, CALLFRAME_RA(sp) /* stop the ddb backtrace right here */ 990 REG_S zero, CALLFRAME_SP(sp) 991 move ra, k0 992 993 SAVE_CPU 994 995 /* 996 * Now restore the value of 'sp' at the time of the tlb exception in 997 * the trapframe. 998 */ 999 SAVE_REG(k1, SP, sp) 1000 1001 /* 1002 * Squelch any more overflow checks by setting the stack base to 0. 1003 */ 1004 GET_CPU_PCPU(k1) 1005 PTR_L k0, PC_CURTHREAD(k1) 1006 PTR_S zero, TD_KSTACK(k0) 1007 1008 move a1, a0 1009 PANIC("kernel stack overflow - trapframe at %p") 1010 1011 /* 1012 * This nop is necessary so that the 'ra' remains within the bounds 1013 * of this handler. Otherwise the ddb backtrace code will think that 1014 * the panic() was called from MipsTLBMissException. 1015 */ 1016 .globl MipsKStackOverflow 1017MipsKStackOverflow: 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 .set push 1100 .set hardfloat 1101 PTR_SUBU sp, sp, CALLFRAME_SIZ 1102 mfc0 t0, MIPS_COP_0_STATUS 1103 HAZARD_DELAY 1104 REG_S ra, CALLFRAME_RA(sp) 1105 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 1106 1107#if defined(__mips_n32) || defined(__mips_n64) 1108 or t1, t0, MIPS_SR_COP_1_BIT | MIPS_SR_FR 1109#else 1110 or t1, t0, MIPS_SR_COP_1_BIT 1111#endif 1112 mtc0 t1, MIPS_COP_0_STATUS 1113 HAZARD_DELAY 1114 ITLBNOPFIX 1115 cfc1 t1, MIPS_FPU_CSR # stall til FP done 1116 cfc1 t1, MIPS_FPU_CSR # now get status 1117 nop 1118 sll t2, t1, (31 - 17) # unimplemented operation? 1119 bgez t2, 3f # no, normal trap 1120 nop 1121/* 1122 * We got an unimplemented operation trap so 1123 * fetch the instruction, compute the next PC and emulate the instruction. 1124 */ 1125 bgez a1, 1f # Check the branch delay bit. 1126 nop 1127/* 1128 * The instruction is in the branch delay slot so the branch will have to 1129 * be emulated to get the resulting PC. 1130 */ 1131 PTR_S a2, CALLFRAME_SIZ + 8(sp) 1132 GET_CPU_PCPU(a0) 1133#mips64 unsafe? 1134 PTR_L a0, PC_CURPCB(a0) 1135 PTR_ADDU a0, a0, U_PCB_REGS # first arg is ptr to CPU registers 1136 move a1, a2 # second arg is instruction PC 1137 move a2, t1 # third arg is floating point CSR 1138 PTR_LA t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch 1139 jalr t3 # compute PC after branch 1140 move a3, zero # fourth arg is FALSE 1141/* 1142 * Now load the floating-point instruction in the branch delay slot 1143 * to be emulated. 1144 */ 1145 PTR_L a2, CALLFRAME_SIZ + 8(sp) # restore EXC pc 1146 b 2f 1147 lw a0, 4(a2) # a0 = coproc instruction 1148/* 1149 * This is not in the branch delay slot so calculate the resulting 1150 * PC (epc + 4) into v0 and continue to MipsEmulateFP(). 1151 */ 11521: 1153 lw a0, 0(a2) # a0 = coproc instruction 1154#xxx mips64 unsafe? 1155 PTR_ADDU v0, a2, 4 # v0 = next pc 11562: 1157 GET_CPU_PCPU(t2) 1158 PTR_L t2, PC_CURPCB(t2) 1159 SAVE_U_PCB_REG(v0, PC, t2) # save new pc 1160/* 1161 * Check to see if the instruction to be emulated is a floating-point 1162 * instruction. 1163 */ 1164 srl a3, a0, MIPS_OPCODE_SHIFT 1165 beq a3, MIPS_OPCODE_C1, 4f # this should never fail 1166 nop 1167/* 1168 * Send a floating point exception signal to the current process. 1169 */ 11703: 1171 GET_CPU_PCPU(a0) 1172 PTR_L a0, PC_CURTHREAD(a0) # get current thread 1173 cfc1 a2, MIPS_FPU_CSR # code = FP execptions 1174 ctc1 zero, MIPS_FPU_CSR # Clear exceptions 1175 PTR_LA t3, _C_LABEL(trapsignal) 1176 jalr t3 1177 li a1, SIGFPE 1178 b FPReturn 1179 nop 1180 1181/* 1182 * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate. 1183 */ 11844: 1185 PTR_LA t3, _C_LABEL(MipsEmulateFP) 1186 jalr t3 1187 nop 1188 1189/* 1190 * Turn off the floating point coprocessor and return. 1191 */ 1192FPReturn: 1193 mfc0 t0, MIPS_COP_0_STATUS 1194 PTR_L ra, CALLFRAME_RA(sp) 1195 and t0, t0, ~MIPS_SR_COP_1_BIT 1196 mtc0 t0, MIPS_COP_0_STATUS 1197 ITLBNOPFIX 1198 j ra 1199 PTR_ADDU sp, sp, CALLFRAME_SIZ 1200 .set pop 1201END(MipsFPTrap) 1202 1203/* 1204 * Vector to real handler in KSEG1. 1205 */ 1206 .text 1207VECTOR(MipsCache, unknown) 1208 PTR_LA k0, _C_LABEL(MipsCacheException) 1209 li k1, MIPS_KSEG0_PHYS_MASK 1210 and k0, k1 1211 PTR_LI k1, MIPS_KSEG1_START 1212 or k0, k1 1213 j k0 1214 nop 1215VECTOR_END(MipsCache) 1216 1217 .set at 1218 1219 1220/* 1221 * Panic on cache errors. A lot more could be done to recover 1222 * from some types of errors but it is tricky. 1223 */ 1224NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra) 1225 .set noat 1226 .mask 0x80000000, -4 1227 PTR_LA k0, _C_LABEL(panic) # return to panic 1228 PTR_LA a0, 9f # panicstr 1229 MFC0 a1, MIPS_COP_0_ERROR_PC 1230 mfc0 a2, MIPS_COP_0_CACHE_ERR # 3rd arg cache error 1231 1232 MTC0 k0, MIPS_COP_0_ERROR_PC # set return address 1233 1234 mfc0 k0, MIPS_COP_0_STATUS # restore status 1235 li k1, MIPS_SR_DIAG_PE # ignore further errors 1236 or k0, k1 1237 mtc0 k0, MIPS_COP_0_STATUS # restore status 1238 COP0_SYNC 1239 1240 eret 1241 1242 MSG("cache error @ EPC 0x%x CachErr 0x%x"); 1243 .set at 1244END(MipsCacheException) 1245