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#include "opt_kdtrace.h" 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 65#include "assym.s" 66 67 .set noreorder # Noreorder is default style! 68 69#ifdef KDTRACE_HOOKS 70 .data 71 .globl dtrace_invop_jump_addr 72 .align 4 73 .type dtrace_invop_jump_addr, @object 74 .size dtrace_invop_jump_addr, 8 75dtrace_invop_jump_addr: 76 .word 0 77 .word 0 78 .globl dtrace_invop_calltrap_addr 79 .align 4 80 .type dtrace_invop_calltrap_addr, @object 81 .size dtrace_invop_calltrap_addr, 8 82dtrace_invop_calltrap_addr: 83 .word 0 84 .word 0 85 86 .text 87#endif 88 89/* 90 * Reasonable limit 91 */ 92#define INTRCNT_COUNT 256 93 94 95/* 96 *---------------------------------------------------------------------------- 97 * 98 * MipsTLBMiss -- 99 * 100 * Vector code for the TLB-miss exception vector 0x80000000. 101 * 102 * This code is copied to the TLB exception vector address to 103 * which the CPU jumps in response to an exception or a TLB miss. 104 * NOTE: This code must be position independent!!! 105 * 106 * 107 */ 108VECTOR(MipsTLBMiss, unknown) 109 .set push 110 .set noat 111 j MipsDoTLBMiss 112 MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address 113 .set pop 114VECTOR_END(MipsTLBMiss) 115 116/* 117 *---------------------------------------------------------------------------- 118 * 119 * MipsDoTLBMiss -- 120 * 121 * This is the real TLB Miss Handler code. 122 * 'segbase' points to the base of the segment table for user processes. 123 * 124 * Don't check for invalid pte's here. We load them as well and 125 * let the processor trap to load the correct value after service. 126 *---------------------------------------------------------------------------- 127 */ 128 .set push 129 .set noat 130MipsDoTLBMiss: 131 bltz k0, 1f #02: k0<0 -> 1f (kernel fault) 132 PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost) 133 134 GET_CPU_PCPU(k1) 135 PTR_L k1, PC_SEGBASE(k1) 136 beqz k1, 2f #05: make sure segbase is not null 137 andi k0, k0, PDEPTRMASK #06: k0=seg offset 138 PTR_ADDU k1, k0, k1 #07: k1=seg entry address 139 140 PTR_L k1, 0(k1) #08: k1=seg entry 141 MFC0 k0, MIPS_COP_0_BAD_VADDR #09: k0=bad address (again) 142 beq k1, zero, 2f #0a: ==0 -- no page table 143#ifdef __mips_n64 144 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN 145 andi k0, k0, PDEPTRMASK # k0=pde offset 146 PTR_ADDU k1, k0, k1 # k1=pde entry address 147 PTR_L k1, 0(k1) # k1=pde entry 148 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) 149 beq k1, zero, 2f # ==0 -- no page table 150#endif 151 PTR_SRL k0, PAGE_SHIFT - PTESHIFT #0b: k0=VPN (aka va>>10) 152 andi k0, k0, PTE2MASK #0c: k0=page tab offset 153 PTR_ADDU k1, k1, k0 #0d: k1=pte address 154 PTE_L k0, 0(k1) #0e: k0=lo0 pte 155 PTE_L k1, PTESIZE(k1) #0f: k1=lo0 pte 156 CLEAR_PTE_SWBITS(k0) 157 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded 158 COP0_SYNC 159 CLEAR_PTE_SWBITS(k1) 160 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded 161 COP0_SYNC 162 tlbwr #1a: write to tlb 163 HAZARD_DELAY 164 eret #1f: retUrn from exception 1651: j MipsTLBMissException #20: kernel exception 166 nop #21: branch delay slot 1672: j SlowFault #22: no page table present 168 nop #23: branch delay slot 169 .set pop 170 171/* 172 * This code is copied to the general exception vector address to 173 * handle all execptions except RESET and TLBMiss. 174 * NOTE: This code must be position independent!!! 175 */ 176VECTOR(MipsException, unknown) 177/* 178 * Find out what mode we came from and jump to the proper handler. 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 379NNON_LEAF(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#define SAVE_U_PCB_REG(reg, offs, base) \ 415 REG_S reg, U_PCB_REGS + (SZREG * offs) (base) 416 417#define RESTORE_U_PCB_REG(reg, offs, base) \ 418 REG_L reg, U_PCB_REGS + (SZREG * offs) (base) 419 420/*---------------------------------------------------------------------------- 421 * 422 * MipsUserGenException -- 423 * 424 * Handle an exception from user mode. 425 * 426 * Results: 427 * None. 428 * 429 * Side effects: 430 * None. 431 * 432 *---------------------------------------------------------------------------- 433 */ 434NNON_LEAF(MipsUserGenException, CALLFRAME_SIZ, ra) 435 .set noat 436 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 437/* 438 * Save all of the registers except for the kernel temporaries in u.u_pcb. 439 */ 440 GET_CPU_PCPU(k1) 441 PTR_L k1, PC_CURPCB(k1) 442 SAVE_U_PCB_REG(AT, AST, k1) 443 .set at 444 SAVE_U_PCB_REG(v0, V0, k1) 445 SAVE_U_PCB_REG(v1, V1, k1) 446 SAVE_U_PCB_REG(a0, A0, k1) 447 mflo v0 448 SAVE_U_PCB_REG(a1, A1, k1) 449 SAVE_U_PCB_REG(a2, A2, k1) 450 SAVE_U_PCB_REG(a3, A3, k1) 451 SAVE_U_PCB_REG(t0, T0, k1) 452 mfhi v1 453 SAVE_U_PCB_REG(t1, T1, k1) 454 SAVE_U_PCB_REG(t2, T2, k1) 455 SAVE_U_PCB_REG(t3, T3, k1) 456 SAVE_U_PCB_REG(ta0, TA0, k1) 457 mfc0 a0, MIPS_COP_0_STATUS # First arg is the status reg. 458 SAVE_U_PCB_REG(ta1, TA1, k1) 459 SAVE_U_PCB_REG(ta2, TA2, k1) 460 SAVE_U_PCB_REG(ta3, TA3, k1) 461 SAVE_U_PCB_REG(s0, S0, k1) 462 mfc0 a1, MIPS_COP_0_CAUSE # Second arg is the cause reg. 463 SAVE_U_PCB_REG(s1, S1, k1) 464 SAVE_U_PCB_REG(s2, S2, k1) 465 SAVE_U_PCB_REG(s3, S3, k1) 466 SAVE_U_PCB_REG(s4, S4, k1) 467 MFC0 a2, MIPS_COP_0_BAD_VADDR # Third arg is the fault addr 468 SAVE_U_PCB_REG(s5, S5, k1) 469 SAVE_U_PCB_REG(s6, S6, k1) 470 SAVE_U_PCB_REG(s7, S7, k1) 471 SAVE_U_PCB_REG(t8, T8, k1) 472 MFC0 a3, MIPS_COP_0_EXC_PC # Fourth arg is the pc. 473 SAVE_U_PCB_REG(t9, T9, k1) 474 SAVE_U_PCB_REG(gp, GP, k1) 475 SAVE_U_PCB_REG(sp, SP, k1) 476 SAVE_U_PCB_REG(s8, S8, k1) 477 PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP 478 SAVE_U_PCB_REG(ra, RA, k1) 479 SAVE_U_PCB_REG(v0, MULLO, k1) 480 SAVE_U_PCB_REG(v1, MULHI, k1) 481 SAVE_U_PCB_REG(a0, SR, k1) 482 SAVE_U_PCB_REG(a1, CAUSE, k1) 483 SAVE_U_PCB_REG(a2, BADVADDR, k1) 484 SAVE_U_PCB_REG(a3, PC, k1) 485 REG_S a3, CALLFRAME_RA(sp) # for debugging 486 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP 487# Turn off fpu and enter kernel mode 488 and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_KSU_MASK | MIPS_SR_INT_IE) 489#if defined(CPU_CNMIPS) 490 and t0, t0, ~(MIPS_SR_COP_2_BIT) 491 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX) 492#elif defined(CPU_RMI) || defined(CPU_NLM) 493 or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) 494#endif 495 mtc0 t0, MIPS_COP_0_STATUS 496 PTR_ADDU a0, k1, U_PCB_REGS 497 ITLBNOPFIX 498 499/* 500 * Call the exception handler. 501 */ 502 PTR_LA k0, _C_LABEL(trap) 503 jalr k0 504 nop 505 506/* 507 * Restore user registers and return. 508 * First disable interrupts and set exeption level. 509 */ 510 DO_AST 511 512 CLEAR_STATUS 513 514/* 515 * The use of k1 for storing the PCB pointer must be done only 516 * after interrupts are disabled. Otherwise it will get overwritten 517 * by the interrupt code. 518 */ 519 GET_CPU_PCPU(k1) 520 PTR_L k1, PC_CURPCB(k1) 521 522 /* 523 * Update interrupt mask in saved status register 524 * Some of interrupts could be enabled by ithread 525 * scheduled by ast() 526 */ 527 mfc0 a0, MIPS_COP_0_STATUS 528 and a0, a0, MIPS_SR_INT_MASK 529 RESTORE_U_PCB_REG(a1, SR, k1) 530 and a1, a1, ~MIPS_SR_INT_MASK 531 or a1, a1, a0 532 SAVE_U_PCB_REG(a1, SR, k1) 533 534 RESTORE_U_PCB_REG(t0, MULLO, k1) 535 RESTORE_U_PCB_REG(t1, MULHI, k1) 536 mtlo t0 537 mthi t1 538 RESTORE_U_PCB_REG(a0, PC, k1) 539 RESTORE_U_PCB_REG(v0, V0, k1) 540 MTC0 a0, MIPS_COP_0_EXC_PC # set return address 541 RESTORE_U_PCB_REG(v1, V1, k1) 542 RESTORE_U_PCB_REG(a0, A0, k1) 543 RESTORE_U_PCB_REG(a1, A1, k1) 544 RESTORE_U_PCB_REG(a2, A2, k1) 545 RESTORE_U_PCB_REG(a3, A3, k1) 546 RESTORE_U_PCB_REG(t0, T0, k1) 547 RESTORE_U_PCB_REG(t1, T1, k1) 548 RESTORE_U_PCB_REG(t2, T2, k1) 549 RESTORE_U_PCB_REG(t3, T3, k1) 550 RESTORE_U_PCB_REG(ta0, TA0, k1) 551 RESTORE_U_PCB_REG(ta1, TA1, k1) 552 RESTORE_U_PCB_REG(ta2, TA2, k1) 553 RESTORE_U_PCB_REG(ta3, TA3, k1) 554 RESTORE_U_PCB_REG(s0, S0, k1) 555 RESTORE_U_PCB_REG(s1, S1, k1) 556 RESTORE_U_PCB_REG(s2, S2, k1) 557 RESTORE_U_PCB_REG(s3, S3, k1) 558 RESTORE_U_PCB_REG(s4, S4, k1) 559 RESTORE_U_PCB_REG(s5, S5, k1) 560 RESTORE_U_PCB_REG(s6, S6, k1) 561 RESTORE_U_PCB_REG(s7, S7, k1) 562 RESTORE_U_PCB_REG(t8, T8, k1) 563 RESTORE_U_PCB_REG(t9, T9, k1) 564 RESTORE_U_PCB_REG(gp, GP, k1) 565 RESTORE_U_PCB_REG(sp, SP, k1) 566 RESTORE_U_PCB_REG(k0, SR, k1) 567 RESTORE_U_PCB_REG(s8, S8, k1) 568 RESTORE_U_PCB_REG(ra, RA, k1) 569 .set noat 570 RESTORE_U_PCB_REG(AT, AST, k1) 571 572 mtc0 k0, MIPS_COP_0_STATUS # still exception level 573 ITLBNOPFIX 574 sync 575 eret 576 .set at 577END(MipsUserGenException) 578 579 .set push 580 .set noat 581NON_LEAF(mips_wait, CALLFRAME_SIZ, ra) 582 PTR_SUBU sp, sp, CALLFRAME_SIZ 583 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 584 REG_S ra, CALLFRAME_RA(sp) # save RA 585 mfc0 t0, MIPS_COP_0_STATUS 586 xori t1, t0, MIPS_SR_INT_IE 587 mtc0 t1, MIPS_COP_0_STATUS 588 COP0_SYNC 589 jal sched_runnable 590 nop 591 REG_L ra, CALLFRAME_RA(sp) 592 mfc0 t0, MIPS_COP_0_STATUS 593 ori t1, t0, MIPS_SR_INT_IE 594 .align 4 595GLOBAL(MipsWaitStart) # this is 16 byte aligned 596 mtc0 t1, MIPS_COP_0_STATUS 597 bnez v0, MipsWaitEnd 598 nop 599 wait 600GLOBAL(MipsWaitEnd) # MipsWaitStart + 16 601 jr ra 602 PTR_ADDU sp, sp, CALLFRAME_SIZ 603END(mips_wait) 604 .set pop 605 606/*---------------------------------------------------------------------------- 607 * 608 * MipsKernIntr -- 609 * 610 * Handle an interrupt from kernel mode. 611 * Interrupts use the standard kernel stack. 612 * switch_exit sets up a kernel stack after exit so interrupts won't fail. 613 * 614 * Results: 615 * None. 616 * 617 * Side effects: 618 * None. 619 * 620 *---------------------------------------------------------------------------- 621 */ 622 623NNON_LEAF(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra) 624 .set noat 625 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE 626 .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE) 627 628/* 629 * Check for getting interrupts just before wait 630 */ 631 MFC0 k0, MIPS_COP_0_EXC_PC 632 ori k0, 0xf 633 xori k0, 0xf # 16 byte align 634 PTR_LA k1, MipsWaitStart 635 bne k0, k1, 1f 636 nop 637 PTR_ADDU k1, 16 # skip over wait 638 MTC0 k1, MIPS_COP_0_EXC_PC 6391: 640/* 641 * Save CPU state, building 'frame'. 642 */ 643 SAVE_CPU 644/* 645 * Call the interrupt handler. a0 points at the saved frame. 646 */ 647 PTR_LA gp, _C_LABEL(_gp) 648 PTR_LA k0, _C_LABEL(cpu_intr) 649 jalr k0 650 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging 651 652 /* 653 * Update interrupt and CPU mask in saved status register 654 * Some of interrupts could be disabled by 655 * intr filters if interrupts are enabled later 656 * in trap handler 657 */ 658 mfc0 a0, MIPS_COP_0_STATUS 659 and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) 660 RESTORE_REG(a1, SR, sp) 661 and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) 662 or a1, a1, a0 663 SAVE_REG(a1, SR, sp) 664 REG_L v0, CALLFRAME_RA + KERN_REG_SIZE(sp) 665 RESTORE_CPU # v0 contains the return address. 666 sync 667 eret 668 .set at 669END(MipsKernIntr) 670 671/*---------------------------------------------------------------------------- 672 * 673 * MipsUserIntr -- 674 * 675 * Handle an interrupt from user mode. 676 * Note: we save minimal state in the u.u_pcb struct and use the standard 677 * kernel stack since there has to be a u page if we came from user mode. 678 * If there is a pending software interrupt, then save the remaining state 679 * and call softintr(). This is all because if we call switch() inside 680 * interrupt(), not all the user registers have been saved in u.u_pcb. 681 * 682 * Results: 683 * None. 684 * 685 * Side effects: 686 * None. 687 * 688 *---------------------------------------------------------------------------- 689 */ 690NNON_LEAF(MipsUserIntr, CALLFRAME_SIZ, ra) 691 .set noat 692 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 693/* 694 * Save the relevant user registers into the u.u_pcb struct. 695 * We don't need to save s0 - s8 because the compiler does it for us. 696 */ 697 GET_CPU_PCPU(k1) 698 PTR_L k1, PC_CURPCB(k1) 699 SAVE_U_PCB_REG(AT, AST, k1) 700 .set at 701 SAVE_U_PCB_REG(v0, V0, k1) 702 SAVE_U_PCB_REG(v1, V1, k1) 703 SAVE_U_PCB_REG(a0, A0, k1) 704 SAVE_U_PCB_REG(a1, A1, k1) 705 SAVE_U_PCB_REG(a2, A2, k1) 706 SAVE_U_PCB_REG(a3, A3, k1) 707 SAVE_U_PCB_REG(t0, T0, k1) 708 SAVE_U_PCB_REG(t1, T1, k1) 709 SAVE_U_PCB_REG(t2, T2, k1) 710 SAVE_U_PCB_REG(t3, T3, k1) 711 SAVE_U_PCB_REG(ta0, TA0, k1) 712 SAVE_U_PCB_REG(ta1, TA1, k1) 713 SAVE_U_PCB_REG(ta2, TA2, k1) 714 SAVE_U_PCB_REG(ta3, TA3, k1) 715 SAVE_U_PCB_REG(t8, T8, k1) 716 SAVE_U_PCB_REG(t9, T9, k1) 717 SAVE_U_PCB_REG(gp, GP, k1) 718 SAVE_U_PCB_REG(sp, SP, k1) 719 SAVE_U_PCB_REG(ra, RA, k1) 720/* 721 * save remaining user state in u.u_pcb. 722 */ 723 SAVE_U_PCB_REG(s0, S0, k1) 724 SAVE_U_PCB_REG(s1, S1, k1) 725 SAVE_U_PCB_REG(s2, S2, k1) 726 SAVE_U_PCB_REG(s3, S3, k1) 727 SAVE_U_PCB_REG(s4, S4, k1) 728 SAVE_U_PCB_REG(s5, S5, k1) 729 SAVE_U_PCB_REG(s6, S6, k1) 730 SAVE_U_PCB_REG(s7, S7, k1) 731 SAVE_U_PCB_REG(s8, S8, k1) 732 733 mflo v0 # get lo/hi late to avoid stall 734 mfhi v1 735 mfc0 a0, MIPS_COP_0_STATUS 736 mfc0 a1, MIPS_COP_0_CAUSE 737 MFC0 a3, MIPS_COP_0_EXC_PC 738 SAVE_U_PCB_REG(v0, MULLO, k1) 739 SAVE_U_PCB_REG(v1, MULHI, k1) 740 SAVE_U_PCB_REG(a0, SR, k1) 741 SAVE_U_PCB_REG(a1, CAUSE, k1) 742 SAVE_U_PCB_REG(a3, PC, k1) # PC in a3, note used later! 743 PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP 744 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP 745 746# Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level. 747 and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS_SR_KSU_MASK) 748#ifdef CPU_CNMIPS 749 and t0, t0, ~(MIPS_SR_COP_2_BIT) 750 or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX) 751#elif defined(CPU_RMI) || defined(CPU_NLM) 752 or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) 753#endif 754 mtc0 t0, MIPS_COP_0_STATUS 755 ITLBNOPFIX 756 PTR_ADDU a0, k1, U_PCB_REGS 757/* 758 * Call the interrupt handler. 759 */ 760 PTR_LA k0, _C_LABEL(cpu_intr) 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 846NLEAF(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 nop 1017 1018 .set pop 1019END(MipsTLBInvalidException) 1020 1021/*---------------------------------------------------------------------------- 1022 * 1023 * MipsTLBMissException -- 1024 * 1025 * Handle a TLB miss exception from kernel mode in kernel space. 1026 * The BaddVAddr, Context, and EntryHi registers contain the failed 1027 * virtual address. 1028 * 1029 * Results: 1030 * None. 1031 * 1032 * Side effects: 1033 * None. 1034 * 1035 *---------------------------------------------------------------------------- 1036 */ 1037NLEAF(MipsTLBMissException) 1038 .set noat 1039 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address 1040 PTR_LI k1, VM_MAX_KERNEL_ADDRESS # check fault address against 1041 sltu k1, k1, k0 # upper bound of kernel_segmap 1042 bnez k1, MipsKernGenException # out of bound 1043 lui k1, %hi(kernel_segmap) # k1=hi of segbase 1044 PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost) 1045 PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base 1046 beq k1, zero, MipsKernGenException # ==0 -- no seg tab 1047 andi k0, k0, PDEPTRMASK #06: k0=seg offset 1048 PTR_ADDU k1, k0, k1 # k1=seg entry address 1049 PTR_L k1, 0(k1) # k1=seg entry 1050 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) 1051 beq k1, zero, MipsKernGenException # ==0 -- no page table 1052#ifdef __mips_n64 1053 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN 1054 andi k0, k0, PDEPTRMASK # k0=pde offset 1055 PTR_ADDU k1, k0, k1 # k1=pde entry address 1056 PTR_L k1, 0(k1) # k1=pde entry 1057 MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) 1058 beq k1, zero, MipsKernGenException # ==0 -- no page table 1059#endif 1060 PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN 1061 andi k0, k0, PTE2MASK # k0=page tab offset 1062 PTR_ADDU k1, k1, k0 # k1=pte address 1063 PTE_L k0, 0(k1) # k0=lo0 pte 1064 PTE_L k1, PTESIZE(k1) # k1=lo1 pte 1065 CLEAR_PTE_SWBITS(k0) 1066 PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 # lo0 is loaded 1067 COP0_SYNC 1068 CLEAR_PTE_SWBITS(k1) 1069 PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded 1070 COP0_SYNC 1071 tlbwr # write to tlb 1072 HAZARD_DELAY 1073 eret # return from exception 1074 .set at 1075END(MipsTLBMissException) 1076 1077/*---------------------------------------------------------------------------- 1078 * 1079 * MipsFPTrap -- 1080 * 1081 * Handle a floating point Trap. 1082 * 1083 * MipsFPTrap(statusReg, causeReg, pc) 1084 * unsigned statusReg; 1085 * unsigned causeReg; 1086 * unsigned pc; 1087 * 1088 * Results: 1089 * None. 1090 * 1091 * Side effects: 1092 * None. 1093 * 1094 *---------------------------------------------------------------------------- 1095 */ 1096NON_LEAF(MipsFPTrap, CALLFRAME_SIZ, ra) 1097 PTR_SUBU sp, sp, CALLFRAME_SIZ 1098 mfc0 t0, MIPS_COP_0_STATUS 1099 REG_S ra, CALLFRAME_RA(sp) 1100 .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) 1101 1102 or t1, t0, MIPS_SR_COP_1_BIT 1103 mtc0 t1, MIPS_COP_0_STATUS 1104 ITLBNOPFIX 1105 cfc1 t1, MIPS_FPU_CSR # stall til FP done 1106 cfc1 t1, MIPS_FPU_CSR # now get status 1107 nop 1108 sll t2, t1, (31 - 17) # unimplemented operation? 1109 bgez t2, 3f # no, normal trap 1110 nop 1111/* 1112 * We got an unimplemented operation trap so 1113 * fetch the instruction, compute the next PC and emulate the instruction. 1114 */ 1115 bgez a1, 1f # Check the branch delay bit. 1116 nop 1117/* 1118 * The instruction is in the branch delay slot so the branch will have to 1119 * be emulated to get the resulting PC. 1120 */ 1121 PTR_S a2, CALLFRAME_SIZ + 8(sp) 1122 GET_CPU_PCPU(a0) 1123#mips64 unsafe? 1124 PTR_L a0, PC_CURPCB(a0) 1125 PTR_ADDU a0, a0, U_PCB_REGS # first arg is ptr to CPU registers 1126 move a1, a2 # second arg is instruction PC 1127 move a2, t1 # third arg is floating point CSR 1128 PTR_LA t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch 1129 jalr t3 # compute PC after branch 1130 move a3, zero # fourth arg is FALSE 1131/* 1132 * Now load the floating-point instruction in the branch delay slot 1133 * to be emulated. 1134 */ 1135 PTR_L a2, CALLFRAME_SIZ + 8(sp) # restore EXC pc 1136 b 2f 1137 lw a0, 4(a2) # a0 = coproc instruction 1138/* 1139 * This is not in the branch delay slot so calculate the resulting 1140 * PC (epc + 4) into v0 and continue to MipsEmulateFP(). 1141 */ 11421: 1143 lw a0, 0(a2) # a0 = coproc instruction 1144#xxx mips64 unsafe? 1145 PTR_ADDU v0, a2, 4 # v0 = next pc 11462: 1147 GET_CPU_PCPU(t2) 1148 PTR_L t2, PC_CURPCB(t2) 1149 SAVE_U_PCB_REG(v0, PC, t2) # save new pc 1150/* 1151 * Check to see if the instruction to be emulated is a floating-point 1152 * instruction. 1153 */ 1154 srl a3, a0, MIPS_OPCODE_SHIFT 1155 beq a3, MIPS_OPCODE_C1, 4f # this should never fail 1156 nop 1157/* 1158 * Send a floating point exception signal to the current process. 1159 */ 11603: 1161 GET_CPU_PCPU(a0) 1162 PTR_L a0, PC_CURTHREAD(a0) # get current thread 1163 cfc1 a2, MIPS_FPU_CSR # code = FP execptions 1164 ctc1 zero, MIPS_FPU_CSR # Clear exceptions 1165 PTR_LA t3, _C_LABEL(trapsignal) 1166 jalr t3 1167 li a1, SIGFPE 1168 b FPReturn 1169 nop 1170 1171/* 1172 * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate. 1173 */ 11744: 1175 PTR_LA t3, _C_LABEL(MipsEmulateFP) 1176 jalr t3 1177 nop 1178 1179/* 1180 * Turn off the floating point coprocessor and return. 1181 */ 1182FPReturn: 1183 mfc0 t0, MIPS_COP_0_STATUS 1184 PTR_L ra, CALLFRAME_RA(sp) 1185 and t0, t0, ~MIPS_SR_COP_1_BIT 1186 mtc0 t0, MIPS_COP_0_STATUS 1187 ITLBNOPFIX 1188 j ra 1189 PTR_ADDU sp, sp, CALLFRAME_SIZ 1190END(MipsFPTrap) 1191 1192/* 1193 * Interrupt counters for vmstat. 1194 */ 1195 .data 1196 .globl intrcnt 1197 .globl sintrcnt 1198 .globl intrnames 1199 .globl sintrnames 1200intrnames: 1201 .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 1202sintrnames: 1203#ifdef __mips_n64 1204 .quad INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 1205#else 1206 .int INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 1207#endif 1208 1209 .align (_MIPS_SZLONG / 8) 1210intrcnt: 1211 .space INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 1212sintrcnt: 1213#ifdef __mips_n64 1214 .quad INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 1215#else 1216 .int INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 1217#endif 1218 1219 1220/* 1221 * Vector to real handler in KSEG1. 1222 */ 1223 .text 1224VECTOR(MipsCache, unknown) 1225 PTR_LA k0, _C_LABEL(MipsCacheException) 1226 li k1, MIPS_KSEG0_PHYS_MASK 1227 and k0, k1 1228 PTR_LI k1, MIPS_KSEG1_START 1229 or k0, k1 1230 j k0 1231 nop 1232VECTOR_END(MipsCache) 1233 1234 .set at 1235 1236 1237/* 1238 * Panic on cache errors. A lot more could be done to recover 1239 * from some types of errors but it is tricky. 1240 */ 1241NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra) 1242 .set noat 1243 .mask 0x80000000, -4 1244 PTR_LA k0, _C_LABEL(panic) # return to panic 1245 PTR_LA a0, 9f # panicstr 1246 MFC0 a1, MIPS_COP_0_ERROR_PC 1247 mfc0 a2, MIPS_COP_0_CACHE_ERR # 3rd arg cache error 1248 1249 MTC0 k0, MIPS_COP_0_ERROR_PC # set return address 1250 1251 mfc0 k0, MIPS_COP_0_STATUS # restore status 1252 li k1, MIPS_SR_DIAG_PE # ignore further errors 1253 or k0, k1 1254 mtc0 k0, MIPS_COP_0_STATUS # restore status 1255 COP0_SYNC 1256 1257 eret 1258 1259 MSG("cache error @ EPC 0x%x CachErr 0x%x"); 1260 .set at 1261END(MipsCacheException) 1262