Annotation of sys/arch/mips64/mips64/tlbhandler.S, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: tlbhandler.S,v 1.16 2007/05/25 20:58:39 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1995-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this list of conditions and the following disclaimer.
! 11: * 2. Redistributions in binary form must reproduce the above copyright
! 12: * notice, this list of conditions and the following disclaimer in the
! 13: * documentation and/or other materials provided with the distribution.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
! 16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
! 19: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 25: * SUCH DAMAGE.
! 26: *
! 27: */
! 28:
! 29: /*
! 30: * This code handles TLB exceptions and updates.
! 31: */
! 32:
! 33: #include <machine/param.h>
! 34: #include <machine/psl.h>
! 35: #include <machine/pte.h>
! 36: #include <machine/asm.h>
! 37: #include <machine/cpu.h>
! 38: #include <machine/regnum.h>
! 39: #include <machine/cpustate.h>
! 40:
! 41: #define HAIRY_R5000_ERRATA
! 42:
! 43: #include "assym.h"
! 44:
! 45: .set mips3
! 46:
! 47: .set noreorder /* Default reorder mode */
! 48:
! 49: /*---------------------------------------------------------------- tlb_miss
! 50: * Low level TLB exception handler. TLB and XTLB share some
! 51: * code for the moment and is copied down at the same time.
! 52: * This code must be PIC and not more than 64 instructions
! 53: * for both TLB and XTLB handling or it will overflow the
! 54: * available storage. If the startup code finds out that it
! 55: * is larger, the trampoline code is copied instead of panicing.
! 56: */
! 57: /***************************** Start of code copied to exception vector */
! 58: .globl tlb_miss /* 0xffffffff80000000 */
! 59: .set noat
! 60: .ent tlb_miss, 0
! 61: tlb_miss:
! 62: #ifdef HAIRY_R5000_ERRATA
! 63: /*
! 64: * R5000 errata: edge cases can trigger a TLB miss exception
! 65: * instead of an invalid TLB exception. Servicing the TLB miss
! 66: * exception would cause a duplicate TLB to be inserted, which
! 67: * causes the processor operation to become unpredictable (but
! 68: * very bad for the kernel's health, ten times out of nine).
! 69: *
! 70: * More details about the problem can be found in:
! 71: * http://www.linux-mips.org/archives/linux-mips/2000-02/msg00040.html
! 72: *
! 73: * We work around the issue by checking for an existing TLB entry,
! 74: * and handling this as an invalid TLB exception (as it was intended
! 75: * to be), in this case.
! 76: */
! 77: tlbp
! 78: mfc0 k1, COP_0_TLB_INDEX
! 79: bltz k1, 1f # missing!
! 80: nop
! 81: j k_tlb_inv
! 82: nop
! 83: 1:
! 84: #endif
! 85: PTR_L k1, curprocpaddr
! 86: dmfc0 k0, COP_0_BAD_VADDR
! 87: bltz k0, _k_miss # kernel address space
! 88: PTR_SRL k0, k0, SEGSHIFT - LOGREGSZ
! 89: PTR_L k1, PCB_SEGTAB(k1)
! 90: andi k0, k0, (PMAP_SEGTABSIZE - 1) << LOGREGSZ
! 91: PTR_ADDU k1, k1, k0
! 92: PTR_L k1, 0(k1) # get pointer to page table
! 93: dmfc0 k0, COP_0_BAD_VADDR
! 94: PTR_SRL k0, k0, PGSHIFT - 2
! 95: andi k0, k0, ((NPTEPG/2) - 1) << 3
! 96: beqz k1, _inv_seg # invalid segment map
! 97: PTR_ADDU k1, k1, k0 # index into segment map
! 98: lw k0, 0(k1) # get page PTE
! 99: tlb_load:
! 100: lw k1, 4(k1)
! 101: dsll k0, k0, 34
! 102: dsrl k0, k0, 34
! 103: dmtc0 k0, COP_0_TLB_LO0
! 104: dsll k1, k1, 34
! 105: dsrl k1, k1, 34
! 106: dmtc0 k1, COP_0_TLB_LO1
! 107: nop # RM7000 needs 4 nops
! 108: nop
! 109: nop
! 110: nop
! 111: tlbwr # update TLB
! 112: nop
! 113: nop
! 114: nop
! 115: nop
! 116: eret # RM7000 need 4 for JTLB usage.
! 117: .end tlb_miss
! 118:
! 119: .globl e_tlb_miss
! 120: e_tlb_miss:
! 121:
! 122: /*---------------------------------------------------------------- xtlb_miss
! 123: * Low level XTLB exception handler.
! 124: */
! 125: .globl xtlb_miss /* 0xffffffff80000080 */
! 126: .set noat
! 127: .ent xtlb_miss, 0
! 128: xtlb_miss:
! 129: #ifdef HAIRY_R5000_ERRATA
! 130: /* See errata comments in tlb_miss above */
! 131: tlbp
! 132: mfc0 k1, COP_0_TLB_INDEX
! 133: bltz k1, 1f # missing!
! 134: nop
! 135: j k_tlb_inv
! 136: nop
! 137: 1:
! 138: #endif
! 139: dmfc0 k0, COP_0_BAD_VADDR
! 140: bltz k0, _k_miss # kernel address space
! 141: PTR_SRL k0, k0, SEGSHIFT
! 142: sltiu k1, k0, PMAP_SEGTABSIZE
! 143: beqz k1, _inv_seg # wrong if outside pm_segtab
! 144: PTR_SLL k0, k0, LOGREGSZ
! 145: PTR_L k1, curprocpaddr
! 146: PTR_L k1, PCB_SEGTAB(k1)
! 147: PTR_ADDU k1, k1, k0
! 148: PTR_L k1, 0(k1) # get pointer to page table
! 149: dmfc0 k0, COP_0_BAD_VADDR
! 150: PTR_SRL k0, k0, PGSHIFT - 2
! 151: andi k0, k0, ((NPTEPG/2) - 1) << 3
! 152: beqz k1, _inv_seg
! 153: PTR_ADDU k1, k1, k0
! 154: b tlb_load # rest is same as 'tlb_miss'
! 155: lw k0, 0(k1)
! 156:
! 157: _inv_seg:
! 158: j tlb_miss_nopt # No page table for this segment.
! 159: nop
! 160:
! 161: _k_miss:
! 162: j k_tlb_miss # kernel tlbmiss.
! 163: dmfc0 k0, COP_0_BAD_VADDR # must reload.
! 164: .end xtlb_miss
! 165:
! 166: .globl e_xtlb_miss
! 167: e_xtlb_miss:
! 168: .set at
! 169: /***************************** End of code copied to exception vector */
! 170:
! 171: .globl tlb_miss_nopt
! 172: .ent tlb_miss_nopt, 0
! 173: tlb_miss_nopt:
! 174: .set noat
! 175: mfc0 k0, COP_0_STATUS_REG
! 176: andi k0, SR_KSU_USER
! 177: bne k0, zero, go_u_general
! 178: nop
! 179: j k_general
! 180: nop
! 181: .end tlb_miss_nopt
! 182: .set at
! 183:
! 184: /*
! 185: * Trampolines copied to exception vectors when code is too big.
! 186: */
! 187: .globl tlb_miss_tramp
! 188: .ent tlb_miss_tramp, 0
! 189: tlb_miss_tramp:
! 190: .set noat
! 191: LA k0, tlb_miss
! 192: jr k0
! 193: nop
! 194: .end tlb_miss_tramp
! 195: .set at
! 196: .globl e_tlb_miss_tramp
! 197: e_tlb_miss_tramp:
! 198:
! 199: .globl xtlb_miss_tramp
! 200: .ent xtlb_miss_tramp, 0
! 201: xtlb_miss_tramp:
! 202: .set noat
! 203: LA k0, xtlb_miss
! 204: jr k0
! 205: nop
! 206: .end xtlb_miss_tramp
! 207: .set at
! 208: .globl e_xtlb_miss_tramp
! 209: e_xtlb_miss_tramp:
! 210:
! 211:
! 212: /*---------------------------------------------------------------- k_tlb_inv
! 213: * Handle a TLB invalid exception from kernel mode in kernel
! 214: * space. This happens when we have a TLB match but an invalid
! 215: * entry. Try to reload.
! 216: */
! 217: NLEAF(k_tlb_inv, 0)
! 218: .set noat
! 219: LA k1, (VM_MIN_KERNEL_ADDRESS) # compute index
! 220: dmfc0 k0, COP_0_BAD_VADDR # get the fault address
! 221: PTR_SUBU k0, k0, k1
! 222: lw k1, Sysmapsize # index within range?
! 223: PTR_SRL k0, k0, PGSHIFT
! 224: sltu k1, k0, k1
! 225: beq k1, zero, sys_stk_chk # No. check for valid stack
! 226: nop
! 227:
! 228: PTR_L k1, Sysmap
! 229: PTR_SLL k0, k0, 2 # compute offset from index
! 230: tlbp # Probe the invalid entry
! 231: PTR_ADDU k1, k1, k0
! 232: and k0, k0, 4 # check even/odd page
! 233: bne k0, zero, k_tlb_inv_odd
! 234: nop
! 235:
! 236: mfc0 k0, COP_0_TLB_INDEX
! 237: blez k0, sys_stk_chk # probe fail or index 0!
! 238: lw k0, 0(k1) # get PTE entry
! 239:
! 240: dsll k0, k0, 34 # get rid of "wired" bit
! 241: dsrl k0, k0, 34
! 242: dmtc0 k0, COP_0_TLB_LO0 # load PTE entry
! 243: and k0, k0, PG_V # check for valid entry
! 244: beq k0, zero, go_k_general # PTE invalid
! 245: lw k0, 4(k1) # get odd PTE entry
! 246: dsll k0, k0, 34
! 247: dsrl k0, k0, 34
! 248: dmtc0 k0, COP_0_TLB_LO1 # load PTE entry
! 249: nop
! 250: nop
! 251: nop
! 252: nop
! 253: tlbwi # write TLB
! 254: nop
! 255: nop
! 256: nop
! 257: nop
! 258: eret
! 259:
! 260: k_tlb_inv_odd:
! 261: mfc0 k0, COP_0_TLB_INDEX
! 262: blez k0, sys_stk_chk # probe fail or index 0!
! 263: lw k0, 0(k1) # get PTE entry
! 264:
! 265: dsll k0, k0, 34 # get rid of wired bit
! 266: dsrl k0, k0, 34
! 267: dmtc0 k0, COP_0_TLB_LO1 # save PTE entry
! 268: and k0, k0, PG_V # check for valid entry
! 269: beq k0, zero, go_k_general # PTE invalid
! 270: lw k0, -4(k1) # get even PTE entry
! 271: dsll k0, k0, 34
! 272: dsrl k0, k0, 34
! 273: dmtc0 k0, COP_0_TLB_LO0 # save PTE entry
! 274: nop
! 275: nop
! 276: nop
! 277: nop
! 278: tlbwi # update TLB
! 279: nop
! 280: nop
! 281: nop
! 282: nop
! 283: eret
! 284: END(k_tlb_inv)
! 285:
! 286: /*---------------------------------------------------------------- k_tlb_miss
! 287: *
! 288: * Handle a TLB miss exception from kernel mode in kernel space.
! 289: * We must check that this is coming from kernel mode. If not
! 290: * it's a bad address from user mode so handle properly.
! 291: * Load up the correct entry contents from the kernel map.
! 292: * k0 has bad address.
! 293: */
! 294: NLEAF(k_tlb_miss, 0)
! 295: .set noat
! 296: mfc0 k1, COP_0_STATUS_REG
! 297: andi k1, SR_KSU_USER
! 298: bne k1, zero, go_u_general
! 299: LA k1, (VM_MIN_KERNEL_ADDRESS) # compute index
! 300: PTR_SUBU k0, k0, k1
! 301: lw k1, Sysmapsize # index within range?
! 302: PTR_SRL k0, k0, PGSHIFT
! 303: sltu k1, k0, k1
! 304: beq k1, zero, sys_stk_chk # No. check for valid stack
! 305: PTR_SRL k0, k0, 1
! 306: PTR_L k1, Sysmap
! 307: PTR_SLL k0, k0, 3 # compute offset from index
! 308: PTR_ADDU k1, k1, k0
! 309: lw k0, 0(k1) # get PTE entry
! 310: lw k1, 4(k1) # get odd PTE entry
! 311: dsll k0, k0, 34 # get rid of "wired" bit
! 312: dsrl k0, k0, 34
! 313: dmtc0 k0, COP_0_TLB_LO0 # load PTE entry
! 314: dsll k1, k1, 34
! 315: dsrl k1, k1, 34
! 316: dmtc0 k1, COP_0_TLB_LO1 # load PTE entry
! 317: nop
! 318: nop
! 319: nop
! 320: nop
! 321: tlbwr # write TLB
! 322: nop
! 323: nop
! 324: nop
! 325: nop
! 326: eret
! 327:
! 328: sys_stk_chk:
! 329: PTR_L k1, curprocpaddr
! 330: PTR_SUBU k0, sp, k1 # check to see if we have a
! 331: sltiu k0, 2048 # valid kernel stack
! 332: beqz k0, go_k_general # yes, handle.
! 333: nop
! 334:
! 335: LA a0, start-FRAMESZ(CF_SZ)-4*REGSZ # set sp to a valid place
! 336: #ifdef __mips_n64
! 337: mfc0 a4, COP_0_STATUS_REG
! 338: mfc0 a5, COP_0_CAUSE_REG
! 339: move a6, sp
! 340: #else
! 341: mfc0 a2, COP_0_STATUS_REG
! 342: mfc0 a3, COP_0_CAUSE_REG
! 343: REG_S a2, CF_ARGSZ+0*REGSZ(sp)
! 344: REG_S a3, CF_ARGSZ+1*REGSZ(sp)
! 345: PTR_S sp, CF_ARGSZ+2*REGSZ(a0)
! 346: #endif
! 347: move sp, a0
! 348: dmfc0 a1, COP_0_EXC_PC
! 349: move a2, ra
! 350: LA a0, 1f
! 351: jal printf
! 352: dmfc0 a3, COP_0_BAD_VADDR
! 353:
! 354: LA sp, start-FRAMESZ(CF_SZ) # set sp to a valid place
! 355:
! 356: #ifdef DDB
! 357: LA a0, 2f
! 358: jal trapDump
! 359: nop
! 360: #endif
! 361:
! 362: PANIC("kernel stack overflow")
! 363: /*noreturn*/
! 364:
! 365: go_k_general:
! 366: j k_general
! 367: nop
! 368:
! 369: go_u_general:
! 370: j u_general
! 371: nop
! 372:
! 373:
! 374: .data
! 375: 1:
! 376: .asciiz "\rktlbmiss: PC %p RA %p ADR %p\nSR %p CR %p SP %p\n"
! 377: 2:
! 378: .asciiz "stack ovf"
! 379: .text
! 380:
! 381: .set at
! 382: END(k_tlb_miss)
! 383:
! 384: /*---------------------------------------------------------------- tlb_write_i
! 385: * Write the given entry into the TLB at the given index.
! 386: */
! 387: LEAF(tlb_write_indexed, 0)
! 388: mfc0 v1, COP_0_STATUS_REG # Save the status register.
! 389: ori v0, v1, SR_INT_ENAB
! 390: xori v0, v0, SR_INT_ENAB
! 391: mtc0 v0, COP_0_STATUS_REG # Disable interrupts
! 392: ITLBNOPFIX
! 393: ld a2, 16(a1)
! 394: ld a3, 24(a1)
! 395: dmfc0 ta0, COP_0_TLB_HI # Save the current PID.
! 396:
! 397: dmtc0 a2, COP_0_TLB_LO0 # Set up entry low0.
! 398: dmtc0 a3, COP_0_TLB_LO1 # Set up entry low1.
! 399: ld a2, 0(a1)
! 400: ld a3, 8(a1)
! 401: mtc0 a0, COP_0_TLB_INDEX # Set the index.
! 402: dmtc0 a2, COP_0_TLB_PG_MASK # Set up entry mask.
! 403: dmtc0 a3, COP_0_TLB_HI # Set up entry high.
! 404: nop
! 405: nop
! 406: nop
! 407: nop
! 408: tlbwi # Write the TLB
! 409: nop
! 410: nop # Delay for effect
! 411: nop
! 412: nop
! 413:
! 414: dmtc0 ta0, COP_0_TLB_HI # Restore the PID.
! 415: nop
! 416: dmtc0 zero, COP_0_TLB_PG_MASK # Default mask value.
! 417: mtc0 v1, COP_0_STATUS_REG # Restore the status register
! 418: ITLBNOPFIX
! 419: j ra
! 420: nop
! 421: END(tlb_write_indexed)
! 422:
! 423: /*---------------------------------------------------------------- tlb_flush
! 424: * Flush the "random" entries from the TLB.
! 425: * Uses "wired" register to determine what register to start with.
! 426: * Arg "tlbsize" is the number of entries to flush.
! 427: */
! 428: LEAF(tlb_flush, 0)
! 429: mfc0 v1, COP_0_STATUS_REG # Save the status register.
! 430: ori v0, v1, SR_INT_ENAB
! 431: xori v0, v0, SR_INT_ENAB
! 432: mtc0 v0, COP_0_STATUS_REG # Disable interrupts
! 433: ITLBNOPFIX
! 434: mfc0 ta1, COP_0_TLB_WIRED
! 435: LA v0, KSEG0_BASE # invalid address
! 436: dmfc0 ta0, COP_0_TLB_HI # Save the PID
! 437:
! 438: dmtc0 v0, COP_0_TLB_HI # Mark entry high as invalid
! 439: dmtc0 zero, COP_0_TLB_LO0 # Zero out low entry0.
! 440: dmtc0 zero, COP_0_TLB_LO1 # Zero out low entry1.
! 441: mtc0 zero, COP_0_TLB_PG_MASK # Zero out mask entry.
! 442: /*
! 443: * Align the starting value (ta1) and the upper bound (a0).
! 444: */
! 445: 1:
! 446: mtc0 ta1, COP_0_TLB_INDEX # Set the index register.
! 447: addu ta1, ta1, 1 # Increment index.
! 448: nop
! 449: nop
! 450: nop
! 451: tlbwi # Write the TLB entry.
! 452: nop
! 453: nop
! 454: bne ta1, a0, 1b
! 455: nop
! 456:
! 457: dmtc0 ta0, COP_0_TLB_HI # Restore the PID
! 458: mtc0 v1, COP_0_STATUS_REG # Restore the status register
! 459: ITLBNOPFIX
! 460: j ra
! 461: nop
! 462: END(tlb_flush)
! 463:
! 464: /*--------------------------------------------------------------- tlb_flush_addr
! 465: * Flush any TLB entries for the given address and TLB PID.
! 466: */
! 467: LEAF(tlb_flush_addr, 0)
! 468: mfc0 v1, COP_0_STATUS_REG # Save the status register.
! 469: ori v0, v1, SR_INT_ENAB
! 470: xori v0, v0, SR_INT_ENAB
! 471: mtc0 v0, COP_0_STATUS_REG # Disable interrupts
! 472: ITLBNOPFIX
! 473: li v0, (PG_HVPN | PG_ASID)
! 474: and a0, a0, v0 # Make sure valid hi value.
! 475: dmfc0 ta0, COP_0_TLB_HI # Get current PID
! 476: dmtc0 a0, COP_0_TLB_HI # look for addr & PID
! 477: nop
! 478: nop
! 479: nop
! 480: nop
! 481: tlbp # Probe for the entry.
! 482: nop
! 483: nop # Delay for effect
! 484: nop
! 485: LA ta1, KSEG0_BASE # Load invalid entry.
! 486: mfc0 v0, COP_0_TLB_INDEX # See what we got
! 487: bltz v0, 1f # index < 0 => !found
! 488: nop
! 489: dmtc0 ta1, COP_0_TLB_HI # Mark entry high as invalid
! 490:
! 491: dmtc0 zero, COP_0_TLB_LO0 # Zero out low entry.
! 492: dmtc0 zero, COP_0_TLB_LO1 # Zero out low entry.
! 493: nop
! 494: nop
! 495: nop
! 496: nop
! 497: tlbwi
! 498: nop
! 499: nop
! 500: nop
! 501: nop
! 502: 1:
! 503: dmtc0 ta0, COP_0_TLB_HI # restore PID
! 504: mtc0 v1, COP_0_STATUS_REG # Restore the status register
! 505: ITLBNOPFIX
! 506: j ra
! 507: nop
! 508: END(tlb_flush_addr)
! 509:
! 510: /*---------------------------------------------------------------- tlb_update
! 511: * Update the TLB if highreg is found; otherwise, enter the data.
! 512: */
! 513: LEAF(tlb_update, 0)
! 514: mfc0 v1, COP_0_STATUS_REG # Save the status register.
! 515: ori v0, v1, SR_INT_ENAB
! 516: xori v0, v0, SR_INT_ENAB
! 517: mtc0 v0, COP_0_STATUS_REG # Disable interrupts
! 518: ITLBNOPFIX
! 519: and ta1, a0, 0x1000 # ta1 = Even/Odd flag
! 520: li v0, (PG_HVPN | PG_ASID)
! 521: and a0, a0, v0
! 522: dmfc0 ta0, COP_0_TLB_HI # Save current PID
! 523: dmtc0 a0, COP_0_TLB_HI # Init high reg
! 524: and a2, a1, PG_G # Copy global bit
! 525: nop
! 526: nop
! 527: nop
! 528: tlbp # Probe for the entry.
! 529: dsll a1, a1, 34
! 530: dsrl a1, a1, 34
! 531: bne ta1, zero, 2f # Decide even odd
! 532: mfc0 v0, COP_0_TLB_INDEX # See what we got
! 533: # EVEN
! 534: bltz v0, 1f # index < 0 => !found
! 535: nop
! 536:
! 537: tlbr # update, read entry first
! 538: nop
! 539: nop
! 540: nop
! 541: dmtc0 a1, COP_0_TLB_LO0 # init low reg0.
! 542: nop
! 543: nop
! 544: nop
! 545: nop
! 546: tlbwi # update slot found
! 547: b 4f
! 548: li v0, 1
! 549: 1:
! 550: mtc0 zero, COP_0_TLB_PG_MASK # init mask.
! 551: dmtc0 a0, COP_0_TLB_HI # init high reg.
! 552: dmtc0 a1, COP_0_TLB_LO0 # init low reg0.
! 553: dmtc0 a2, COP_0_TLB_LO1 # init low reg1.
! 554: nop
! 555: nop
! 556: nop
! 557: nop
! 558: tlbwr # enter into a random slot
! 559: b 4f
! 560: li v0, 0
! 561: # ODD
! 562: 2:
! 563: nop
! 564: bltz v0, 3f # index < 0 => !found
! 565: nop
! 566:
! 567: tlbr # read the entry first
! 568: nop
! 569: nop
! 570: nop
! 571: dmtc0 a1, COP_0_TLB_LO1 # init low reg1.
! 572: nop
! 573: nop
! 574: nop
! 575: nop
! 576: tlbwi # update slot found
! 577: b 4f
! 578: li v0, 1
! 579: 3:
! 580: mtc0 zero, COP_0_TLB_PG_MASK # init mask.
! 581: dmtc0 a0, COP_0_TLB_HI # init high reg.
! 582: dmtc0 a2, COP_0_TLB_LO0 # init low reg0.
! 583: dmtc0 a1, COP_0_TLB_LO1 # init low reg1.
! 584: nop
! 585: nop
! 586: nop
! 587: nop
! 588: tlbwr # enter into a random slot
! 589: nop
! 590: li v0, 0
! 591:
! 592: 4: # Make sure pipeline
! 593: nop # advances before we
! 594: nop # use the tlb.
! 595: dmtc0 ta0, COP_0_TLB_HI # restore PID
! 596: mtc0 v1, COP_0_STATUS_REG # Restore the status register
! 597: ITLBNOPFIX
! 598: j ra
! 599: nop
! 600: END(tlb_update)
! 601:
! 602: /*---------------------------------------------------------------- tlb_read
! 603: * Read the TLB entry.
! 604: */
! 605: LEAF(tlb_read, 0)
! 606: mfc0 v1, COP_0_STATUS_REG # Save the status register.
! 607: ori v0, v1, SR_INT_ENAB
! 608: xori v0, v0, SR_INT_ENAB
! 609: mtc0 v0, COP_0_STATUS_REG # Disable interrupts
! 610: ITLBNOPFIX
! 611: dmfc0 v0, COP_0_TLB_HI # Get current PID
! 612:
! 613: mtc0 a0, COP_0_TLB_INDEX # Set the index register
! 614: nop
! 615: nop
! 616: nop
! 617: nop
! 618: tlbr # Read from the TLB
! 619: nop
! 620: nop
! 621: nop
! 622: dmfc0 ta0, COP_0_TLB_PG_MASK # fetch the hi entry
! 623: dmfc0 ta1, COP_0_TLB_HI # fetch the hi entry
! 624: dmfc0 ta2, COP_0_TLB_LO0 # See what we got
! 625: dmfc0 ta3, COP_0_TLB_LO1 # See what we got
! 626: dmtc0 v0, COP_0_TLB_HI # restore PID
! 627: nop
! 628: nop
! 629: nop # wait for PID active
! 630: mtc0 v1, COP_0_STATUS_REG # Restore the status register
! 631: ITLBNOPFIX
! 632: sd ta0, 0(a1)
! 633: sd ta1, 8(a1)
! 634: sd ta2, 16(a1)
! 635: j ra
! 636: sd ta3, 24(a1)
! 637: END(tlb_read)
! 638:
! 639: /*---------------------------------------------------------------- tlb_get_pid
! 640: * Read the tlb pid value.
! 641: */
! 642: LEAF(tlb_get_pid, 0)
! 643: dmfc0 v0, COP_0_TLB_HI # get PID
! 644: li v1, VMTLB_PID # mask off PID
! 645: j ra
! 646: and v0, v0, v1 # mask off PID
! 647: END(tlb_get_pid)
! 648:
! 649: /*---------------------------------------------------------------- tlb_set_pid
! 650: * Write the given pid into the TLB pid reg.
! 651: */
! 652: LEAF(tlb_set_pid, 0)
! 653: dmtc0 a0, COP_0_TLB_HI # Write the hi reg value
! 654: j ra
! 655: nop
! 656: END(tlb_set_pid)
! 657:
! 658: /*---------------------------------------------------------------- tlb_get_wired
! 659: * Get the value from the TLB wired reg.
! 660: */
! 661: LEAF(tlb_get_wired, 0)
! 662: mfc0 v0, COP_0_TLB_WIRED
! 663: j ra
! 664: nop
! 665: END(tlb_get_wired)
! 666:
! 667: /*---------------------------------------------------------------- tlb_set_wired
! 668: * Write the given value into the TLB wired reg.
! 669: */
! 670: LEAF(tlb_set_wired, 0)
! 671: mtc0 a0, COP_0_TLB_WIRED
! 672: j ra
! 673: nop
! 674: END(tlb_set_wired)
CVSweb