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