1/* $NetBSD: locore_mips1.S,v 1.99 2024/02/09 22:08:32 andvar Exp $ */ 2 3/* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Digital Equipment Corporation and Ralph Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * Copyright (C) 1989 Digital Equipment Corporation. 35 * Permission to use, copy, modify, and distribute this software and 36 * its documentation for any purpose and without fee is hereby granted, 37 * provided that the above copyright notice appears in all copies. 38 * Digital Equipment Corporation makes no representations about the 39 * suitability of this software for any purpose. It is provided "as is" 40 * without express or implied warranty. 41 * 42 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, 43 * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) 44 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, 45 * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) 46 * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, 47 * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) 48 * 49 * @(#)locore.s 8.5 (Berkeley) 1/4/94 50 */ 51#include "opt_cputype.h" 52#include "opt_ddb.h" 53#include "opt_kgdb.h" 54 55#include <sys/cdefs.h> 56 57#include <mips/asm.h> 58#include <mips/cpuregs.h> 59 60RCSID("$NetBSD: locore_mips1.S,v 1.99 2024/02/09 22:08:32 andvar Exp $") 61 62#include "assym.h" 63 64#define _SLLV sllv 65 66#define _SLL sll 67#define _SRL srl 68#define WIRED_SHIFT 2 69 70/* 71 * Use correct-sized m?c0/dm?c0 opcodes. 72 */ 73#define _MFC0 mfc0 74#define _MTC0 mtc0 75 76#if defined(__mips_n32) || defined(__mips_n64) 77#error MIPS1 does not support N32/N64. 78#endif 79 80#define MIPSX(name) __CONCAT(mips1_,name) 81 82 .set noreorder 83 .text 84 85EXPORT(MIPSX(exceptionentry_start)) 86 87/* 88 * mipsN_utlb_miss 89 * 90 * A reference is made (in either kernel or user mode) to a page in 91 * kuseg that has no matching TLB entry. This routine is copied down 92 * at 0x80000000 and total length must be less than 32 instructions. 93 * No pc relative jump instruction is allowed. 94 */ 95VECTOR(MIPSX(utlb_miss), unknown) 96 .set noat 97 _MFC0 k0, MIPS_COP_0_BAD_VADDR #00: k0=bad address 98 lui k1, %hi(CPUVAR(PMAP_SEG0TAB)) #01: k1=hi of seg0tab 99 bltz k0, 1f # R3000 chip bug 100 PTR_SRL k0, SEGSHIFT-PTR_SCALESHIFT #03: k0=seg offset (almost) 101 PTR_L k1, %lo(CPUVAR(PMAP_SEG0TAB))(k1) #04: k1=seg0tab 102 andi k0, (NSEGPG-1)<<PTR_SCALESHIFT #07: k0=seg offset (mask 0x3) 103 PTR_ADDU k1, k0 #08: k1=seg entry address 104 PTR_L k1, 0(k1) #09: k1=seg entry 105 _MFC0 k0, MIPS_COP_0_BAD_VADDR #0a: k0=bad address (again) 106 beqz k1, MIPSX(nopagetable) #0b: ==0 -- no page table 107 PTR_SRL k0, (PGSHIFT-PTPSHIFT) #0c: k0=VPN (aka va>>10) 108 andi k0, (NPTEPG-1) << PTPSHIFT #0d: k0=page table offset 109 PTR_ADDU k1, k0 #0e: k1=pte address 110 INT_L k0, 0(k1) #0f: k0=lo0 pte 111 nop #10: load delay 112 beqz k0, MIPSX(invalidpte) #11: dont load invalid entries 113 nop #12 branch delay 114 mtc0 k0, MIPS_COP_0_TLB_LOW #13: lo0 is loaded 115 nop #14: load delay 116 tlbwr #15: update TLB 1171: 118 _MFC0 k1, MIPS_COP_0_EXC_PC #16: get return address 119 nop #17: load delay 120 j k1 #18: return from 121 rfe #19: exception 122MIPSX(nopagetable): 123MIPSX(invalidpte): 124 j MIPSX(slowfault) #1a: handle the rest 125 nop #1b: branch delay 126 .set at 127VECTOR_END(MIPSX(utlb_miss)) 128 129 130/* 131 * mipsN_exception 132 * 133 * Handles any exceptions other than reset and UTLB miss. This routine 134 * is copied down at 0x80000080 and total length must be less than 32 135 * instructions. No pc relative jump instruction is allowed. 136 */ 137 .org MIPSX(utlb_miss) + 0x80 138VECTOR(MIPSX(exception), unknown) 139/* 140 * Find out what mode we came from and jump to the proper handler. 141 */ 142 .set noat 143 mfc0 k0, MIPS_COP_0_STATUS #00: get the status register 144 mfc0 k1, MIPS_COP_0_CAUSE #01: get the cause register 145 and k0, MIPS1_SR_KU_PREV #02: test for user mode 146 sll k0, 4 #03: shift user bit for cause index 147 and k1, MIPS1_CR_EXC_CODE #04: mask out the cause bits 148 or k1, k0 #05: change index to user table 149 PTR_LA k0, MIPSX(excpt_sw) #06: get base of the jump table 150 PTR_ADDU k0, k1 #08: get the address of the 151 # function entry. Note that 152 # the cause is already 153 # shifted left by 2 bits so 154 # we dont have to shift. 155 PTR_L k0, 0(k0) #09: get the function address 156 nop #0a: load delay 157 j k0 #0b: jump to the function 158 nop #0c 159 nop #0d 160 nop #0e 161 nop #0f 162 .set at 163VECTOR_END(MIPSX(exception)) 164 165 166/*---------------------------------------------------------------------------- 167 * 168 * mipsN_slowfault 169 * 170 * Alternate entry point into the mipsN_user_gen_exception or 171 * mipsN_kern_gen_exception, when the UTLB miss handler couldn't 172 * find a TLB entry. 173 * 174 * Find out what mode we came from and call the appropriate handler. 175 * 176 *---------------------------------------------------------------------------- 177 */ 178MIPSX(slowfault): 179 .set noat 180 mfc0 k0, MIPS_COP_0_STATUS 181 nop 182 and k0, MIPS1_SR_KU_PREV 183 bnez k0, _C_LABEL(MIPSX(user_gen_exception)) 184 nop 185 .set at 186/* 187 * Fall through ... 188 */ 189 190/* 191 * mipsN_kern_gen_exception 192 * 193 * Handle an exception during kernel mode. 194 * Build trapframe on stack to hold interrupted kernel context, then 195 * call trap() to process the condition. 196 * 197 * trapframe is pointed to by the 5th arg and a dummy sixth argument is used 198 * to avoid alignment problems 199 * { 200 * register_t cf_args[4 + 1]; 201 * register_t cf_pad; (for 8 word alignment) 202 * register_t cf_sp; 203 * register_t cf_ra; 204 * struct reg cf_tf; 205 * }; 206 */ 207NESTED_NOPROFILE(MIPSX(kern_gen_exception), KERNFRAME_SIZ, ra) 208 .set noat 209 .mask 0x80000000, -4 210#ifdef PARANOIA 211 PTR_L k0, L_PCB(MIPS_CURLWP) 212 nop 213 slt k0, k0, sp # k0 = L_PCB(MIPS_CURLWP) < sp 2141: beqz k0, 1b # loop forever if false 215 nop 216 PTR_L k0, L_PCB(MIPS_CURLWP) 217 nop 218 PTR_ADDU k0, USPACE 219 slt k0, sp, k0 # k0 = sp < L_PCB(MIPS_CURLWP) + USPACE 2202: beqz k0, 2b # loop forever if false 221 nop 222#endif /* PARANOIA 223/* 224 * Save the relevant kernel registers onto the stack. 225 * We don't need to save s0 - s8, sp and gp because 226 * the compiler does it for us. 227 */ 228 PTR_SUBU sp, KERNFRAME_SIZ 229 REG_S AT, TF_BASE+TF_REG_AST(sp) 230 REG_S v0, TF_BASE+TF_REG_V0(sp) 231 REG_S v1, TF_BASE+TF_REG_V1(sp) 232 mflo v0 233 mfhi v1 234 REG_S a0, TF_BASE+TF_REG_A0(sp) 235 REG_S a1, TF_BASE+TF_REG_A1(sp) 236 REG_S a2, TF_BASE+TF_REG_A2(sp) 237 REG_S a3, TF_BASE+TF_REG_A3(sp) 238 mfc0 a0, MIPS_COP_0_STATUS # 1st arg is STATUS 239 REG_S t0, TF_BASE+TF_REG_T0(sp) 240 REG_S t1, TF_BASE+TF_REG_T1(sp) 241 REG_S t2, TF_BASE+TF_REG_T2(sp) 242 REG_S t3, TF_BASE+TF_REG_T3(sp) 243 mfc0 a1, MIPS_COP_0_CAUSE # 2nd arg is CAUSE 244 REG_S ta0, TF_BASE+TF_REG_TA0(sp) 245 REG_S ta1, TF_BASE+TF_REG_TA1(sp) 246 REG_S ta2, TF_BASE+TF_REG_TA2(sp) 247 REG_S ta3, TF_BASE+TF_REG_TA3(sp) 248 _MFC0 a2, MIPS_COP_0_BAD_VADDR # 3rd arg is fault address 249 #REG_S t8, TF_BASE+TF_REG_T8(sp) # is MIPS_CURLWP 250 REG_S t9, TF_BASE+TF_REG_T9(sp) 251 REG_S ra, TF_BASE+TF_REG_RA(sp) 252 REG_S a0, TF_BASE+TF_REG_SR(sp) 253 _MFC0 a3, MIPS_COP_0_EXC_PC # 4th arg is exception PC 254 REG_S v0, TF_BASE+TF_REG_MULLO(sp) 255 REG_S v1, TF_BASE+TF_REG_MULHI(sp) 256 REG_S a3, TF_BASE+TF_REG_EPC(sp) 257 REG_S a1, TF_BASE+TF_REG_CAUSE(sp) 258#if defined(DDB) || defined(KGDB) 259 REG_S s0, TF_BASE+TF_REG_S0(sp) 260 REG_S s1, TF_BASE+TF_REG_S1(sp) 261 REG_S s2, TF_BASE+TF_REG_S2(sp) 262 REG_S s3, TF_BASE+TF_REG_S3(sp) 263 REG_S s4, TF_BASE+TF_REG_S4(sp) 264 REG_S s5, TF_BASE+TF_REG_S5(sp) 265 REG_S s6, TF_BASE+TF_REG_S6(sp) 266 REG_S s7, TF_BASE+TF_REG_S7(sp) 267 PTR_ADDU v0, sp, KERNFRAME_SIZ 268 REG_S v0, TF_BASE+TF_REG_SP(sp) 269 REG_S s8, TF_BASE+TF_REG_S8(sp) 270 REG_S gp, TF_BASE+TF_REG_GP(sp) 271#endif 272 PTR_ADDU v0, sp, TF_BASE 273 REG_S v0, KERNFRAME_ARG5(sp) # 5th arg is p. to trapframe 274#ifdef PARANOIA 275 /* 276 * save PPL in trapframe 277 */ 278 PTR_L t0, L_CPU(MIPS_CURLWP) 279 nop 280 INT_L t1, CPU_INFO_CPL(t0) # get current priority level 281 nop 282 INT_S t1, TF_BASE+TF_PPL(sp) # save priority level 283#endif /* PARANOIA */ 284 285#if defined(DDB) || defined(DEBUG) || defined(KGDB) 286 PTR_ADDU v0, sp, KERNFRAME_SIZ 287 REG_S v0, KERNFRAME_SP(sp) 288#endif 289 290#ifdef PARANOIA 291 /* 292 * Verify our existing interrupt level. 293 */ 294 jal _C_LABEL(splcheck) 295 nop 296#endif /* PARANOIA */ 297 298 /* 299 * Call the trap handler. 300 */ 301 jal _C_LABEL(trap) 302 REG_S a3, KERNFRAME_RA(sp) # for debugging 303 304 /* 305 * Restore registers and return from the exception. 306 */ 307 REG_L a0, TF_BASE+TF_REG_SR(sp) 308 nop 309 mtc0 a0, MIPS_COP_0_STATUS # restore the SR, disable intrs 310 311 /* 312 * Start of common kernel exception return code for both 313 * mipxN_kern_gen_exception and mipsN_kern_intr. 314 */ 315MIPSX(kern_return): 316 REG_L t0, TF_BASE+TF_REG_MULLO(sp) 317 REG_L t1, TF_BASE+TF_REG_MULHI(sp) 318 REG_L k1, TF_BASE+TF_REG_EPC(sp) # might be changed inside trap 319 mtlo t0 320 mthi t1 321 322#ifdef PARANOIA 323 INT_L t2, TF_BASE+TF_PPL(sp) # get saved priority level 324 PTR_L t0, L_CPU(MIPS_CURLWP) 325 nop 326 INT_L t1, CPU_INFO_CPL(t0) # get current priority level 327 nop 32811: bne t2, t1, 11b # loop forever if unequal 329 nop 330 331 /* 332 * Verify our existing interrupt level. 333 */ 334 jal _C_LABEL(splcheck) 335 nop 336#endif /* PARANOIA */ 337 338 /* 339 * Check for kernel restartable atomic sequences. 340 */ 341 PTR_LA t0, _C_LABEL(_lock_ras_start) 342 li t1, -MIPS_LOCK_RAS_SIZE 343 and t1, k1 344 bne t1, t0, 1f # exception PC in RAS area? 345 nop 346 jal _C_LABEL(_restart_lock_ras) # fix the pc (k1) 347 nop 3481: 349 350 REG_L AT, TF_BASE+TF_REG_AST(sp) 351 REG_L v0, TF_BASE+TF_REG_V0(sp) 352 REG_L v1, TF_BASE+TF_REG_V1(sp) 353 REG_L a0, TF_BASE+TF_REG_A0(sp) 354 REG_L a1, TF_BASE+TF_REG_A1(sp) 355 REG_L a2, TF_BASE+TF_REG_A2(sp) 356 REG_L a3, TF_BASE+TF_REG_A3(sp) 357 REG_L t0, TF_BASE+TF_REG_T0(sp) 358 REG_L t1, TF_BASE+TF_REG_T1(sp) 359 REG_L t2, TF_BASE+TF_REG_T2(sp) 360 REG_L t3, TF_BASE+TF_REG_T3(sp) 361 REG_L ta0, TF_BASE+TF_REG_TA0(sp) 362 REG_L ta1, TF_BASE+TF_REG_TA1(sp) 363 REG_L ta2, TF_BASE+TF_REG_TA2(sp) 364 REG_L ta3, TF_BASE+TF_REG_TA3(sp) 365 #REG_L t8, TF_BASE+TF_REG_T8(sp) # is MIPS_CURLWP 366 REG_L t9, TF_BASE+TF_REG_T9(sp) 367 REG_L ra, TF_BASE+TF_REG_RA(sp) 368#ifdef DDBnotyet 369 REG_L s0, TF_BASE+TF_REG_S0(sp) 370 REG_L s1, TF_BASE+TF_REG_S1(sp) 371 REG_L s2, TF_BASE+TF_REG_S2(sp) 372 REG_L s3, TF_BASE+TF_REG_S3(sp) 373 REG_L s4, TF_BASE+TF_REG_S4(sp) 374 REG_L s5, TF_BASE+TF_REG_S5(sp) 375 REG_L s6, TF_BASE+TF_REG_S6(sp) 376 REG_L s7, TF_BASE+TF_REG_S7(sp) 377 REG_L s8, TF_BASE+TF_REG_S8(sp) 378#endif 379 PTR_ADDU sp, KERNFRAME_SIZ 380 j k1 # return to interrupted point 381 rfe 382 .set at 383END(MIPSX(kern_gen_exception)) 384 385/* 386 * mipsN_kern_intr 387 * 388 * Handle an interrupt from kernel mode. 389 * Build kernframe on stack to hold interrupted kernel context, then 390 * call cpu_intr() to process it. 391 * 392 */ 393NESTED_NOPROFILE(MIPSX(kern_intr), KERNFRAME_SIZ, ra) 394 .set noat 395 .mask 0x80000000, -4 396#ifdef PARANOIA 397 PTR_L k0, L_PCB(MIPS_CURLWP) 398 nop 399 slt k0, k0, sp # k0 = L_PCB(MIPS_CURLWP) < sp 4001: beqz k0, 1b # loop forever if false 401 nop 402 PTR_L k0, L_PCB(MIPS_CURLWP) 403 nop 404 PTR_ADDU k0, USPACE 405 slt k0, sp, k0 # k0 = sp < L_PCB(MIPS_CURLWP) + USPACE 4062: beqz k0, 2b # loop forever if false 407 nop 408 PTR_L k0, L_CPU(MIPS_CURLWP) 409 nop 410 INT_L k0, CPU_INFO_IDEPTH(k0) # grab interrupt depth 411 nop 412 sltu k0, k0, 3 # must be < 3 4133: beqz k0, 3b # loop forever if false 414 nop 415#endif 416 /* 417 * Save the relevant kernel registers onto the stack. We don't need 418 * to save s0 - s8, sp, and gp because the compiler does it for us. 419 * But we use s0-s2 so need to save them. 420 */ 421 PTR_SUBU sp, KERNFRAME_SIZ 422 REG_S AT, TF_BASE+TF_REG_AST(sp) 423 REG_S v0, TF_BASE+TF_REG_V0(sp) 424 REG_S v1, TF_BASE+TF_REG_V1(sp) 425 mflo v0 426 mfhi v1 427 REG_S a0, TF_BASE+TF_REG_A0(sp) 428 REG_S a1, TF_BASE+TF_REG_A1(sp) 429 REG_S a2, TF_BASE+TF_REG_A2(sp) 430 REG_S a3, TF_BASE+TF_REG_A3(sp) 431 REG_S t0, TF_BASE+TF_REG_T0(sp) 432 REG_S t1, TF_BASE+TF_REG_T1(sp) 433 REG_S t2, TF_BASE+TF_REG_T2(sp) 434 REG_S t3, TF_BASE+TF_REG_T3(sp) 435 REG_S ta0, TF_BASE+TF_REG_TA0(sp) 436 REG_S ta1, TF_BASE+TF_REG_TA1(sp) 437 REG_S ta2, TF_BASE+TF_REG_TA2(sp) 438 REG_S ta3, TF_BASE+TF_REG_TA3(sp) 439 REG_S s0, TF_BASE+TF_REG_S0(sp) # used for saved ipl/idepth 440 REG_S s1, TF_BASE+TF_REG_S1(sp) # used for initial status 441 mfc0 s1, MIPS_COP_0_STATUS 442 REG_S s2, TF_BASE+TF_REG_S2(sp) # used for cpu_info 443 #REG_S t8, TF_BASE+TF_REG_T8(sp) # already contains MIPS_CURLWP 444 REG_S t9, TF_BASE+TF_REG_T9(sp) 445 REG_S ra, TF_BASE+TF_REG_RA(sp) 446 REG_S s1, TF_BASE+TF_REG_SR(sp) 447 REG_S v0, TF_BASE+TF_REG_MULLO(sp) 448 REG_S v1, TF_BASE+TF_REG_MULHI(sp) 449/* 450 * Call the interrupt handler. 451 */ 452 _MFC0 ta0, MIPS_COP_0_EXC_PC # grab exception PC 453 PTR_L s2, L_CPU(MIPS_CURLWP) # delay slot 454 REG_S ta0, TF_BASE+TF_REG_EPC(sp) # and save it 455 456#if defined(DDB) || defined(DEBUG) || defined(KGDB) 457 REG_S ta0, KERNFRAME_RA(sp) # for debugging 458#endif 459 460#ifdef PARANOIA 461 INT_L s0, CPU_INFO_CPL(s2) 462 nop # load delay 463 INT_S s0, TF_BASE+TF_PPL(sp) # save priority level 464 465 /* 466 * Verify the current interrupt level 467 */ 468 jal _C_LABEL(splcheck) 469 nop 470#endif /* PARANOIA */ 471 472 /* 473 * We first need to get to IPL_HIGH so that interrupts are masked. 474 */ 475 jal _C_LABEL(splhigh_noprof) 476 nop 477 478#ifdef PARANOIA 4791: bne s0, v0, 1b 480 nop 481#endif /* PARANOIA */ 482 483 sll s0, v0, 8 # remember previous priority 484 # low 8 bits used for idepth 485 486#ifdef PARANOIA 487 /* 488 * Interrupts at IPL_HIGH are not allowed. 489 */ 490 li v1, IPL_HIGH 491 sltu t0, v0, v1 4922: beqz t0, 2b 493 nop 494#endif /* PARANOIA */ 495 496 INT_L t1, CPU_INFO_IDEPTH(s2) # we need to inc. intr depth 497 nop # load delay 498 or s0, t1 # save old interrupt depth 499 INT_ADDU t1, 1 500 INT_S t1, CPU_INFO_IDEPTH(s2) # store new interrupt depth 501 502 /* 503 * Now that we're at splhigh so all interrupts are masked 504 * individually and we won't get interrupted here, turn the 505 * global interrupt enable bit on again. This will allow 506 * high-priority interrupts to be delivered once a 507 * low-priority interrupt handler lowers spl to execute. 508 */ 509 mfc0 v1, MIPS_COP_0_STATUS 510 nop 511 or v0, v1, MIPS_SR_INT_IE 512 mtc0 v0, MIPS_COP_0_STATUS # write new status 513 514 /* 515 * Now hard interrupts can be processed. 516 */ 517 move a1, ta0 # 2nd arg is exception PC 518 move a2, s1 # 3rd arg is status 519 jal _C_LABEL(cpu_intr) # cpu_intr(ppl, pc, status) 520 srl a0, s0, 8 # 1st arg is previous pri level 521 522 and t1, s0, 0xff # get previous interrupt depth 523 INT_S t1, CPU_INFO_IDEPTH(s2) # to it previous value 524 525#ifdef PARANOIA 526 mfc0 t0, MIPS_COP_0_STATUS # verify INT_IE is still set 527 nop 528 and t0, MIPS_SR_INT_IE 5293: beqz t0, 3b 530 nop 531#endif /* PARANOIA */ 532 533#ifdef __HAVE_FAST_SOFTINTS 534 and a0, s1, MIPS_SOFT_INT_MASK # were softints enabled? 535 beqz a0, 4f # nope 536 nop 537 mfc0 v0, MIPS_COP_0_CAUSE # grab the pending softints 538 nop 539 and a0, v0 # are softints pending 540 beqz a0, 4f # nope 541 nop 542 543 jal _C_LABEL(softint_process) # softint_process(pending) 544 nop 545 546#ifdef __HAVE_PREEMPTION 547 srl v1, s0, 8 # get saved priority level 548 bnez v1, 4f # branch if not at IPL_NONE 549 nop 550 INT_L t0, CPU_INFO_SOFTINTS(s2) # get pending softints 551 nop 552 and v0, t0, 1 << SOFTINT_KPREEMPT # do we need a kernel preempt? 553 beqz v0, 4f # nope 554 nop 555 xor t0, v0 # clear preempt bit 556 INT_S t0, CPU_INFO_SOFTINTS(s2) # and save it. 557 jal _C_LABEL(kpreempt) # kpreempt(pc) 558 PTR_L a0, TF_BASE+TF_REG_EPC(sp) 559#endif /* __HAVE_PREEMPTION */ 5604: 561#endif /* __HAVE_FAST_SOFTINTS */ 562 /* 563 * Interrupts handled, restore registers and return from the interrupt. 564 * First, clear interrupt enable 565 */ 566 mtc0 s1, MIPS_COP_0_STATUS # disable interrupts 567 568 srl a0, s0, 8 # get previous priority level 569#ifdef PARANOIA 570 INT_L t0, TF_BASE+TF_PPL(sp) # get saved priority level 571 nop 5729: bne t0, a0, 9b # should still match 573 nop 574 575 li t0, IPL_HIGH 576 sltu v0, a0, t0 5778: beqz v0, 8b 578 nop 579#endif /* PARANOIA */ 580 581 /* 582 * Restore IPL knowing interrupts are disabled 583 */ 584 jal _C_LABEL(splx_noprof) # splx(ppl) 585 nop 586 587#ifdef PARANOIA 588 mfc0 v0, MIPS_COP_0_STATUS 589 nop 590 or v0, MIPS_SR_INT_IE 5915: bne v0, s1, 5b 592 nop 593#endif /* PARANOIA */ 594 595 /* 596 * Restore SR 597 */ 598 mtc0 s1, MIPS_COP_0_STATUS 599 600 /* 601 * Restore s0-s2 and goto common kernel return code. 602 */ 603 REG_L s0, TF_BASE+TF_REG_S0(sp) 604 REG_L s1, TF_BASE+TF_REG_S1(sp) 605 b MIPSX(kern_return) 606 REG_L s2, TF_BASE+TF_REG_S2(sp) 607 .set at 608END(MIPSX(kern_intr)) 609 610/* 611 * mipsN_user_gen_exception 612 * 613 * Handle an exception during user mode. 614 * Save user context atop the kernel stack, then call trap() to process 615 * the condition. The context can be manipulated alternatively via 616 * curlwp->l_md.md_regs. 617 */ 618NESTED_NOPROFILE(MIPSX(user_gen_exception), CALLFRAME_SIZ, ra) 619 .set noat 620 .mask 0x80000000, -4 621 /* 622 * Save all the registers except the kernel temporaries onto the stack. 623 */ 624 PTR_L k1, CPUVAR(CURLWP) 625 nop 626 PTR_L k0, L_PCB(k1) 627 nop 628 PTR_ADDU k0, USPACE - TF_SIZ - CALLFRAME_SIZ 629 REG_S AT, CALLFRAME_SIZ+TF_REG_AST(k0) 630 REG_S v0, CALLFRAME_SIZ+TF_REG_V0(k0) 631 REG_S v1, CALLFRAME_SIZ+TF_REG_V1(k0) 632 mflo v0 633 REG_S a0, CALLFRAME_SIZ+TF_REG_A0(k0) 634 REG_S a1, CALLFRAME_SIZ+TF_REG_A1(k0) 635 REG_S a2, CALLFRAME_SIZ+TF_REG_A2(k0) 636 REG_S a3, CALLFRAME_SIZ+TF_REG_A3(k0) 637 mfhi v1 638 REG_S t0, CALLFRAME_SIZ+TF_REG_T0(k0) 639 REG_S t1, CALLFRAME_SIZ+TF_REG_T1(k0) 640 REG_S t2, CALLFRAME_SIZ+TF_REG_T2(k0) 641 REG_S t3, CALLFRAME_SIZ+TF_REG_T3(k0) 642 mfc0 a0, MIPS_COP_0_STATUS # 1st arg is STATUS 643 REG_S ta0, CALLFRAME_SIZ+TF_REG_TA0(k0) 644 REG_S ta1, CALLFRAME_SIZ+TF_REG_TA1(k0) 645 REG_S ta2, CALLFRAME_SIZ+TF_REG_TA2(k0) 646 REG_S ta3, CALLFRAME_SIZ+TF_REG_TA3(k0) 647 mfc0 a1, MIPS_COP_0_CAUSE # 2nd arg is CAUSE 648 REG_S s0, CALLFRAME_SIZ+TF_REG_S0(k0) 649 REG_S s1, CALLFRAME_SIZ+TF_REG_S1(k0) 650 REG_S s2, CALLFRAME_SIZ+TF_REG_S2(k0) 651 REG_S s3, CALLFRAME_SIZ+TF_REG_S3(k0) 652 _MFC0 a2, MIPS_COP_0_BAD_VADDR # 3rd arg is fault address 653 REG_S s4, CALLFRAME_SIZ+TF_REG_S4(k0) 654 REG_S s5, CALLFRAME_SIZ+TF_REG_S5(k0) 655 REG_S s6, CALLFRAME_SIZ+TF_REG_S6(k0) 656 REG_S s7, CALLFRAME_SIZ+TF_REG_S7(k0) 657 _MFC0 a3, MIPS_COP_0_EXC_PC # 4th arg is exception PC 658 REG_S t8, CALLFRAME_SIZ+TF_REG_T8(k0) # will be MIPS_CURLWP 659 REG_S t9, CALLFRAME_SIZ+TF_REG_T9(k0) 660 REG_S gp, CALLFRAME_SIZ+TF_REG_GP(k0) 661 REG_S sp, CALLFRAME_SIZ+TF_REG_SP(k0) 662 REG_S s8, CALLFRAME_SIZ+TF_REG_S8(k0) 663 REG_S ra, CALLFRAME_SIZ+TF_REG_RA(k0) 664 REG_S a0, CALLFRAME_SIZ+TF_REG_SR(k0) 665 REG_S v0, CALLFRAME_SIZ+TF_REG_MULLO(k0) 666 REG_S v1, CALLFRAME_SIZ+TF_REG_MULHI(k0) 667 REG_S a3, CALLFRAME_SIZ+TF_REG_EPC(k0) 668#ifdef __GP_SUPPORT__ 669 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP 670#endif 671 move sp, k0 # switch to kernel SP 672 move MIPS_CURLWP, k1 673#ifndef NOFPU 674 lui t0, %hi(MIPS_SR_COP_1_BIT) 675 and t0, a0 676 beqz t0, 1f 677 xor t0, a0 # turn off the FPU 678 mtc0 t0, MIPS_COP_0_STATUS 679 nop 6801: 681#endif 682/* 683 * Call the trap handler. 684 */ 685 jal _C_LABEL(trap) 686 REG_S a3, CALLFRAME_RA(sp) # for debugging 687/* 688 * Check pending asynchronous traps. 689 */ 690 INT_L v0, L_MD_ASTPENDING(MIPS_CURLWP)# any pending ast? 691 nop 692 beqz v0, MIPSX(user_return) # if no, skip ast processing 693 nop 694/* 695 * We have pending asynchronous traps; all the state is already saved. 696 */ 697 lui ra, %hi(MIPSX(user_return)) # return directly to user return 698 j _C_LABEL(ast) 699 PTR_ADDIU ra, %lo(MIPSX(user_return)) # return directly to user return 700 .set at 701END(MIPSX(user_gen_exception)) 702 703/*---------------------------------------------------------------------------- 704 * 705 * mipsN_user_intr 706 * 707 * Handle an interrupt from user mode. 708 * We save partial state onto the kernel stack since we know there will 709 * always a kernel stack and chances are we won't need the registers we 710 * don't save. If there is a pending asynchronous system trap, then save 711 * the remaining state and call ast(). 712 * 713 * Results: 714 * None. 715 * 716 * Side effects: 717 * None. 718 * 719 *---------------------------------------------------------------------------- 720 */ 721NESTED_NOPROFILE(MIPSX(user_intr), CALLFRAME_SIZ, ra) 722 .set noat 723 .mask 0x80000000, -4 724/* 725 * Save the relevant user registers onto the kernel stack. 726 * We don't need to save s0 - s8 because the compiler does it for us. 727 */ 728 PTR_L k1, CPUVAR(CURLWP) 729 nop 730 PTR_L k0, L_PCB(k1) # XXXuvm_lwp_getuarea 731 nop 732 PTR_ADDU k0, USPACE - TF_SIZ - CALLFRAME_SIZ 733 REG_S AT, CALLFRAME_SIZ+TF_REG_AST(k0) # $1 734 REG_S v0, CALLFRAME_SIZ+TF_REG_V0(k0) # $2 735 REG_S v1, CALLFRAME_SIZ+TF_REG_V1(k0) # $3 736 mflo v0 737 REG_S a0, CALLFRAME_SIZ+TF_REG_A0(k0) # $4 738 REG_S a1, CALLFRAME_SIZ+TF_REG_A1(k0) # $5 739 REG_S a2, CALLFRAME_SIZ+TF_REG_A2(k0) # $6 740 REG_S a3, CALLFRAME_SIZ+TF_REG_A3(k0) # $7 741 mfhi v1 742 REG_S t0, CALLFRAME_SIZ+TF_REG_T0(k0) # $8 743 REG_S t1, CALLFRAME_SIZ+TF_REG_T1(k0) # $9 744 REG_S t2, CALLFRAME_SIZ+TF_REG_T2(k0) # $10 745 REG_S t3, CALLFRAME_SIZ+TF_REG_T3(k0) # $11 746 mfc0 t0, MIPS_COP_0_CAUSE 747 REG_S ta0, CALLFRAME_SIZ+TF_REG_TA0(k0) # $12 748 REG_S ta1, CALLFRAME_SIZ+TF_REG_TA1(k0) # $13 749 REG_S ta2, CALLFRAME_SIZ+TF_REG_TA2(k0) # $14 750 REG_S ta3, CALLFRAME_SIZ+TF_REG_TA3(k0) # $15 751 REG_S s0, CALLFRAME_SIZ+TF_REG_S0(k0) # $16 752 REG_S s1, CALLFRAME_SIZ+TF_REG_S1(k0) # $17 753 mfc0 s1, MIPS_COP_0_STATUS 754 REG_S t8, CALLFRAME_SIZ+TF_REG_T8(k0) # $24 MIPS_CURLWP 755 REG_S t9, CALLFRAME_SIZ+TF_REG_T9(k0) # $25 756 REG_S gp, CALLFRAME_SIZ+TF_REG_GP(k0) # $28 757 REG_S sp, CALLFRAME_SIZ+TF_REG_SP(k0) # $29 758 REG_S ra, CALLFRAME_SIZ+TF_REG_RA(k0) # $31 759 REG_S s1, CALLFRAME_SIZ+TF_REG_SR(k0) 760 _MFC0 ta0, MIPS_COP_0_EXC_PC 761 REG_S v0, CALLFRAME_SIZ+TF_REG_MULLO(k0) 762 REG_S v1, CALLFRAME_SIZ+TF_REG_MULHI(k0) 763 REG_S ta0, CALLFRAME_SIZ+TF_REG_EPC(k0) 764 REG_S t0, CALLFRAME_SIZ+TF_REG_CAUSE(k0) 765 move sp, k0 # switch to kernel SP 766 move MIPS_CURLWP, k1 # set curlwp reg (t8) 767#if defined(DDB) || defined(DEBUG) || defined(KGDB) 768 REG_S ta0, CALLFRAME_RA(sp) # for debugging 769#endif 770#ifdef __GP_SUPPORT__ 771 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP 772#endif 773 774 /* 775 * We first need to get to IPL_HIGH so that interrupts are masked. 776 */ 777 jal _C_LABEL(splhigh_noprof) # splhigh() 778 nop 779 move s0, v0 # remember previous priority 780 781 /* 782 * Now that we're at splhigh so all interrupts are masked 783 * individually and we won't get interrupted here, turn the 784 * global interrupt enable bit on again. This will allow 785 * high-priority interrupts to be delivered once a 786 * low-priority interrupt handler lowers spl to execute. 787 * 788 * Also switch off the FPU. 789 */ 790 mfc0 v1, MIPS_COP_0_STATUS 791#ifndef NOFPU 792 lui v0, %hi(MIPS_SR_COP_1_BIT) 793 and v0, v1 794 or v0, MIPS_SR_INT_IE # make sure intrs are still on 795#else 796 li v0, MIPS_SR_INT_IE # reenable intrs 797#endif 798 xor v0, v1 799 mtc0 v0, MIPS_COP_0_STATUS 800 nop 801 802 /* 803 * Since we interrupted user mode, the new interrupt depth must be 1. 804 */ 805 PTR_L t0, L_CPU(MIPS_CURLWP) 806 li t1, 1 807 INT_S t1, CPU_INFO_IDEPTH(t0) # store new interrupt depth (1) 808 809 /* 810 * Now hard interrupts can be processed. 811 */ 812 move a1, ta0 # 2nd arg is exception pc 813 move a2, s1 # 3rd arg is status 814 jal _C_LABEL(cpu_intr) # cpu_intr(ppl, pc, status) 815 move a0, s0 # 1st arg is previous pri level 816 817 /* 818 * Interrupt depth is now back to 0. 819 */ 820 PTR_L t0, L_CPU(MIPS_CURLWP) 821 nop 822 INT_S zero, CPU_INFO_IDEPTH(t0) 823 824#ifdef __HAVE_FAST_SOFTINTS 825 /* 826 * This an interrupt from user mode so both softints must be enabled. 827 * No need to check (unless we're being paranoid). 828 */ 829#ifdef PARANOIA 830 and a0, s1, MIPS_SOFT_INT_MASK # get softints enabled bits 831 xor a0, MIPS_SOFT_INT_MASK # invert them. 8321: bnez a0, 1b # loop forever if disabled 833 nop 834#endif 835 mfc0 a0, MIPS_COP_0_CAUSE # grab the pending softints 836 nop # load delay 837 and a0, MIPS_SOFT_INT_MASK # are there softints pending 838 beqz a0, 4f # nope 839 nop 840 jal _C_LABEL(softint_process) # softint_process(pending) 841 nop 8424: 843#endif 844 /* 845 * Disable interrupts 846 */ 847 mfc0 v1, MIPS_COP_0_STATUS 848 nop # delay slot 849 and v0, v1, MIPS_SR_INT_IE # clear interrupt enable 850 xor v0, v1 851 mtc0 v0, MIPS_COP_0_STATUS # interrupts are disabled 852 853 /* 854 * Restore IPL knowing interrupts are off 855 */ 856 jal _C_LABEL(splx_noprof) 857 move a0, s0 # fetch previous priority level 858 859 /* 860 * Check pending asynchronous traps. 861 */ 862 REG_L s0, CALLFRAME_SIZ+TF_REG_S0(sp) # restore 863 REG_L s1, CALLFRAME_SIZ+TF_REG_S1(sp) # restore 864 INT_L v0, L_MD_ASTPENDING(MIPS_CURLWP)# any pending ast? 865 nop 866 beqz v0, MIPSX(user_intr_return) # if no, skip ast processing 867 nop 868 869 /* 870 * We have a pending asynchronous trap; save remaining user state into 871 * trapframe. 872 */ 873 #REG_S s0, CALLFRAME_SIZ+TF_REG_S0(sp) # $16 (saved above) 874 #REG_S s1, CALLFRAME_SIZ+TF_REG_S1(sp) # $17 (saved above) 875 REG_S s2, CALLFRAME_SIZ+TF_REG_S2(sp) # $18 876 REG_S s3, CALLFRAME_SIZ+TF_REG_S3(sp) # $19 877 REG_S s4, CALLFRAME_SIZ+TF_REG_S4(sp) # $20 878 REG_S s5, CALLFRAME_SIZ+TF_REG_S5(sp) # $21 879 REG_S s6, CALLFRAME_SIZ+TF_REG_S6(sp) # $22 880 REG_S s7, CALLFRAME_SIZ+TF_REG_S7(sp) # $23 881 REG_S s8, CALLFRAME_SIZ+TF_REG_S8(sp) # $30 882 883 mfc0 t0, MIPS_COP_0_STATUS 884 PTR_LA ra, MIPSX(user_return) # load delay 885 or t0, MIPS_SR_INT_IE # enable interrupts 886 j _C_LABEL(ast) # ast() 887 mtc0 t0, MIPS_COP_0_STATUS # enable interrupts (spl0) 888 .set at 889END(MIPSX(user_intr)) 890 891/* 892 * mipsN_systemcall 893 * 894 * Save user context atop of kernel stack, then call syscall() to process 895 * a system call. The context can be manipulated alternatively via 896 * curlwp->l_md.md_utf->tf_regs. 897 */ 898NESTED_NOPROFILE(MIPSX(systemcall), CALLFRAME_SIZ, ra) 899 .set noat 900 .mask 0x80000000, -4 901 /* 902 * Save all the registers but kernel temporaries onto the stack. 903 */ 904 PTR_L k1, CPUVAR(CURLWP) 905 nop 906 PTR_L k0, L_PCB(k1) 907 nop 908 PTR_ADDU k0, USPACE - TF_SIZ - CALLFRAME_SIZ 909 #REG_S AT, CALLFRAME_SIZ+TF_REG_AST(k0) 910 #.set at 911 REG_S v0, CALLFRAME_SIZ+TF_REG_V0(k0) # syscall # 912 REG_S v1, CALLFRAME_SIZ+TF_REG_V1(k0) # used by syscall() 913 mflo v0 914 REG_S a0, CALLFRAME_SIZ+TF_REG_A0(k0) 915 REG_S a1, CALLFRAME_SIZ+TF_REG_A1(k0) 916 REG_S a2, CALLFRAME_SIZ+TF_REG_A2(k0) 917 REG_S a3, CALLFRAME_SIZ+TF_REG_A3(k0) 918 move a0, k1 # 1st arg is curlwp 919 mfhi v1 920 mfc0 a1, MIPS_COP_0_STATUS # 2nd arg is STATUS 921 REG_S s0, CALLFRAME_SIZ+TF_REG_S0(k0) 922 REG_S s1, CALLFRAME_SIZ+TF_REG_S1(k0) 923 REG_S s2, CALLFRAME_SIZ+TF_REG_S2(k0) 924 REG_S s3, CALLFRAME_SIZ+TF_REG_S3(k0) 925 mfc0 a2, MIPS_COP_0_CAUSE # 3rd arg is CAUSE 926 REG_S s4, CALLFRAME_SIZ+TF_REG_S4(k0) 927 REG_S s5, CALLFRAME_SIZ+TF_REG_S5(k0) 928 REG_S s6, CALLFRAME_SIZ+TF_REG_S6(k0) 929 REG_S s7, CALLFRAME_SIZ+TF_REG_S7(k0) 930 _MFC0 a3, MIPS_COP_0_EXC_PC # 4th arg is PC 931 REG_S t0, CALLFRAME_SIZ+TF_REG_T0(k0) 932 REG_S t1, CALLFRAME_SIZ+TF_REG_T1(k0) 933 REG_S t2, CALLFRAME_SIZ+TF_REG_T2(k0) 934 REG_S t3, CALLFRAME_SIZ+TF_REG_T3(k0) # syscall saved gp for fork 935 REG_S ta0, CALLFRAME_SIZ+TF_REG_TA0(k0) 936 REG_S ta1, CALLFRAME_SIZ+TF_REG_TA1(k0) 937 REG_S ta2, CALLFRAME_SIZ+TF_REG_TA2(k0) 938 REG_S ta3, CALLFRAME_SIZ+TF_REG_TA3(k0) 939 REG_S t8, CALLFRAME_SIZ+TF_REG_T8(k0) # will be MIPS_CURLWP 940 REG_S t9, CALLFRAME_SIZ+TF_REG_T9(k0) 941 REG_S gp, CALLFRAME_SIZ+TF_REG_GP(k0) 942 REG_S sp, CALLFRAME_SIZ+TF_REG_SP(k0) 943 REG_S s8, CALLFRAME_SIZ+TF_REG_S8(k0) 944 REG_S ra, CALLFRAME_SIZ+TF_REG_RA(k0) 945 REG_S a1, CALLFRAME_SIZ+TF_REG_SR(k0) 946 REG_S v0, CALLFRAME_SIZ+TF_REG_MULLO(k0) 947 REG_S v1, CALLFRAME_SIZ+TF_REG_MULHI(k0) 948 REG_S a3, CALLFRAME_SIZ+TF_REG_EPC(k0) 949 PTR_L t0, L_PROC(a0) # curlwp->l_proc (used below) 950 move sp, k0 # switch to kernel SP 951 move MIPS_CURLWP, a0 # set curlwp reg 952#ifdef __GP_SUPPORT__ 953 PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP 954#endif 955#if defined(DDB) || defined(DEBUG) || defined(KGDB) 956 move ra, a3 957 REG_S ra, CALLFRAME_RA(sp) 958#endif 959 PTR_L t9, P_MD_SYSCALL(t0) # t9 = syscall 960 /* 961 * Turn off FPU 962 */ 963#ifdef NOFPU 964 li t0, MIPS_SR_INT_IE 965#else 966 lui t0, %hi(MIPS_SR_COP_1_BIT) 967 and t0, a1 968 ori t0, MIPS_SR_INT_IE # turn on IEc, enable intr. 969#endif 970 xor t0, a1 # turns off the FPU & ints on 971 mtc0 t0, MIPS_COP_0_STATUS # re-enable interrupts 972/* 973 * Call the system call handler. 974 */ 975 jalr t9 976 nop 977/* 978 * Check pending asynchronous traps. 979 */ 980 INT_L v0, L_MD_ASTPENDING(MIPS_CURLWP)# any pending ast? 981 nop 982 beqz v0, MIPSX(user_return) # no, skip ast processing 983 nop 984/* 985 * We have pending asynchronous traps; all the state is already saved. 986 */ 987 lui ra, %hi(MIPSX(user_return)) # return directly to user return 988 j _C_LABEL(ast) 989 PTR_ADDIU ra, %lo(MIPSX(user_return)) # return directly to user return 990 .set at 991END(MIPSX(systemcall)) 992 993/*---------------------------------------------------------------------------- 994 * 995 * R3000 TLB exception handlers 996 * 997 *---------------------------------------------------------------------------- 998 */ 999 1000/*---------------------------------------------------------------------------- 1001 * 1002 * mipsN_kern_tlb_miss -- 1003 * 1004 * Handle a TLB miss exception from kernel mode in kernel space. 1005 * The BaddVAddr, Context, and EntryHi registers contain the failed 1006 * virtual address. 1007 * 1008 * Results: 1009 * None. 1010 * 1011 * Side effects: 1012 * None. 1013 * 1014 *---------------------------------------------------------------------------- 1015 */ 1016LEAF_NOPROFILE(MIPSX(kern_tlb_miss)) 1017 .set noat 1018 _MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address 1019 PTR_LA k1, _C_LABEL(pmap_kern_segtab) # get address of kernel segtab 1020 PTR_SRL k0, SEGSHIFT - PTR_SCALESHIFT # get segtab index (part1) 1021 and k0, (NSEGPG-1) << PTR_SCALESHIFT # get segtab index (part2) 1022 PTR_ADDU k1, k0 # add index to segtab addr 1023 PTR_L k1, 0(k1) # load address of PTP 1024 _MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address 1025 /* 1026 * If there isn't a PTP for this, let trap panic for us. 1027 */ 1028 beqz k1, _C_LABEL(MIPSX(kern_gen_exception)) # full trap processing 1029 PTR_SRL k0, PGSHIFT - PTPSHIFT # - delay slot - 1030 and k0, (NPTEPG-1) << PTPSHIFT # get ptp index (part2) 1031 PTR_ADDU k1, k0 # add to PTP address 1032 INT_L k0, 0(k1) # get PTE entry 1033 _MFC0 k1, MIPS_COP_0_EXC_PC # get return address 1034 mtc0 k0, MIPS_COP_0_TLB_LOW # save PTE entry 1035 and k0, MIPS1_PG_V # check for valid PTE entry 1036 beqz k0, _C_LABEL(MIPSX(kern_gen_exception)) # PTE invalid 1037 nop 1038 tlbwr # write random TLB 1039 j k1 1040 rfe 1041 .set at 1042END(MIPSX(kern_tlb_miss)) 1043 1044#if 0 1045/*---------------------------------------------------------------------------- 1046 * 1047 * mipsN_tlb_invalid_exception -- 1048 * 1049 * Handle a TLB modified exception. 1050 * The BaddVAddr, Context, and EntryHi registers contain the failed 1051 * virtual address. 1052 * 1053 * Results: 1054 * None. 1055 * 1056 * Side effects: 1057 * None. 1058 * 1059 *---------------------------------------------------------------------------- 1060 */ 1061LEAF_NOPROFILE(MIPSX(tlb_mod_exception)) 1062 .set noat 1063 tlbp # find the TLB entry 1064 mfc0 k0, MIPS_COP_0_TLB_LOW # get the physical address 1065 mfc0 k1, MIPS_COP_0_TLB_INDEX # check to be sure its valid 1066 or k0, k0, MIPS1_TLB_DIRTY_BIT # update TLB 1067 blt k1, zero, 4f # not found!!! 1068 mtc0 k0, MIPS_COP_0_TLB_LOW 1069 li k1, MIPS_KSEG0_START 1070 PTR_SUBU k0, k1 1071 srl k0, k0, MIPS1_TLB_PHYS_PAGE_SHIFT 1072 PTR_L k1, pmap_attributes # DANGER! DANGER! 1073 PTR_ADDU k0, k1 1074 lbu k1, 0(k0) # fetch old value 1075 nop 1076 or k1, k1, 1 # set modified bit 1077 sb k1, 0(k0) # save new value 1078 _MFC0 k0, MIPS_COP_0_EXC_PC # get return address 1079 nop 1080 j k0 1081 rfe 10824: 1083 break 0 # panic 1084 .set at 1085END(MIPSX(tlb_mod_exception)) 1086#endif 1087 1088/* 1089 * Mark where code entered from exception handler jumptable 1090 * ends, for stack traceback code. 1091 */ 1092 1093 .globl _C_LABEL(MIPSX(exceptionentry_end)) 1094_C_LABEL(MIPSX(exceptionentry_end)): 1095 1096/*-------------------------------------------------------------------------- 1097 * 1098 * mipsN_tlb_get_asid -- 1099 * 1100 * Return the pid from the TLB pid reg. 1101 * 1102 * tlb_asid_t mipsN_tlb_get_asid(void) 1103 * 1104 * Results: 1105 * The current ASID. 1106 * 1107 * Side effects: 1108 * None. 1109 * 1110 *-------------------------------------------------------------------------- 1111 */ 1112LEAF(MIPSX(tlb_get_asid)) 1113 mfc0 v0, MIPS_COP_0_TLB_HI # Read the hi reg value 1114 nop 1115 and v0, MIPS1_TLB_PID # mask out only the PID 1116 j ra 1117 srl v0, MIPS1_TLB_PID_SHIFT # put PID in right spot 1118END(MIPSX(tlb_get_asid)) 1119 1120/*-------------------------------------------------------------------------- 1121 * 1122 * mipsN_tlb_set_asid -- 1123 * 1124 * Write the given pid into the TLB pid reg. 1125 * 1126 * void mipsN_tlb_set_asid(tlb_asid_t pid) 1127 * 1128 * Results: 1129 * None. 1130 * 1131 * Side effects: 1132 * PID set in the entry hi register. 1133 * 1134 *-------------------------------------------------------------------------- 1135 */ 1136LEAF(MIPSX(tlb_set_asid)) 1137 sll a0, MIPS1_TLB_PID_SHIFT # put PID in right spot 1138 and a0, MIPS1_TLB_PID 1139 mtc0 a0, MIPS_COP_0_TLB_HI # Write the hi reg value 1140 j ra 1141 nop 1142END(MIPSX(tlb_set_asid)) 1143 1144/*-------------------------------------------------------------------------- 1145 * 1146 * mipsN_tlb_update_addr -- 1147 * 1148 * Update the TLB if highreg is found; otherwise, do_nothing 1149 * 1150 * bool mipsN_tlb_update_addr(vaddr_t va, tlb_asid_t asid, 1151 * pt_entry_t pte, bool insert); 1152 * 1153 * Results: 1154 * 0 if skipped, 1 if updated 1155 * 1156 * Side effects: 1157 * None. 1158 * 1159 *-------------------------------------------------------------------------- 1160 */ 1161LEAF(MIPSX(tlb_update_addr)) 1162 mfc0 ta0, MIPS_COP_0_STATUS # save the status register 1163 mtc0 zero, MIPS_COP_0_STATUS # disable interrupts 1164 nop 1165 mfc0 ta1, MIPS_COP_0_TLB_HI # save current PID 1166 nop 1167 sll a1, MIPS1_TLB_PID_SHIFT 1168 or a0, a1 1169 mtc0 a0, MIPS_COP_0_TLB_HI # set entryhi 1170 nop 1171 tlbp # probe the existence 1172 mfc0 v0, MIPS_COP_0_TLB_INDEX # see what we got 1173 mtc0 a2, MIPS_COP_0_TLB_LOW # set new entrylo 1174 bltz v0, 2f # index < 0 => !found 1175 nop 1176 tlbwi # update slot found 1177 b 3f # return 1178 li v0, 1 # and show success 11792: 1180 beqz a2, 3f # return 1181 li v0, 0 # and show failure 1182 tlbwr # put it in a new slot 1183 li v0, 1 # show success 11843: 1185 mtc0 ta1, MIPS_COP_0_TLB_HI # restore current PID 1186 j ra 1187 mtc0 ta0, MIPS_COP_0_STATUS # restore interrupts 1188END(MIPSX(tlb_update_addr)) 1189 1190/*-------------------------------------------------------------------------- 1191 * 1192 * mipsN_tlb_read_entry -- 1193 * 1194 * Read the TLB entry. 1195 * 1196 * void mipsN_tlb_read_entry(register_t entry, struct tlbmask *tlb) 1197 * 1198 * Results: 1199 * tlb will contain the TLB entry found (tlb_lo1/tlb_mask will be 0). 1200 * 1201 *-------------------------------------------------------------------------- 1202 */ 1203LEAF(MIPSX(tlb_read_entry)) 1204 mfc0 ta0, MIPS_COP_0_STATUS # Save the status register. 1205 mtc0 zero, MIPS_COP_0_STATUS # Disable interrupts 1206 mfc0 ta1, MIPS_COP_0_TLB_HI # Get current PID 1207 1208 sll a0, MIPS1_TLB_INDEX_SHIFT 1209 mtc0 a0, MIPS_COP_0_TLB_INDEX # Set the index register 1210 nop 1211 tlbr # Read from the TLB 1212 mfc0 t2, MIPS_COP_0_TLB_HI # fetch the hi entry 1213 mfc0 t3, MIPS_COP_0_TLB_LOW # fetch the low entry 1214 1215 mtc0 ta1, MIPS_COP_0_TLB_HI # Restore proper PID 1216 # (before touching memory) 1217 mtc0 ta0, MIPS_COP_0_STATUS # Restore the status register 1218 1219 PTR_S t2, TLBMASK_HI(a1) 1220 REG_S t3, TLBMASK_LO0(a1) 1221 REG_S zero, TLBMASK_LO1(a1) 1222 j ra 1223 INT_S zero, TLBMASK_MASK(a1) 1224END(MIPSX(tlb_read_entry)) 1225 1226/*-------------------------------------------------------------------------- 1227 * 1228 * mipsX_tlb_write_entry -- 1229 * 1230 * Write the TLB entry. 1231 * 1232 * void mipsX_tlb_write_entry(size_t entry, struct tlbmask *tlb) 1233 * 1234 * Results: 1235 * None. 1236 * 1237 *-------------------------------------------------------------------------- 1238 */ 1239LEAF(MIPSX(tlb_write_entry)) 1240 PTR_L t2, TLBMASK_HI(a1) # fetch the hi entry 1241 INT_L t3, TLBMASK_LO0(a1) # fetch the low entry 1242 mfc0 ta0, MIPS_COP_0_STATUS # Save the status register. 1243 mtc0 zero, MIPS_COP_0_STATUS # Disable interrupts 1244 mfc0 ta1, MIPS_COP_0_TLB_HI # Get current PID 1245 1246 sll a0, MIPS1_TLB_INDEX_SHIFT 1247 mtc0 a0, MIPS_COP_0_TLB_INDEX # Set the index register 1248 nop 1249 mtc0 t2, MIPS_COP_0_TLB_HI 1250 mtc0 t3, MIPS_COP_0_TLB_LOW 1251 1252 tlbwi # Write to the TLB entry 1253 1254 mtc0 ta1, MIPS_COP_0_TLB_HI # restore PID 1255 j ra 1256 mtc0 ta0, MIPS_COP_0_STATUS # Restore the status register 1257END(MIPSX(tlb_write_entry)) 1258 1259/* 1260 * void mipsN_tlb_invalidate_addr(vaddr_t va, tlb_asid_t asid) 1261 * 1262 * Invalidate a TLB entry for given virtual address if found in TLB. 1263 */ 1264LEAF(MIPSX(tlb_invalidate_addr)) 1265 mfc0 ta0, MIPS_COP_0_STATUS # save status register 1266 mtc0 zero, MIPS_COP_0_STATUS # disable interrupts 1267 mfc0 ta1, MIPS_COP_0_TLB_HI # save current PID 1268 nop 1269 1270 sll a1, MIPS1_TLB_PID_SHIFT # move ASID into position 1271 and a1, MIPS1_TLB_PID # make it off 1272 or a0, a1 # merge with addr 1273 mtc0 a0, MIPS_COP_0_TLB_HI # look for addr & PID 1274 nop 1275 tlbp # probe the entry in question 1276 mfc0 a0, MIPS_COP_0_TLB_INDEX # see what we got 1277 li t1, MIPS_KSEG0_START # load invalid address 1278 bltz a0, 1f # index < 0 then skip 1279 nop 1280 mtc0 t1, MIPS_COP_0_TLB_HI # make entryHi invalid 1281 mtc0 zero, MIPS_COP_0_TLB_LOW # zero out entryLo 1282 nop 1283 tlbwi 12841: 1285 mtc0 ta1, MIPS_COP_0_TLB_HI # restore PID 1286 j ra 1287 mtc0 ta0, MIPS_COP_0_STATUS # restore the status register 1288END(MIPSX(tlb_invalidate_addr)) 1289 1290/* 1291 * void mipsN_tlb_invalidate_asids(uint32_t asid_lo, uint32_t asid_hi) 1292 * 1293 * Invalidate TLB entries belonging to asids (asid_lo,asid_hi] 1294 * leaving entries for kernel space marked global intact. 1295 */ 1296LEAF(MIPSX(tlb_invalidate_asids)) 1297 mfc0 ta1, MIPS_COP_0_TLB_HI # save EntryHi 1298 mfc0 ta0, MIPS_COP_0_STATUS # save status register 1299 mtc0 zero, MIPS_COP_0_STATUS # disable interrupts 1300 1301 INT_L t2, _C_LABEL(mips_options) + MO_NUM_TLB_ENTRIES 1302 li t1, MIPS1_TLB_FIRST_RAND_ENTRY << MIPS1_TLB_INDEX_SHIFT 1303 li v0, MIPS_KSEG0_START # invalid address 1304 sll t2, MIPS1_TLB_INDEX_SHIFT 1305 1306 # do {} while (t1 < t2) 13071: 1308 mtc0 t1, MIPS_COP_0_TLB_INDEX # set index 1309 nop 1310 tlbr # obtain an entry 1311 mfc0 t0, MIPS_COP_0_TLB_LOW 1312 nop 1313 and t0, t0, MIPS1_PG_G # check to see it has G bit 1314 bnez t0, 2f 1315 nop 1316 1317 mfc0 t0, MIPS_COP_0_TLB_HI # get va and ASID 1318 nop 1319 and t0, MIPS1_TLB_PID # mask off ASID 1320 srl t0, MIPS1_TLB_PID_SHIFT 1321 sltu v1, t0, a0 # < asid_lo 1322 bnez v1, 2f # yes, next tlb entry 1323 nop 1324 sltu v1, t0, a1 # < asid_hi 1325 beqz v1, 2f # no, next tlb entry 1326 nop 1327 1328 mtc0 v0, MIPS_COP_0_TLB_HI # make entryHi invalid 1329 mtc0 zero, MIPS_COP_0_TLB_LOW # zero out entryLo 1330 nop 1331 tlbwi # invalidate the TLB entry 13322: 1333 addu t1, t1, 1 << MIPS1_TLB_INDEX_SHIFT # increment index 1334 bne t1, t2, 1b 1335 nop 1336 1337 mtc0 ta1, MIPS_COP_0_TLB_HI # restore entryHi 1338 1339 j ra # new TLBpid will be set soon 1340 mtc0 ta0, MIPS_COP_0_STATUS # restore status register 1341END(MIPSX(tlb_invalidate_asids)) 1342 1343/* 1344 * void mipsN_tlb_invalidate_all(void) 1345 * 1346 * Invalidate TLB entirely. 1347 */ 1348LEAF(MIPSX(tlb_invalidate_all)) 1349 INT_L a0, _C_LABEL(mips_options) + MO_NUM_TLB_ENTRIES 1350 1351 mfc0 ta0, MIPS_COP_0_STATUS # save the status register. 1352 mtc0 zero, MIPS_COP_0_STATUS # disable interrupts 1353 1354 mfc0 ta1, MIPS_COP_0_TLB_HI # save current PID 1355 li t0, MIPS_KSEG0_START # invalid address 1356 mtc0 t0, MIPS_COP_0_TLB_HI # make entryHi invalid 1357 mtc0 zero, MIPS_COP_0_TLB_LOW # zero out entryLo 1358 1359 move t0, zero 1360 sll a0, MIPS1_TLB_INDEX_SHIFT 1361 1362 # do {} while (t1 < a0) 13631: 1364 mtc0 t0, MIPS_COP_0_TLB_INDEX # set TLBindex 1365 addu t0, t0, 1 << MIPS1_TLB_INDEX_SHIFT # increment index 1366 bne t0, a0, 1b 1367 tlbwi # invalidate the entry 1368 1369 mtc0 ta1, MIPS_COP_0_TLB_HI # restore PID 1370 j ra 1371 mtc0 ta0, MIPS_COP_0_STATUS # restore status register 1372END(MIPSX(tlb_invalidate_all)) 1373 1374/* 1375 * u_int mipsN_tlb_record_asids(u_long *bitmap, uint32_t asid_max) 1376 * 1377 * Scan the random part of the TLB looking at non-global entries and 1378 * record each ASID in use into the bitmap. Additionally, return the 1379 * number of new unique ASIDs encountered. 1380 */ 1381LEAF(MIPSX(tlb_record_asids)) 1382 mfc0 ta1, MIPS_COP_0_TLB_HI # save EntryHi 1383 li v1, MIPS1_TLB_FIRST_RAND_ENTRY << MIPS1_TLB_INDEX_SHIFT 1384 INT_L a3, _C_LABEL(mips_options) + MO_NUM_TLB_ENTRIES 1385 move ta2, zero 1386 li ta3, 1 1387 sll a3, MIPS1_TLB_INDEX_SHIFT 1388 1389 mfc0 ta0, MIPS_COP_0_STATUS # save status register 1390 mtc0 zero, MIPS_COP_0_STATUS # disable interrupts 1391 1392 move v0, zero # start at zero ASIDs 1393 1394 # do {} while (v1 < ta1) 13951: 1396 mtc0 v1, MIPS_COP_0_TLB_INDEX # set index 1397 nop 1398 tlbr # obtain an entry 1399 mfc0 t0, MIPS_COP_0_TLB_LOW 1400 nop 1401 and t0, MIPS1_PG_G # check to see it has G bit 1402 bnez t0, 4f 1403 nop 1404 1405 mfc0 t0, MIPS_COP_0_TLB_HI # get va and ASID 1406 nop 1407 and t0, MIPS1_TLB_PID 1408 srl t0, MIPS1_TLB_PID_SHIFT # shift to low bits 1409 bgt t0, a1, 4f # > ASID max? skip 1410 nop 1411 1412 srl a2, t0, 3 + LONG_SCALESHIFT # drop low 5 bits 1413 sll a2, LONG_SCALESHIFT # make an index for the bitmap 1414 sllv t0, ta3, t0 # t0 is mask (ta3 == 1) 1415 1416 PTR_ADDU a2, a0 # index into the bitmap 1417 beq a2, ta2, 3f # is the desired cell loaded? 1418 nop # yes, don't reload it 1419 beqz ta2, 2f # have we ever loaded it? 1420 nop # nope, so don't save it 1421 1422 LONG_S t2, 0(ta2) # save the updated value. 14232: 1424 LONG_L t2, 0(a2) # and load it 1425 move ta2, a2 # remember the new cell's addr 14263: 1427 and t1, t2, t0 # see if this asid was recorded 1428 sltu t1, t1, ta3 # t1 = t1 < 1 (aka t1 == 0) 1429 addu v0, t1 # v0 += t1 1430 or t2, t0 # or in the new ASID bits 1431 14324: 1433 addu v1, 1 << MIPS1_TLB_INDEX_SHIFT # increment TLB entry # 1434 bne v1, a3, 1b # keep lookup if not limit 1435 nop 1436 1437 beqz ta2, 5f # do we have a cell to write? 1438 nop # nope, nothing. 1439 1440 LONG_S t2, 0(ta2) # save the updated value. 14415: 1442 mtc0 ta1, MIPS_COP_0_TLB_HI # restore entryHi 1443 1444 j ra # new TLBpid will be set soon 1445 mtc0 ta0, MIPS_COP_0_STATUS # restore status register 1446END(MIPSX(tlb_record_asids)) 1447 1448/*---------------------------------------------------------------------------- 1449 * 1450 * R3000 trampolines and context resume 1451 * 1452 *---------------------------------------------------------------------------- 1453 */ 1454 1455/*---------------------------------------------------------------------------- 1456 * 1457 * mipsN_lwp_trampoline 1458 * 1459 * Special arrangement for a process about to go user mode right after 1460 * fork() system call. When the first CPU tick is scheduled to run the 1461 * forked child, it starts running from here. Then, a service function 1462 * is called with one argument supplied to complete final preparations, 1463 * and the process returns to user mode as if the fork() system call is 1464 * handled in a normal way. No need to save any registers although this 1465 * calls another. 1466 *---------------------------------------------------------------------------- 1467 */ 1468LEAF(MIPSX(lwp_trampoline)) 1469 PTR_ADDU sp, -CALLFRAME_SIZ 1470 1471 # Call lwp_startup(), with args from cpu_switchto()/cpu_lwp_fork() 1472 move a0, v0 1473 jal _C_LABEL(lwp_startup) 1474 move a1, MIPS_CURLWP 1475 1476 # Call the routine specified by cpu_lwp_fork() 1477 jalr s0 1478 move a0, s1 1479 1480 # Return to user (won't happen if a kernel thread) 1481 .set noat 1482MIPSX(user_return): 1483 REG_L s0, CALLFRAME_SIZ+TF_REG_S0(sp) # $16 1484 REG_L s1, CALLFRAME_SIZ+TF_REG_S1(sp) # $17 1485 REG_L s2, CALLFRAME_SIZ+TF_REG_S2(sp) # $18 1486 REG_L s3, CALLFRAME_SIZ+TF_REG_S3(sp) # $19 1487 REG_L s4, CALLFRAME_SIZ+TF_REG_S4(sp) # $20 1488 REG_L s5, CALLFRAME_SIZ+TF_REG_S5(sp) # $21 1489 REG_L s6, CALLFRAME_SIZ+TF_REG_S6(sp) # $22 1490 REG_L s7, CALLFRAME_SIZ+TF_REG_S7(sp) # $23 1491 REG_L s8, CALLFRAME_SIZ+TF_REG_S8(sp) # $30 1492MIPSX(user_intr_return): 1493 REG_L a0, CALLFRAME_SIZ+TF_REG_SR(sp) 1494 REG_L t0, CALLFRAME_SIZ+TF_REG_MULLO(sp) 1495 REG_L t1, CALLFRAME_SIZ+TF_REG_MULHI(sp) 1496 mtc0 a0, MIPS_COP_0_STATUS # this should disable interrupts 1497 mtlo t0 1498 mthi t1 1499 move k1, sp 1500 REG_L AT, TF_BASE+TF_REG_AST(sp) 1501 REG_L k0, CALLFRAME_SIZ+TF_REG_EPC(k1) 1502 REG_L AT, CALLFRAME_SIZ+TF_REG_AST(k1) 1503 REG_L v0, CALLFRAME_SIZ+TF_REG_V0(k1) 1504 REG_L v1, CALLFRAME_SIZ+TF_REG_V1(k1) 1505 REG_L a0, CALLFRAME_SIZ+TF_REG_A0(k1) 1506 REG_L a1, CALLFRAME_SIZ+TF_REG_A1(k1) 1507 REG_L a2, CALLFRAME_SIZ+TF_REG_A2(k1) 1508 REG_L a3, CALLFRAME_SIZ+TF_REG_A3(k1) 1509 REG_L t0, CALLFRAME_SIZ+TF_REG_T0(k1) 1510 REG_L t1, CALLFRAME_SIZ+TF_REG_T1(k1) 1511 REG_L t2, CALLFRAME_SIZ+TF_REG_T2(k1) 1512 REG_L t3, CALLFRAME_SIZ+TF_REG_T3(k1) 1513 REG_L ta0, CALLFRAME_SIZ+TF_REG_TA0(k1) 1514 REG_L ta1, CALLFRAME_SIZ+TF_REG_TA1(k1) 1515 REG_L ta2, CALLFRAME_SIZ+TF_REG_TA2(k1) 1516 REG_L ta3, CALLFRAME_SIZ+TF_REG_TA3(k1) 1517 REG_L t8, CALLFRAME_SIZ+TF_REG_T8(k1) 1518 REG_L t9, CALLFRAME_SIZ+TF_REG_T9(k1) 1519 REG_L gp, CALLFRAME_SIZ+TF_REG_GP(k1) 1520 REG_L ra, CALLFRAME_SIZ+TF_REG_RA(k1) 1521 REG_L sp, CALLFRAME_SIZ+TF_REG_SP(k1) 1522 nop 1523 j k0 1524 rfe 1525 .set at 1526END(MIPSX(lwp_trampoline)) 1527 1528/* 1529 * void mipsN_cpu_switch_resume(struct lwp *newlwp) 1530 * 1531 * Wiredown the USPACE of newproc with TLB entry#0 and #1. Check 1532 * if target USPACE is already referred by any TLB entry before 1533 * doing that, and make sure TBIS(them) in the case. 1534 */ 1535LEAF_NOPROFILE(MIPSX(cpu_switch_resume)) 1536 INT_L a1, L_MD_UPTE_0(a0) # a1 = upte[0] 1537 INT_L a2, L_MD_UPTE_1(a0) # a2 = upte[1] 1538 PTR_L s0, L_PCB(a0) # va = l->l_addr 1539 li s2, VM_MIN_KERNEL_ADDRESS 1540 blt s0, s2, resume 1541 nop 1542 1543 mfc0 t3, MIPS_COP_0_TLB_HI # save PID 1544 nop 1545 mtc0 s0, MIPS_COP_0_TLB_HI # VPN = va 1546 nop 1547 tlbp # probe 1st VPN 1548 mfc0 s1, MIPS_COP_0_TLB_INDEX 1549 nop 1550 bltz s1, entry0set 1551 li s1, MIPS_KSEG0_START # found, then 1552 mtc0 s1, MIPS_COP_0_TLB_HI 1553 mtc0 zero, MIPS_COP_0_TLB_LOW 1554 nop 1555 tlbwi # TBIS(va) 1556 nop 1557 mtc0 s0, MIPS_COP_0_TLB_HI # set 1st VPN again 1558entry0set: 1559 mtc0 zero, MIPS_COP_0_TLB_INDEX # TLB index #0 1560 ori a1, a1, MIPS1_PG_G 1561 mtc0 a1, MIPS_COP_0_TLB_LOW # 1st PFN w/ PG_G 1562 nop 1563 tlbwi # set TLB entry #0 1564 1565 addu s0, s0, PAGE_SIZE 1566 mtc0 s0, MIPS_COP_0_TLB_HI # VPN = va+PAGE_SIZE 1567 nop 1568 tlbp # probe 2nd VPN 1569 mfc0 s1, MIPS_COP_0_TLB_INDEX 1570 nop 1571 bltz s1, entry1set 1572 li s1, MIPS_KSEG0_START # found, then 1573 mtc0 s1, MIPS_COP_0_TLB_HI 1574 mtc0 zero, MIPS_COP_0_TLB_LOW 1575 nop 1576 tlbwi # TBIS(va+PAGE_SIZE) 1577 nop 1578 mtc0 s0, MIPS_COP_0_TLB_HI # set 2nd VPN again 1579entry1set: 1580 li s1, 1 << MIPS1_TLB_INDEX_SHIFT 1581 mtc0 s1, MIPS_COP_0_TLB_INDEX # TLB index #1 1582 ori a2, a2, MIPS1_PG_G 1583 mtc0 a2, MIPS_COP_0_TLB_LOW # 2nd PFN w/ PG_G 1584 nop 1585 tlbwi # set TLB entry #1 1586 nop 1587 mfc0 t3, MIPS_COP_0_TLB_HI # restore PID 1588 1589resume: 1590 j ra 1591 nop 1592END(MIPSX(cpu_switch_resume)) 1593 1594/*---------------------------------------------------------------------------- 1595 * 1596 * R3000 cache sizing and flushing code. 1597 * 1598 *---------------------------------------------------------------------------- 1599 */ 1600#ifndef ENABLE_MIPS_TX3900 1601/* 1602 * void mipsN_wbflush(void) 1603 * 1604 * Drain processor's write buffer, normally used to ensure any I/O 1605 * register write operations are done before subsequent manipulations. 1606 * 1607 * Some hardware implementations have a WB chip independent from CPU 1608 * core, and CU0 (Coprocessor Usability #0) bit of CP0 status register 1609 * is wired to indicate writebuffer condition. This code does busy-loop 1610 * while CU0 bit indicates false condition. 1611 * 1612 * For other hardware which have the writebuffer logic is implemented 1613 * in a system controller ASIC chip, wbflush operation would done 1614 * differently. 1615 */ 1616LEAF(MIPSX(wbflush)) 1617 nop 1618 nop 1619 nop 1620 nop 16211: bc0f 1b 1622 nop 1623 j ra 1624 nop 1625END(MIPSX(wbflush)) 1626#else /* !ENABLE_MIPS_TX3900 */ 1627/* 1628 * The differences between R3900 and R3000. 1629 * 1. Cache system 1630 * Physical-index physical-tag 1631 * fixed line-size 1632 * refil-size 4/8/16/32 words (set in config register) 1633 * TX3912 1634 * Write-through 1635 * I-cache 4KB/16B direct mapped (256line) 1636 * D-cache 1KB/4B 2-way sa (128line) 1637 * Cache snoop 1638 * TX3922 1639 * Write-through/write-back (set in config register) 1640 * I-cache 16KB/16B 2-way sa 1641 * D-cache 8KB/16B 2-way sa 1642 * Cache snoop 1643 * 1644 * 2. Coprocessor1 1645 * 2.1 cache operation. 1646 * R3900 uses MIPSIII cache op like method. 1647 * 2.2 R3900 specific CP0 register. 1648 * (mips/include/r3900regs.h overrides cpuregs.h) 1649 * 2.3 # of TLB entries 1650 * TX3912 32 entries 1651 * TX3922 64 entries 1652 * 1653 * 3. System address map 1654 * kseg2 0xff000000-0xfffeffff is reserved. 1655 * (mips/include/vmparam.h) 1656 * 1657 * + If defined both MIPS1 and ENABLE_MIPS_TX3900, it generates kernel for 1658 * R3900. If defined MIPS1 only, No R3900 feature include. 1659 * + R3920 core has write-back mode. but it is always disabled in NetBSD. 1660 */ 1661 1662LEAF_NOPROFILE(tx3900_cp0_config_read) 1663 mfc0 v0, R3900_COP_0_CONFIG 1664 j ra 1665 nop 1666END(tx3900_cp0_config_read) 1667 1668LEAF(MIPSX(wbflush)) 1669 .set push 1670 .set mips2 1671 sync 1672 .set pop 1673 j ra 1674 nop 1675END(MIPSX(wbflush)) 1676#endif /* !ENABLE_MIPS_TX3900 */ 1677 1678 .rdata 1679 1680 .globl _C_LABEL(MIPSX(locore_vec)) 1681_C_LABEL(MIPSX(locore_vec)): 1682 PTR_WORD _C_LABEL(MIPSX(cpu_switch_resume)) 1683 PTR_WORD _C_LABEL(MIPSX(lwp_trampoline)) 1684 PTR_WORD _C_LABEL(MIPSX(wbflush)) # wbflush 1685 PTR_WORD _C_LABEL(MIPSX(tlb_get_asid)) 1686 PTR_WORD _C_LABEL(MIPSX(tlb_set_asid)) 1687 PTR_WORD _C_LABEL(MIPSX(tlb_invalidate_asids)) 1688 PTR_WORD _C_LABEL(MIPSX(tlb_invalidate_addr)) 1689 PTR_WORD _C_LABEL(nullop) # tlb_invalidate_globals 1690 PTR_WORD _C_LABEL(MIPSX(tlb_invalidate_all)) 1691 PTR_WORD _C_LABEL(MIPSX(tlb_record_asids)) 1692 PTR_WORD _C_LABEL(MIPSX(tlb_update_addr)) 1693 PTR_WORD _C_LABEL(MIPSX(tlb_read_entry)) 1694 PTR_WORD _C_LABEL(MIPSX(tlb_write_entry)) 1695 1696 .globl _C_LABEL(MIPSX(locoresw)) 1697_C_LABEL(MIPSX(locoresw)): 1698 PTR_WORD _C_LABEL(MIPSX(wbflush)) # lsw_wbflush 1699 PTR_WORD _C_LABEL(nullop) # lsw_cpu_idle 1700 PTR_WORD _C_LABEL(nullop) # lsw_send_ipi 1701 PTR_WORD _C_LABEL(nullop) # lsw_cpu_offline_md 1702 PTR_WORD _C_LABEL(nullop) # lsw_cpu_init 1703 PTR_WORD _C_LABEL(nullop) # lsw_cpu_run 1704 PTR_WORD _C_LABEL(nullop) # lsw_bus_error 1705 1706MIPSX(excpt_sw): 1707 #### 1708 #### The kernel exception handlers. 1709 #### 1710 PTR_WORD _C_LABEL(MIPSX(kern_intr)) # 0 external interrupt 1711 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 1 TLB modification 1712 PTR_WORD _C_LABEL(MIPSX(kern_tlb_miss)) # 2 TLB miss (LW/I-fetch) 1713 PTR_WORD _C_LABEL(MIPSX(kern_tlb_miss)) # 3 TLB miss (SW) 1714 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 4 address error (LW/I-fetch) 1715 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 5 address error (SW) 1716 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 6 bus error (I-fetch) 1717 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 7 bus error (load or store) 1718 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 8 system call 1719 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 9 breakpoint 1720 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 10 reserved instruction 1721 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 11 coprocessor unusable 1722 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 12 arithmetic overflow 1723 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 13 r3k reserved 1724 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 14 r3k reserved 1725 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 15 r3k reserved 1726 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 16 never happens w/ MIPS1 1727 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 17 never happens w/ MIPS1 1728 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 18 never happens w/ MIPS1 1729 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 19 never happens w/ MIPS1 1730 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 20 never happens w/ MIPS1 1731 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 21 never happens w/ MIPS1 1732 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 22 never happens w/ MIPS1 1733 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 23 never happens w/ MIPS1 1734 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 24 never happens w/ MIPS1 1735 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 25 never happens w/ MIPS1 1736 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 26 never happens w/ MIPS1 1737 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 27 never happens w/ MIPS1 1738 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 28 never happens w/ MIPS1 1739 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 29 never happens w/ MIPS1 1740 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 30 never happens w/ MIPS1 1741 PTR_WORD _C_LABEL(MIPSX(kern_gen_exception))# 31 never happens w/ MIPS1 1742 ##### 1743 ##### The user exception handlers. 1744 ##### 1745 PTR_WORD _C_LABEL(MIPSX(user_intr)) # 0 1746 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 1 1747 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 2 1748 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 3 1749 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 4 1750 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 5 1751 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 6 1752 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 7 1753 PTR_WORD _C_LABEL(MIPSX(systemcall)) # 8 1754 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 9 1755 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 10 1756 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 11 1757 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 12 1758 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 13 1759 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 14 1760 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 15 1761 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 16 1762 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 17 1763 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 18 1764 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 19 1765 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 20 1766 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 21 1767 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 22 1768 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 23 1769 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 24 1770 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 25 1771 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 26 1772 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 27 1773 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 28 1774 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 29 1775 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 20 1776 PTR_WORD _C_LABEL(MIPSX(user_gen_exception))# 31 1777