1/* 2 * Copyright (c) 1992 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Digital Equipment Corporation and Ralph Campbell. 7 * 8 * %sccs.include.redist.c% 9 * 10 * Copyright (C) 1989 Digital Equipment Corporation. 11 * Permission to use, copy, modify, and distribute this software and 12 * its documentation for any purpose and without fee is hereby granted, 13 * provided that the above copyright notice appears in all copies. 14 * Digital Equipment Corporation makes no representations about the 15 * suitability of this software for any purpose. It is provided "as is" 16 * without express or implied warranty. 17 * 18 * from: $Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, 19 * v 1.1 89/07/11 17:55:04 nelson Exp $ SPRITE (DECWRL) 20 * from: $Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, 21 * v 9.2 90/01/29 18:00:39 shirriff Exp $ SPRITE (DECWRL) 22 * from: $Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, 23 * v 1.1 89/07/10 14:27:41 nelson Exp $ SPRITE (DECWRL) 24 * 25 * @(#)locore.s 7.2 (Berkeley) 01/07/92 26 */ 27 28/* 29 * Contains code that is the first executed at boot time plus 30 * assembly language support routines. 31 */ 32 33#include "errno.h" 34 35#include "machine/regdef.h" 36#include "machine/param.h" 37#include "machine/vmparam.h" 38#include "machine/psl.h" 39#include "machine/reg.h" 40#include "machine/machAsmDefs.h" 41#include "pte.h" 42#include "assym.h" 43 44/* 45 * Amount to take off of the stack for the benefit of the debugger. 46 */ 47#define START_FRAME ((4 * 4) + 4 + 4) 48 49 .globl start 50start: 51 .set noreorder 52 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 53 li t1, MACH_RESERVED_ADDR # invalid address 54 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid 55 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 56/* 57 * Clear the TLB (just to be safe). 58 * Align the starting value (t1), the increment (t2) and the upper bound (t3). 59 */ 60 move t1, zero 61 li t2, 1 << VMMACH_TLB_INDEX_SHIFT 62 li t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 631: 64 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register. 65 addu t1, t1, t2 # Increment index. 66 bne t1, t3, 1b # NB: always executes next 67 tlbwi # Write the TLB entry. 68 69 li sp, MACH_CODE_START - START_FRAME 70 la gp, _gp 71 sw zero, START_FRAME - 4(sp) # Zero out old ra for debugger 72 jal mach_init # mach_init(argc, argv, envp) 73 sw zero, START_FRAME - 8(sp) # Zero out old fp for debugger 74 75 li t0, MACH_SR_COP_1_BIT # Disable interrupts and 76 mtc0 t0, MACH_COP_0_STATUS_REG # enable the coprocessor 77 li sp, KERNELSTACK - START_FRAME # switch to standard stack 78 mfc0 t0, MACH_COP_0_PRID # read processor ID register 79 cfc1 t1, MACH_FPC_ID # read FPU ID register 80 sw t0, cpu # save PRID register 81 sw t1, fpu # save FPU ID register 82 jal main # main() 83 nop 84 85/* proc[1] == /etc/init now running here; run icode */ 86 li v0, PSL_USERSET 87 mtc0 v0, MACH_COP_0_STATUS_REG # switch to user mode 88 j zero # icode is at address zero 89 rfe 90 .set reorder 91 92/* 93 * This code is copied to user data space as the first program to run. 94 * Basically, it just calls execve(); 95 */ 96 .globl icode 97icode: 98 .set noreorder 99 li a1, (9 * 4) # address of 'icode_argv' 100 addu a0, a1, (3 * 4) # address of 'icode_fname' 101 move a2, zero # no environment 102 li v0, 59 # code for execve system call 103 syscall 104 li v0, 1 # code for exit system call 105 syscall # execve failed: call exit() 1061: b 1b # loop if exit returns 107 nop 108 .set reorder 109icode_argv: 110 .word (12 * 4) # address of 'icode_fname' 111 .word (15 * 4) # address of 'icodeEnd' 112 .word 0 113icode_fname: 114 .asciiz "/sbin/init" # occupies 3 words 115 .align 2 116 .globl icodeEnd 117icodeEnd: 118 119 .sdata 120 .align 2 121 .globl szicode 122szicode: 123 .word (9 + 3 + 3) * 4 # compute icodeEnd - icode 124 .text 125 126/* 127 * Primitives 128 */ 129 130/* 131 * This table is indexed by u.u_pcb.pcb_onfault in trap(). 132 * The reason for using this table rather than storing an address in 133 * u.u_pcb.pcb_onfault is simply to make the code faster. 134 */ 135 .globl onfault_table 136 .data 137 .align 2 138onfault_table: 139 .word 0 # invalid index number 140#define BADERR 1 141 .word baderr 142#define ADDUPCERR 2 143 .word addupcerr 144#define COPYERR 3 145 .word copyerr 146#define FSWBERR 4 147 .word fswberr 148 .text 149 150/* 151 * See if access to addr with a len type instruction causes a machine check. 152 * len is length of access (1=byte, 2=short, 4=long) 153 * 154 * badaddr(addr, len) 155 * char *addr; 156 * int len; 157 */ 158LEAF(badaddr) 159 li v0, BADERR 160 sw v0, UADDR+U_PCB_ONFAULT 161 bne a1, 1, 2f 162 lbu v0, (a0) 163 b 5f 1642: 165 bne a1, 2, 4f 166 lhu v0, (a0) 167 b 5f 1684: 169 lw v0, (a0) 1705: 171 sw zero, UADDR+U_PCB_ONFAULT 172 move v0, zero # made it w/o errors 173 j ra 174baderr: 175 li v0, 1 # trap sends us here 176 j ra 177END(badaddr) 178 179/* 180 * update profiling information for the user 181 * addupc(pc, pr, ticks) 182 * unsigned pc; 183 * struct uprof *pr; 184 * int ticks; 185 */ 186LEAF(addupc) 187 lw v1, 8(a1) # get pr->pr_off 188 subu a0, a0, v1 # pc -= pr->pr_off 189 blt a0, zero, 1f # ignore if less than zero 190 lw v0, 12(a1) # get pr->pr_scale 191 multu v0, a0 # compute index into count table 192 mflo v0 193 srl v0, v0, 16 # shift v1,v0 >> 16 194 mfhi v1 195 sll v1, v1, 16 196 or v0, v0, v1 197 addu v0, v0, 1 # round up and 198 and v0, v0, ~1 # align to short boundary 199 lw v1, 4(a1) # get pr->pr_size 200 bgeu v0, v1, 1f # ignore if index >= size 201 lw v1, 0(a1) # get pr->pr_base 202 addu v0, v0, v1 # add index and base 203 li v1, ADDUPCERR # turn off profiling if fault 204 bltz v0, addupcerr # can this happen? 205 sw v1, UADDR+U_PCB_ONFAULT 206 lh v1, 0(v0) # get old count 207 addu v1, v1, a2 # add ticks 208 sh v1, 0(v0) # save new count 209 sw zero, UADDR+U_PCB_ONFAULT 2101: 211 j ra 212addupcerr: 213 sw zero, 12(a1) # pr->pr_scale = 0 214 j ra 215END(addupc) 216 217/* 218 * netorder = htonl(hostorder) 219 * hostorder = ntohl(netorder) 220 */ 221LEAF(htonl) # a0 = 0x11223344, return 0x44332211 222ALEAF(ntohl) 223 srl v1, a0, 24 # v1 = 0x00000011 224 sll v0, a0, 24 # v0 = 0x44000000 225 or v0, v0, v1 226 and v1, a0, 0xff00 227 sll v1, v1, 8 # v1 = 0x00330000 228 or v0, v0, v1 229 srl v1, a0, 8 230 and v1, v1, 0xff00 # v1 = 0x00002200 231 or v0, v0, v1 232 j ra 233END(htonl) 234 235/* 236 * netorder = htons(hostorder) 237 * hostorder = ntohs(netorder) 238 */ 239LEAF(htons) 240ALEAF(ntohs) 241 srl v0, a0, 8 242 and v0, v0, 0xff 243 sll v1, a0, 8 244 and v1, v1, 0xff00 245 or v0, v0, v1 246 j ra 247END(htons) 248 249/* 250 * bit = ffs(value) 251 */ 252LEAF(ffs) 253 move v0, zero 254 beq a0, zero, 2f 2551: 256 and v1, a0, 1 # bit set? 257 addu v0, v0, 1 258 srl a0, a0, 1 259 beq v1, zero, 1b # no, continue 2602: 261 j ra 262END(ffs) 263 264/* 265 * strlen(str) 266 */ 267LEAF(strlen) 268 addu v1, a0, 1 2691: 270 lb v0, 0(a0) # get byte from string 271 addu a0, a0, 1 # increment pointer 272 bne v0, zero, 1b # continue if not end 273 subu v0, a0, v1 # compute length - 1 for '\0' char 274 j ra 275END(strlen) 276 277/* 278 * bzero(s1, n) 279 */ 280LEAF(bzero) 281ALEAF(blkclr) 282 .set noreorder 283 blt a1, 12, smallclr # small amount to clear? 284 subu a3, zero, a0 # compute # bytes to word align address 285 and a3, a3, 3 286 beq a3, zero, 1f # skip if word aligned 287 subu a1, a1, a3 # subtract from remaining count 288 swr zero, 0(a0) # clear 1, 2, or 3 bytes to align 289 addu a0, a0, a3 2901: 291 and v0, a1, 3 # compute number of words left 292 subu a3, a1, v0 293 move a1, v0 294 addu a3, a3, a0 # compute ending address 2952: 296 addu a0, a0, 4 # clear words 297 bne a0, a3, 2b # unrolling loop doesn't help 298 sw zero, -4(a0) # since we're limited by memory speed 299smallclr: 300 ble a1, zero, 2f 301 addu a3, a1, a0 # compute ending address 3021: 303 addu a0, a0, 1 # clear bytes 304 bne a0, a3, 1b 305 sb zero, -1(a0) 3062: 307 j ra 308 nop 309 .set reorder 310END(bzero) 311 312/* 313 * bcmp(s1, s2, n) 314 */ 315LEAF(bcmp) 316 .set noreorder 317 blt a2, 16, smallcmp # is it worth any trouble? 318 xor v0, a0, a1 # compare low two bits of addresses 319 and v0, v0, 3 320 subu a3, zero, a1 # compute # bytes to word align address 321 bne v0, zero, unalignedcmp # not possible to align addresses 322 and a3, a3, 3 323 324 beq a3, zero, 1f 325 subu a2, a2, a3 # subtract from remaining count 326 move v0, v1 # init v0,v1 so unmodified bytes match 327 lwr v0, 0(a0) # read 1, 2, or 3 bytes 328 lwr v1, 0(a1) 329 addu a1, a1, a3 330 bne v0, v1, nomatch 331 addu a0, a0, a3 3321: 333 and a3, a2, ~3 # compute number of whole words left 334 subu a2, a2, a3 # which has to be >= (16-3) & ~3 335 addu a3, a3, a0 # compute ending address 3362: 337 lw v0, 0(a0) # compare words 338 lw v1, 0(a1) 339 addu a0, a0, 4 340 bne v0, v1, nomatch 341 addu a1, a1, 4 342 bne a0, a3, 2b 343 nop 344 b smallcmp # finish remainder 345 nop 346unalignedcmp: 347 beq a3, zero, 2f 348 subu a2, a2, a3 # subtract from remaining count 349 addu a3, a3, a0 # compute ending address 3501: 351 lbu v0, 0(a0) # compare bytes until a1 word aligned 352 lbu v1, 0(a1) 353 addu a0, a0, 1 354 bne v0, v1, nomatch 355 addu a1, a1, 1 356 bne a0, a3, 1b 357 nop 3582: 359 and a3, a2, ~3 # compute number of whole words left 360 subu a2, a2, a3 # which has to be >= (16-3) & ~3 361 addu a3, a3, a0 # compute ending address 3623: 363 lwr v0, 0(a0) # compare words a0 unaligned, a1 aligned 364 lwl v0, 3(a0) 365 lw v1, 0(a1) 366 addu a0, a0, 4 367 bne v0, v1, nomatch 368 addu a1, a1, 4 369 bne a0, a3, 3b 370 nop 371smallcmp: 372 ble a2, zero, match 373 addu a3, a2, a0 # compute ending address 3741: 375 lbu v0, 0(a0) 376 lbu v1, 0(a1) 377 addu a0, a0, 1 378 bne v0, v1, nomatch 379 addu a1, a1, 1 380 bne a0, a3, 1b 381 nop 382match: 383 j ra 384 move v0, zero 385nomatch: 386 j ra 387 li v0, 1 388 .set reorder 389END(bcmp) 390 391/* 392 * {ov}bcopy(from, to, len) 393 */ 394LEAF(bcopy) 395ALEAF(ovbcopy) 396 .set noreorder 397 addu t0, a0, a2 # t0 = end of s1 region 398 sltu t1, a1, t0 399 sltu t2, a0, a1 400 and t1, t1, t2 # t1 = true if from < to < (from+len) 401 beq t1, zero, forward # non overlapping, do forward copy 402 slt t2, a2, 12 # check for small copy 403 404 ble a2, zero, 2f 405 addu t1, a1, a2 # t1 = end of to region 4061: 407 lb v0, -1(t0) # copy bytes backwards, 408 subu t0, t0, 1 # doesn't happen often so do slow way 409 subu t1, t1, 1 410 bne t0, a0, 1b 411 sb v0, 0(t1) 4122: 413 j ra 414 nop 415forward: 416 bne t2, zero, smallcpy # do a small bcopy 417 xor v0, a0, a1 # compare low two bits of addresses 418 and v0, v0, 3 419 subu a3, zero, a1 # compute # bytes to word align address 420 beq v0, zero, aligned # addresses can be word aligned 421 and a3, a3, 3 422 423 beq a3, zero, 1f 424 subu a2, a2, a3 # subtract from remaining count 425 lwr v0, 0(a0) # get next 4 bytes (unaligned) 426 lwl v0, 3(a0) 427 addu a0, a0, a3 428 swr v0, 0(a1) # store 1, 2, or 3 bytes to align a1 429 addu a1, a1, a3 4301: 431 and v0, a2, 3 # compute number of words left 432 subu a3, a2, v0 433 move a2, v0 434 addu a3, a3, a0 # compute ending address 4352: 436 lwr v0, 0(a0) # copy words a0 unaligned, a1 aligned 437 lwl v0, 3(a0) 438 addu a0, a0, 4 439 addu a1, a1, 4 440 bne a0, a3, 2b 441 sw v0, -4(a1) 442 b smallcpy 443 nop 444aligned: 445 beq a3, zero, 1f 446 subu a2, a2, a3 # subtract from remaining count 447 lwr v0, 0(a0) # copy 1, 2, or 3 bytes to align 448 addu a0, a0, a3 449 swr v0, 0(a1) 450 addu a1, a1, a3 4511: 452 and v0, a2, 3 # compute number of whole words left 453 subu a3, a2, v0 454 move a2, v0 455 addu a3, a3, a0 # compute ending address 4562: 457 lw v0, 0(a0) # copy words 458 addu a0, a0, 4 459 addu a1, a1, 4 460 bne a0, a3, 2b 461 sw v0, -4(a1) 462smallcpy: 463 ble a2, zero, 2f 464 addu a3, a2, a0 # compute ending address 4651: 466 lbu v0, 0(a0) # copy bytes 467 addu a0, a0, 1 468 addu a1, a1, 1 469 bne a0, a3, 1b 470 sb v0, -1(a1) 4712: 472 sw zero, UADDR+U_PCB_ONFAULT # for copyin, copyout 473 j ra 474 move v0, zero 475 .set reorder 476END(bcopy) 477 478/* 479 * Copy a null terminated string within the kernel address space. 480 * Maxlength may be null if count not wanted. 481 * copystr(fromaddr, toaddr, maxlength, &lencopied) 482 * caddr_t fromaddr; 483 * caddr_t toaddr; 484 * u_int maxlength; 485 * u_int *lencopied; 486 */ 487LEAF(copystr) 488 move t2, a2 # Save the number of bytes 4891: 490 lb t0, 0(a0) 491 sb t0, 0(a1) 492 sub a2, a2, 1 493 beq t0, zero, 2f 494 add a0, a0, 1 495 add a1, a1, 1 496 bne a2, zero, 1b 4972: 498 beq a3, zero, 3f 499 sub a2, t2, a2 # compute length copied 500 sw a2, 0(a3) 5013: 502 sw zero, UADDR+U_PCB_ONFAULT # for copyinstr, copyoutstr 503 move v0, zero 504 j ra 505END(copystr) 506 507/* 508 * Copy a null terminated string from the user address space into 509 * the kernel address space. 510 * 511 * copyinstr(fromaddr, toaddr, maxlength, &lencopied) 512 * caddr_t fromaddr; 513 * caddr_t toaddr; 514 * u_int maxlength; 515 * u_int *lencopied; 516 */ 517LEAF(copyinstr) 518 li v0, COPYERR 519 blt a0, zero, copyerr # make sure address is in user space 520 sw v0, UADDR+U_PCB_ONFAULT 521 b copystr 522END(copyinstr) 523 524/* 525 * Copy a null terminated string from the kernel address space into 526 * the user address space. 527 * 528 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied) 529 * caddr_t fromaddr; 530 * caddr_t toaddr; 531 * u_int maxlength; 532 * u_int *lencopied; 533 */ 534LEAF(copyoutstr) 535 li v0, COPYERR 536 blt a1, zero, copyerr # make sure address is in user space 537 sw v0, UADDR+U_PCB_ONFAULT 538 b copystr 539END(copyoutstr) 540 541/* 542 * Copy specified amount of data from user space into the kernel 543 * copyin(from, to, len) 544 * caddr_t *from; (user source address) 545 * caddr_t *to; (kernel destination address) 546 * unsigned len; 547 */ 548LEAF(copyin) 549 li v0, COPYERR 550 blt a0, zero, copyerr # make sure address is in user space 551 sw v0, UADDR+U_PCB_ONFAULT 552 b bcopy 553END(copyin) 554 555/* 556 * Copy specified amount of data from kernel to the user space 557 * copyout(from, to, len) 558 * caddr_t *from; (kernel source address) 559 * caddr_t *to; (user destination address) 560 * unsigned len; 561 */ 562LEAF(copyout) 563 li v0, COPYERR 564 blt a1, zero, copyerr # make sure address is in user space 565 sw v0, UADDR+U_PCB_ONFAULT 566 b bcopy 567END(copyout) 568 569LEAF(copyerr) 570 li v0, EFAULT # return error 571 j ra 572END(copyerr) 573 574/* 575 * Copy data to the DMA buffer. 576 * The DMA bufffer can only be written one short at a time 577 * (and takes ~14 cycles). 578 * 579 * CopyToBuffer(src, dst, length) 580 * u_short *src; NOTE: must be short aligned 581 * u_short *dst; 582 * int length; 583 */ 584LEAF(CopyToBuffer) 585 blez a2, 2f 5861: 587 lhu t0, 0(a0) # read 2 bytes of data 588 subu a2, a2, 2 589 addu a0, a0, 2 590 addu a1, a1, 4 591 sh t0, -4(a1) # write 2 bytes of data to buffer 592 bgtz a2, 1b 5932: 594 j ra 595END(CopyToBuffer) 596 597/* 598 * Copy data from the DMA buffer. 599 * The DMA bufffer can only be read one short at a time 600 * (and takes ~12 cycles). 601 * 602 * CopyFromBuffer(src, dst, length) 603 * u_short *src; 604 * char *dst; 605 * int length; 606 */ 607LEAF(CopyFromBuffer) 608 and t0, a1, 1 # test for aligned dst 609 beq t0, zero, 3f 610 blt a2, 2, 7f # at least 2 bytes to copy? 6111: 612 lhu t0, 0(a0) # read 2 bytes of data from buffer 613 addu a0, a0, 4 # keep buffer pointer word aligned 614 addu a1, a1, 2 615 subu a2, a2, 2 616 sb t0, -2(a1) 617 srl t0, t0, 8 618 sb t0, -1(a1) 619 bge a2, 2, 1b 6203: 621 blt a2, 2, 7f # at least 2 bytes to copy? 6226: 623 lhu t0, 0(a0) # read 2 bytes of data from buffer 624 addu a0, a0, 4 # keep buffer pointer word aligned 625 addu a1, a1, 2 626 subu a2, a2, 2 627 sh t0, -2(a1) 628 bge a2, 2, 6b 6297: 630 ble a2, zero, 9f # done? 631 lhu t0, 0(a0) # copy one more byte 632 sb t0, 0(a1) 6339: 634 j ra 635END(CopyFromBuffer) 636 637/* 638 * Copy the kernel stack to the new process and save the current context so 639 * the new process will return nonzero when it is resumed by swtch(). 640 * 641 * copykstack(up) 642 * struct user *up; 643 */ 644LEAF(copykstack) 645 subu v0, sp, UADDR # compute offset into stack 646 addu v0, v0, a0 # v0 = new stack address 647 move v1, sp # v1 = old stack address 648 li t1, KERNELSTACK 6491: 650 lw t0, 0(v1) # copy stack data 651 addu v1, v1, 4 652 sw t0, 0(v0) 653 addu v0, v0, 4 654 bne v1, t1, 1b 655 /* FALLTHROUGH */ 656/* 657 * Save registers and state so we can do a longjmp later. 658 * Note: this only works if p != curproc since 659 * swtch() will copy over pcb_context. 660 * 661 * savectx(up) 662 * struct user *up; 663 */ 664ALEAF(savectx) 665 .set noreorder 666 sw s0, U_PCB_CONTEXT+0(a0) 667 sw s1, U_PCB_CONTEXT+4(a0) 668 sw s2, U_PCB_CONTEXT+8(a0) 669 sw s3, U_PCB_CONTEXT+12(a0) 670 mfc0 v0, MACH_COP_0_STATUS_REG 671 sw s4, U_PCB_CONTEXT+16(a0) 672 sw s5, U_PCB_CONTEXT+20(a0) 673 sw s6, U_PCB_CONTEXT+24(a0) 674 sw s7, U_PCB_CONTEXT+28(a0) 675 sw sp, U_PCB_CONTEXT+32(a0) 676 sw s8, U_PCB_CONTEXT+36(a0) 677 sw ra, U_PCB_CONTEXT+40(a0) 678 sw v0, U_PCB_CONTEXT+44(a0) 679 j ra 680 move v0, zero 681 .set reorder 682END(copykstack) 683 684/* 685 * _whichqs tells which of the 32 queues _qs 686 * have processes in them. Setrq puts processes into queues, Remrq 687 * removes them from queues. The running process is on no queue, 688 * other processes are on a queue related to p->p_pri, divided by 4 689 * actually to shrink the 0-127 range of priorities into the 32 available 690 * queues. 691 */ 692 693/* 694 * setrq(p) 695 * proc *p; 696 * 697 * Call should be made at splclock(), and p->p_stat should be SRUN. 698 */ 699NON_LEAF(setrq, STAND_FRAME_SIZE, ra) 700 subu sp, sp, STAND_FRAME_SIZE 701 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 702 lw t0, P_RLINK(a0) ## firewall: p->p_rlink must be 0 703 beq t0, zero, 1f ## 704 sw ra, STAND_RA_OFFSET(sp) ## 705 PANIC("setrq") ## 7061: 707 lbu t0, P_PRI(a0) # put on queue which is p->p_pri / 4 708 srl t0, t0, 2 # compute index into 'whichqs' 709 li t1, 1 # compute corresponding bit 710 sll t1, t1, t0 711 lw t2, whichqs # set corresponding bit 712 or t2, t2, t1 713 sw t2, whichqs 714 sll t0, t0, 3 # compute index into 'qs' 715 la t1, qs 716 addu t0, t0, t1 # t0 = qp = &qs[pri >> 2] 717 lw t1, P_RLINK(t0) # t1 = qp->ph_rlink 718 sw t0, P_LINK(a0) # p->p_link = qp 719 sw t1, P_RLINK(a0) # p->p_rlink = qp->ph_rlink 720 sw a0, P_LINK(t1) # p->p_rlink->p_link = p; 721 sw a0, P_RLINK(t0) # qp->ph_rlink = p 722 addu sp, sp, STAND_FRAME_SIZE 723 j ra 724END(setrq) 725 726/* 727 * Remrq(p) 728 * 729 * Call should be made at splclock(). 730 */ 731NON_LEAF(remrq, STAND_FRAME_SIZE, ra) 732 subu sp, sp, STAND_FRAME_SIZE 733 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 734 lbu t0, P_PRI(a0) # get from queue which is p->p_pri / 4 735 srl t0, t0, 2 # compute index into 'whichqs' 736 li t1, 1 # compute corresponding bit 737 sll t1, t1, t0 738 lw t2, whichqs # check corresponding bit 739 and v0, t2, t1 740 bne v0, zero, 1f ## 741 sw ra, STAND_RA_OFFSET(sp) ## 742 PANIC("remrq") ## it wasn't recorded to be on its q 7431: 744 lw v0, P_RLINK(a0) # v0 = p->p_rlink 745 lw v1, P_LINK(a0) # v1 = p->p_link 746 sw v1, P_LINK(v0) # p->p_rlink->p_link = p->p_link; 747 sw v0, P_RLINK(v1) # p->p_link->p_rlink = p->r_rlink 748 sll t0, t0, 3 # compute index into 'qs' 749 la v0, qs 750 addu t0, t0, v0 # t0 = qp = &qs[pri >> 2] 751 lw v0, P_LINK(t0) # check if queue empty 752 bne v0, t0, 2f # No. qp->ph_link != qp 753 xor t2, t2, t1 # clear corresponding bit in 'whichqs' 754 sw t2, whichqs 7552: 756 sw zero, P_RLINK(a0) ## for firewall checking 757 addu sp, sp, STAND_FRAME_SIZE 758 j ra 759END(remrq) 760 761/* 762 * swtch_exit() 763 * 764 * At exit of a process, do a swtch for the last time. 765 * The mapping of the pcb at p->p_addr has already been deleted, 766 * and the memory for the pcb+stack has been freed. 767 * All interrupts should be blocked at this point. 768 */ 769LEAF(swtch_exit) 770 .set noreorder 771 la v0, nullproc # save state into garbage proc 772 lw t0, P_UPTE+0(v0) # t0 = first u. pte 773 lw t1, P_UPTE+4(v0) # t1 = 2nd u. pte 774 li v0, UADDR # v0 = first HI entry 775 mtc0 zero, MACH_COP_0_TLB_INDEX # set the index register 776 mtc0 v0, MACH_COP_0_TLB_HI # init high entry 777 mtc0 t0, MACH_COP_0_TLB_LOW # init low entry 778 li t0, 1 << VMMACH_TLB_INDEX_SHIFT 779 tlbwi # Write the TLB entry. 780 addu v0, v0, NBPG # 2nd HI entry 781 mtc0 t0, MACH_COP_0_TLB_INDEX # set the index register 782 mtc0 v0, MACH_COP_0_TLB_HI # init high entry 783 mtc0 t1, MACH_COP_0_TLB_LOW # init low entry 784 nop 785 tlbwi # Write the TLB entry. 786 .set reorder 787 li sp, KERNELSTACK - START_FRAME # switch to standard stack 788 b swtch 789END(swtch_exit) 790 791/* 792 * When no processes are on the runq, swtch branches to idle 793 * to wait for something to come ready. 794 * Note: this is really a part of swtch() but defined here for kernel profiling. 795 */ 796LEAF(idle) 797 .set noreorder 798 li t0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 799 mtc0 t0, MACH_COP_0_STATUS_REG # enable all interrupts 800 nop 801 .set reorder 8021: 803 lw t0, whichqs # look for non-empty queue 804 beq t0, zero, 1b 805 b sw1 806END(idle) 807 808/* 809 * swtch() 810 * Find the highest priority process and resume it. 811 */ 812NON_LEAF(swtch, STAND_FRAME_SIZE, ra) 813 .set noreorder 814 sw sp, UADDR+U_PCB_CONTEXT+32 # save old sp 815 subu sp, sp, STAND_FRAME_SIZE 816 sw ra, STAND_RA_OFFSET(sp) 817 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 818 lw t2, cnt+V_SWTCH # for statistics 819 lw t1, whichqs # look for non-empty queue 820 mfc0 t0, MACH_COP_0_STATUS_REG # t0 = saved status register 821 sw ra, UADDR+U_PCB_CONTEXT+40 # save return address 822 sw t0, UADDR+U_PCB_CONTEXT+44 # save status register 823 addu t2, t2, 1 824 beq t1, zero, idle # if none, idle 825 sw t2, cnt+V_SWTCH 826sw1: 827 mtc0 zero, MACH_COP_0_STATUS_REG # Disable all interrupts 828 nop 829 lw t0, whichqs # look for non-empty queue 830 li t2, -1 # t2 = lowest bit set 831 beq t0, zero, idle # if none, idle 832 move t3, t0 # t3 = saved whichqs 8331: 834 add t2, t2, 1 835 and t1, t0, 1 # bit set? 836 beq t1, zero, 1b 837 srl t0, t0, 1 # try next bit 838/* 839 * Remove process from queue. 840 */ 841 sll t0, t2, 3 842 la t1, qs 843 addu t0, t0, t1 # t0 = qp = &qs[highbit] 844 lw a0, P_LINK(t0) # a0 = p = highest pri process 845 nop 846 lw v0, P_LINK(a0) # v0 = p->p_link 847 bne t0, a0, 2f # make sure something in queue 848 sw v0, P_LINK(t0) # qp->ph_link = p->p_link; 849 PANIC("swtch") # nothing in queue 8502: 851 sw t0, P_RLINK(v0) # p->p_link->p_rlink = qp 852 bne v0, t0, 3f # queue still not empty 853 sw zero, P_RLINK(a0) ## for firewall checking 854 li v1, 1 # compute bit in 'whichqs' 855 sll v1, v1, t2 856 xor t3, t3, v1 # clear bit in 'whichqs' 857 sw t3, whichqs 8583: 859/* 860 * Save old context and switch to new one. 861 */ 862 sw a0, curproc # set curproc 863 sw zero, want_resched 864 jal pmap_alloc_tlbpid # v0 = TLB PID 865 sw a0, STAND_FRAME_SIZE(sp) # save p 866 lw a0, STAND_FRAME_SIZE(sp) # restore p 867 sll v0, v0, VMMACH_TLB_PID_SHIFT # v0 = aligned PID 868 or v0, v0, UADDR # v0 = first HI entry 869 lw t0, P_UPTE+0(a0) # t0 = first u. pte 870 lw t1, P_UPTE+4(a0) # t1 = 2nd u. pte 871 sw s0, UADDR+U_PCB_CONTEXT+0 # do a 'savectx()' 872 sw s1, UADDR+U_PCB_CONTEXT+4 # We save s0 to s8 here because 873 sw s2, UADDR+U_PCB_CONTEXT+8 # the TLB trap code uses 874 sw s3, UADDR+U_PCB_CONTEXT+12 # CONTEXT and there should be 875 sw s4, UADDR+U_PCB_CONTEXT+16 # no faults at this point. 876 sw s5, UADDR+U_PCB_CONTEXT+20 877 sw s6, UADDR+U_PCB_CONTEXT+24 878 sw s7, UADDR+U_PCB_CONTEXT+28 879 sw s8, UADDR+U_PCB_CONTEXT+36 880/* 881 * Resume process indicated by the pte's for its u struct 882 * NOTE: This is hard coded to UPAGES == 2. 883 * Also, there should be no TLB faults at this point. 884 */ 885 mtc0 zero, MACH_COP_0_TLB_INDEX # set the index register 886 mtc0 v0, MACH_COP_0_TLB_HI # init high entry 887 mtc0 t0, MACH_COP_0_TLB_LOW # init low entry 888 li t0, 1 << VMMACH_TLB_INDEX_SHIFT 889 tlbwi # Write the TLB entry. 890 addu v0, v0, NBPG # 2nd HI entry 891 mtc0 t0, MACH_COP_0_TLB_INDEX # set the index register 892 mtc0 v0, MACH_COP_0_TLB_HI # init high entry 893 mtc0 t1, MACH_COP_0_TLB_LOW # init low entry 894 nop 895 tlbwi # Write the TLB entry. 896/* 897 * Now running on new u struct. 898 * Restore registers and return. 899 */ 900 lw v0, UADDR+U_PCB_CONTEXT+44 # restore kernel context 901 lw ra, UADDR+U_PCB_CONTEXT+40 902 lw s0, UADDR+U_PCB_CONTEXT+0 903 lw s1, UADDR+U_PCB_CONTEXT+4 904 lw s2, UADDR+U_PCB_CONTEXT+8 905 lw s3, UADDR+U_PCB_CONTEXT+12 906 lw s4, UADDR+U_PCB_CONTEXT+16 907 lw s5, UADDR+U_PCB_CONTEXT+20 908 lw s6, UADDR+U_PCB_CONTEXT+24 909 lw s7, UADDR+U_PCB_CONTEXT+28 910 lw sp, UADDR+U_PCB_CONTEXT+32 911 lw s8, UADDR+U_PCB_CONTEXT+36 912 mtc0 v0, MACH_COP_0_STATUS_REG 913 j ra 914 li v0, 1 # possible return to 'savectx()' 915 .set reorder 916END(swtch) 917 918/* 919 * {fu,su},{ibyte,iword}, fetch or store a byte or word to user text space. 920 * {fu,su},{byte,word}, fetch or store a byte or word to user data space. 921 */ 922LEAF(fuword) 923ALEAF(fuiword) 924 li v0, FSWBERR 925 blt a0, zero, fswberr # make sure address is in user space 926 sw v0, UADDR+U_PCB_ONFAULT 927 lw v0, 0(a0) # fetch word 928 sw zero, UADDR+U_PCB_ONFAULT 929 j ra 930END(fuword) 931 932LEAF(fubyte) 933ALEAF(fuibyte) 934 li v0, FSWBERR 935 blt a0, zero, fswberr # make sure address is in user space 936 sw v0, UADDR+U_PCB_ONFAULT 937 lbu v0, 0(a0) # fetch byte 938 sw zero, UADDR+U_PCB_ONFAULT 939 j ra 940END(fubyte) 941 942LEAF(suword) 943ALEAF(suiword) 944 li v0, FSWBERR 945 blt a0, zero, fswberr # make sure address is in user space 946 sw v0, UADDR+U_PCB_ONFAULT 947 sw a1, 0(a0) # store word 948 sw zero, UADDR+U_PCB_ONFAULT 949 move v0, zero 950 j ra 951END(suword) 952 953LEAF(subyte) 954ALEAF(suibyte) 955 li v0, FSWBERR 956 blt a0, zero, fswberr # make sure address is in user space 957 sw v0, UADDR+U_PCB_ONFAULT 958 sb a1, 0(a0) # store byte 959 sw zero, UADDR+U_PCB_ONFAULT 960 move v0, zero 961 j ra 962END(subyte) 963 964LEAF(fswberr) 965 li v0, -1 966 j ra 967END(fswberr) 968 969/* 970 * Insert 'p' after 'q'. 971 * _insque(p, q) 972 * caddr_t p, q; 973 */ 974LEAF(_insque) 975 lw v0, 0(a1) # v0 = q->next 976 sw a1, 4(a0) # p->prev = q 977 sw v0, 0(a0) # p->next = q->next 978 sw a0, 4(v0) # q->next->prev = p 979 sw a0, 0(a1) # q->next = p 980 j ra 981END(_insque) 982 983/* 984 * Remove item 'p' from queue. 985 * _remque(p) 986 * caddr_t p; 987 */ 988LEAF(_remque) 989 lw v0, 0(a0) # v0 = p->next 990 lw v1, 4(a0) # v1 = p->prev 991 sw v0, 0(v1) # p->prev->next = p->next 992 sw v1, 4(v0) # p->next->prev = p->prev 993 j ra 994END(_remque) 995 996/* 997 * This code is copied to the UTLB exception vector address to 998 * handle user level TLB translation misses. 999 * NOTE: This code must be relocatable!!! 1000 */ 1001 .globl MachUTLBMiss 1002MachUTLBMiss: 1003 .set noat 1004 .set noreorder 1005 mfc0 k0, MACH_COP_0_BAD_VADDR # get the virtual address 1006 nop 1007 srl k0, k0, PMAP_HASH_SHIFT1 # get page in low bits 1008 srl k1, k0, PMAP_HASH_SHIFT2 - PMAP_HASH_SHIFT1 1009 and k0, k0, PMAP_HASH_MASK1 1010 and k1, k1, PMAP_HASH_MASK2 1011 or k1, k1, k0 1012 sll k1, k1, PMAP_HASH_SIZE_SHIFT # compute index 1013 lw k0, PMAP_HASH_LOW_OFFSET(k1) # get cached low PTE entry 1014 lw k1, PMAP_HASH_HIGH_OFFSET(k1) # get cached high PTE entry 1015 mtc0 k0, MACH_COP_0_TLB_LOW 1016 mfc0 k0, MACH_COP_0_TLB_HI # get actual high PTE entry 1017 nop 1018 bne k0, k1, 1f # non-matching PTE 1019 mfc0 k0, MACH_COP_0_EXC_PC # get return address 1020 tlbwr # update TLB 1021 j k0 1022 rfe 10231: 1024 j SlowFault # handle cache miss 1025 nop 1026 .set reorder 1027 .set at 1028 .globl MachUTLBMissEnd 1029MachUTLBMissEnd: 1030 1031/* 1032 * This code is copied to the general exception vector address to 1033 * handle all execptions except RESET and UTLBMiss. 1034 * NOTE: This code must be relocatable!!! 1035 */ 1036 .globl MachException 1037MachException: 1038/* 1039 * Find out what mode we came from and jump to the proper handler. 1040 */ 1041 .set noat 1042 .set noreorder 1043 mfc0 k0, MACH_COP_0_STATUS_REG # Get the status register 1044 mfc0 k1, MACH_COP_0_CAUSE_REG # Get the cause register value. 1045 and k0, k0, MACH_SR_KU_PREV # test for user mode 1046 beq k0, zero, 1f # handle kernel exception 1047 and k1, k1, MACH_CR_EXC_CODE # Mask out the cause bits. 1048 addu k1, k1, 0x40 # change index to user table 10491: 1050 la k0, machExceptionTable # get base of the jump table 1051 add k0, k0, k1 # Get the address of the 1052 # function entry. Note that 1053 # the cause is already 1054 # shifted left by 2 bits so 1055 # we don't have to shift. 1056 lw k0, 0(k0) # Get the function address 1057 nop 1058 j k0 # Jump to the function. 1059 nop 1060 .set reorder 1061 .set at 1062 .globl MachExceptionEnd 1063MachExceptionEnd: 1064 1065/* 1066 * We couldn't find a TLB entry. 1067 * Find out what mode we came from and call the appropriate handler. 1068 */ 1069SlowFault: 1070 .set noat 1071 .set noreorder 1072 mfc0 k0, MACH_COP_0_STATUS_REG 1073 nop 1074 and k0, k0, MACH_SR_KU_PREV 1075 bne k0, zero, MachUserGenException 1076 nop 1077 .set reorder 1078 .set at 1079/* 1080 * Fall though ... 1081 */ 1082 1083/*---------------------------------------------------------------------------- 1084 * 1085 * MachKernGenException -- 1086 * 1087 * Handle an exception from kernel mode. 1088 * 1089 * Results: 1090 * None. 1091 * 1092 * Side effects: 1093 * None. 1094 * 1095 *---------------------------------------------------------------------------- 1096 */ 1097 1098/* 1099 * The kernel exception stack contains 18 saved general registers, 1100 * the status register and the multiply lo and high registers. 1101 * In addition, we set this up for linkage conventions. 1102 */ 1103#define KERN_REG_SIZE (18 * 4) 1104#define KERN_REG_OFFSET (STAND_FRAME_SIZE) 1105#define KERN_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) 1106#define KERN_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) 1107#define KERN_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) 1108#define KERN_EXC_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) 1109 1110NON_LEAF(MachKernGenException, KERN_EXC_FRAME_SIZE, ra) 1111 .set noreorder 1112 .set noat 1113 subu sp, sp, KERN_EXC_FRAME_SIZE 1114 .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE) 1115/* 1116 * Save the relevant kernel registers onto the stack. 1117 * We don't need to save s0 - s8, sp and gp because 1118 * the compiler does it for us. 1119 */ 1120 sw AT, KERN_REG_OFFSET + 0(sp) 1121 sw v0, KERN_REG_OFFSET + 4(sp) 1122 sw v1, KERN_REG_OFFSET + 8(sp) 1123 sw a0, KERN_REG_OFFSET + 12(sp) 1124 mflo v0 1125 mfhi v1 1126 sw a1, KERN_REG_OFFSET + 16(sp) 1127 sw a2, KERN_REG_OFFSET + 20(sp) 1128 sw a3, KERN_REG_OFFSET + 24(sp) 1129 sw t0, KERN_REG_OFFSET + 28(sp) 1130 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1131 sw t1, KERN_REG_OFFSET + 32(sp) 1132 sw t2, KERN_REG_OFFSET + 36(sp) 1133 sw t3, KERN_REG_OFFSET + 40(sp) 1134 sw t4, KERN_REG_OFFSET + 44(sp) 1135 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1136 sw t5, KERN_REG_OFFSET + 48(sp) 1137 sw t6, KERN_REG_OFFSET + 52(sp) 1138 sw t7, KERN_REG_OFFSET + 56(sp) 1139 sw t8, KERN_REG_OFFSET + 60(sp) 1140 mfc0 a2, MACH_COP_0_BAD_VADDR # Third arg is the fault addr. 1141 sw t9, KERN_REG_OFFSET + 64(sp) 1142 sw ra, KERN_REG_OFFSET + 68(sp) 1143 sw v0, KERN_MULT_LO_OFFSET(sp) 1144 sw v1, KERN_MULT_HI_OFFSET(sp) 1145 mfc0 a3, MACH_COP_0_EXC_PC # Fourth arg is the pc. 1146 sw a0, KERN_SR_OFFSET(sp) 1147/* 1148 * Call the exception handler. 1149 */ 1150 jal trap 1151 sw a3, STAND_RA_OFFSET(sp) # for debugging 1152/* 1153 * Restore registers and return from the exception. 1154 * v0 contains the return address. 1155 */ 1156 lw a0, KERN_SR_OFFSET(sp) 1157 lw t0, KERN_MULT_LO_OFFSET(sp) 1158 lw t1, KERN_MULT_HI_OFFSET(sp) 1159 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1160 mtlo t0 1161 mthi t1 1162 move k0, v0 1163 lw AT, KERN_REG_OFFSET + 0(sp) 1164 lw v0, KERN_REG_OFFSET + 4(sp) 1165 lw v1, KERN_REG_OFFSET + 8(sp) 1166 lw a0, KERN_REG_OFFSET + 12(sp) 1167 lw a1, KERN_REG_OFFSET + 16(sp) 1168 lw a2, KERN_REG_OFFSET + 20(sp) 1169 lw a3, KERN_REG_OFFSET + 24(sp) 1170 lw t0, KERN_REG_OFFSET + 28(sp) 1171 lw t1, KERN_REG_OFFSET + 32(sp) 1172 lw t2, KERN_REG_OFFSET + 36(sp) 1173 lw t3, KERN_REG_OFFSET + 40(sp) 1174 lw t4, KERN_REG_OFFSET + 44(sp) 1175 lw t5, KERN_REG_OFFSET + 48(sp) 1176 lw t6, KERN_REG_OFFSET + 52(sp) 1177 lw t7, KERN_REG_OFFSET + 56(sp) 1178 lw t8, KERN_REG_OFFSET + 60(sp) 1179 lw t9, KERN_REG_OFFSET + 64(sp) 1180 lw ra, KERN_REG_OFFSET + 68(sp) 1181 addu sp, sp, KERN_EXC_FRAME_SIZE 1182 j k0 # Now return from the 1183 rfe # exception. 1184 .set at 1185 .set reorder 1186END(MachKernGenException) 1187 1188/*---------------------------------------------------------------------------- 1189 * 1190 * MachUserGenException -- 1191 * 1192 * Handle an exception from user mode. 1193 * 1194 * Results: 1195 * None. 1196 * 1197 * Side effects: 1198 * None. 1199 * 1200 *---------------------------------------------------------------------------- 1201 */ 1202NON_LEAF(MachUserGenException, STAND_FRAME_SIZE, ra) 1203 .set noreorder 1204 .set noat 1205 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 1206/* 1207 * Save all of the registers except for the kernel temporaries in u.u_pcb. 1208 */ 1209 sw AT, UADDR+U_PCB_REGS+(AST * 4) 1210 sw v0, UADDR+U_PCB_REGS+(V0 * 4) 1211 sw v1, UADDR+U_PCB_REGS+(V1 * 4) 1212 sw a0, UADDR+U_PCB_REGS+(A0 * 4) 1213 mflo v0 1214 sw a1, UADDR+U_PCB_REGS+(A1 * 4) 1215 sw a2, UADDR+U_PCB_REGS+(A2 * 4) 1216 sw a3, UADDR+U_PCB_REGS+(A3 * 4) 1217 sw t0, UADDR+U_PCB_REGS+(T0 * 4) 1218 mfhi v1 1219 sw t1, UADDR+U_PCB_REGS+(T1 * 4) 1220 sw t2, UADDR+U_PCB_REGS+(T2 * 4) 1221 sw t3, UADDR+U_PCB_REGS+(T3 * 4) 1222 sw t4, UADDR+U_PCB_REGS+(T4 * 4) 1223 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1224 sw t5, UADDR+U_PCB_REGS+(T5 * 4) 1225 sw t6, UADDR+U_PCB_REGS+(T6 * 4) 1226 sw t7, UADDR+U_PCB_REGS+(T7 * 4) 1227 sw s0, UADDR+U_PCB_REGS+(S0 * 4) 1228 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1229 sw s1, UADDR+U_PCB_REGS+(S1 * 4) 1230 sw s2, UADDR+U_PCB_REGS+(S2 * 4) 1231 sw s3, UADDR+U_PCB_REGS+(S3 * 4) 1232 sw s4, UADDR+U_PCB_REGS+(S4 * 4) 1233 mfc0 a2, MACH_COP_0_BAD_VADDR # Third arg is the fault addr 1234 sw s5, UADDR+U_PCB_REGS+(S5 * 4) 1235 sw s6, UADDR+U_PCB_REGS+(S6 * 4) 1236 sw s7, UADDR+U_PCB_REGS+(S7 * 4) 1237 sw t8, UADDR+U_PCB_REGS+(T8 * 4) 1238 mfc0 a3, MACH_COP_0_EXC_PC # Fourth arg is the pc. 1239 sw t9, UADDR+U_PCB_REGS+(T9 * 4) 1240 sw gp, UADDR+U_PCB_REGS+(GP * 4) 1241 sw sp, UADDR+U_PCB_REGS+(SP * 4) 1242 sw s8, UADDR+U_PCB_REGS+(S8 * 4) 1243 li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP 1244 sw ra, UADDR+U_PCB_REGS+(RA * 4) 1245 sw v0, UADDR+U_PCB_REGS+(MULLO * 4) 1246 sw v1, UADDR+U_PCB_REGS+(MULHI * 4) 1247 sw a0, UADDR+U_PCB_REGS+(SR * 4) 1248 la gp, _gp # switch to kernel GP 1249 sw a3, UADDR+U_PCB_REGS+(PC * 4) 1250 sw a3, STAND_RA_OFFSET(sp) # for debugging 1251 and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU. 1252/* 1253 * Call the exception handler. 1254 */ 1255 jal trap 1256 mtc0 t0, MACH_COP_0_STATUS_REG 1257/* 1258 * Restore user registers and return. NOTE: interrupts are enabled. 1259 */ 1260 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1261 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1262 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1263 mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts 1264 mtlo t0 1265 mthi t1 1266 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1267 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1268 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1269 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1270 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1271 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1272 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1273 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1274 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1275 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1276 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1277 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1278 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1279 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1280 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1281 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1282 lw s0, UADDR+U_PCB_REGS+(S0 * 4) 1283 lw s1, UADDR+U_PCB_REGS+(S1 * 4) 1284 lw s2, UADDR+U_PCB_REGS+(S2 * 4) 1285 lw s3, UADDR+U_PCB_REGS+(S3 * 4) 1286 lw s4, UADDR+U_PCB_REGS+(S4 * 4) 1287 lw s5, UADDR+U_PCB_REGS+(S5 * 4) 1288 lw s6, UADDR+U_PCB_REGS+(S6 * 4) 1289 lw s7, UADDR+U_PCB_REGS+(S7 * 4) 1290 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1291 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1292 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1293 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1294 lw s8, UADDR+U_PCB_REGS+(S8 * 4) 1295 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1296 j k0 1297 rfe 1298 .set at 1299 .set reorder 1300END(MachUserGenException) 1301 1302/*---------------------------------------------------------------------------- 1303 * 1304 * MachKernIntr -- 1305 * 1306 * Handle an interrupt from kernel mode. 1307 * Interrupts must use a separate stack since during exit() 1308 * there is a window of time when there is no kernel stack. 1309 * 1310 * Results: 1311 * None. 1312 * 1313 * Side effects: 1314 * None. 1315 * 1316 *---------------------------------------------------------------------------- 1317 */ 1318#define KINTR_REG_OFFSET (STAND_FRAME_SIZE) 1319#define KINTR_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) 1320#define KINTR_SP_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) 1321#define KINTR_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) 1322#define KINTR_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) 1323#define KINTR_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 16) 1324 1325NON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra) 1326 .set noreorder 1327 .set noat 1328 .mask 0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE) 1329/* 1330 * Check to see if we are already on the interrupt stack. 1331 */ 1332 li k0, MACH_CODE_START # interrupt stack below code 1333 sltu k1, sp, k0 1334 beq k1, zero, 1f # no, init sp 1335 nop 1336 sw sp, KINTR_SP_OFFSET - KINTR_FRAME_SIZE(sp) # save old sp 1337 b 2f 1338 subu sp, sp, KINTR_FRAME_SIZE # allocate stack frame 13391: 1340 sw sp, KINTR_SP_OFFSET - KINTR_FRAME_SIZE(k0) # save old sp 1341 subu sp, k0, KINTR_FRAME_SIZE # switch to interrupt stack 13422: 1343/* 1344 * Save the relevant kernel registers onto the stack. 1345 * We don't need to save s0 - s8, sp and gp because 1346 * the compiler does it for us. 1347 */ 1348 sw AT, KINTR_REG_OFFSET + 0(sp) 1349 sw v0, KINTR_REG_OFFSET + 4(sp) 1350 sw v1, KINTR_REG_OFFSET + 8(sp) 1351 sw a0, KINTR_REG_OFFSET + 12(sp) 1352 mflo v0 1353 mfhi v1 1354 sw a1, KINTR_REG_OFFSET + 16(sp) 1355 sw a2, KINTR_REG_OFFSET + 20(sp) 1356 sw a3, KINTR_REG_OFFSET + 24(sp) 1357 sw t0, KINTR_REG_OFFSET + 28(sp) 1358 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1359 sw t1, KINTR_REG_OFFSET + 32(sp) 1360 sw t2, KINTR_REG_OFFSET + 36(sp) 1361 sw t3, KINTR_REG_OFFSET + 40(sp) 1362 sw t4, KINTR_REG_OFFSET + 44(sp) 1363 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1364 sw t5, KINTR_REG_OFFSET + 48(sp) 1365 sw t6, KINTR_REG_OFFSET + 52(sp) 1366 sw t7, KINTR_REG_OFFSET + 56(sp) 1367 sw t8, KINTR_REG_OFFSET + 60(sp) 1368 mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc. 1369 sw t9, KINTR_REG_OFFSET + 64(sp) 1370 sw ra, KINTR_REG_OFFSET + 68(sp) 1371 sw v0, KINTR_MULT_LO_OFFSET(sp) 1372 sw v1, KINTR_MULT_HI_OFFSET(sp) 1373 sw a0, KINTR_SR_OFFSET(sp) 1374/* 1375 * Call the interrupt handler. 1376 */ 1377 jal interrupt 1378 sw a2, STAND_RA_OFFSET(sp) # for debugging 1379/* 1380 * Restore registers and return from the interrupt. 1381 */ 1382 lw a0, KINTR_SR_OFFSET(sp) 1383 lw t0, KINTR_MULT_LO_OFFSET(sp) 1384 lw t1, KINTR_MULT_HI_OFFSET(sp) 1385 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1386 mtlo t0 1387 mthi t1 1388 lw k0, STAND_RA_OFFSET(sp) 1389 lw AT, KINTR_REG_OFFSET + 0(sp) 1390 lw v0, KINTR_REG_OFFSET + 4(sp) 1391 lw v1, KINTR_REG_OFFSET + 8(sp) 1392 lw a0, KINTR_REG_OFFSET + 12(sp) 1393 lw a1, KINTR_REG_OFFSET + 16(sp) 1394 lw a2, KINTR_REG_OFFSET + 20(sp) 1395 lw a3, KINTR_REG_OFFSET + 24(sp) 1396 lw t0, KINTR_REG_OFFSET + 28(sp) 1397 lw t1, KINTR_REG_OFFSET + 32(sp) 1398 lw t2, KINTR_REG_OFFSET + 36(sp) 1399 lw t3, KINTR_REG_OFFSET + 40(sp) 1400 lw t4, KINTR_REG_OFFSET + 44(sp) 1401 lw t5, KINTR_REG_OFFSET + 48(sp) 1402 lw t6, KINTR_REG_OFFSET + 52(sp) 1403 lw t7, KINTR_REG_OFFSET + 56(sp) 1404 lw t8, KINTR_REG_OFFSET + 60(sp) 1405 lw t9, KINTR_REG_OFFSET + 64(sp) 1406 lw ra, KINTR_REG_OFFSET + 68(sp) 1407 lw sp, KINTR_SP_OFFSET(sp) # restore orig sp 1408 j k0 # Now return from the 1409 rfe # interrupt. 1410 .set at 1411 .set reorder 1412END(MachKernIntr) 1413 1414/*---------------------------------------------------------------------------- 1415 * 1416 * MachUserIntr -- 1417 * 1418 * Handle an interrupt from user mode. 1419 * Note: we save minimal state in the u.u_pcb struct and use the standard 1420 * kernel stack since there has to be a u page if we came from user mode. 1421 * If there is a pending software interrupt, then save the remaining state 1422 * and call softintr(). This is all because if we call swtch() inside 1423 * interrupt(), not all the user registers have been saved in u.u_pcb. 1424 * 1425 * Results: 1426 * None. 1427 * 1428 * Side effects: 1429 * None. 1430 * 1431 *---------------------------------------------------------------------------- 1432 */ 1433NON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra) 1434 .set noreorder 1435 .set noat 1436 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 1437/* 1438 * Save the relevant user registers into the u.u_pcb struct. 1439 * We don't need to save s0 - s8 because 1440 * the compiler does it for us. 1441 */ 1442 sw AT, UADDR+U_PCB_REGS+(AST * 4) 1443 sw v0, UADDR+U_PCB_REGS+(V0 * 4) 1444 sw v1, UADDR+U_PCB_REGS+(V1 * 4) 1445 sw a0, UADDR+U_PCB_REGS+(A0 * 4) 1446 mflo v0 1447 mfhi v1 1448 sw a1, UADDR+U_PCB_REGS+(A1 * 4) 1449 sw a2, UADDR+U_PCB_REGS+(A2 * 4) 1450 sw a3, UADDR+U_PCB_REGS+(A3 * 4) 1451 sw t0, UADDR+U_PCB_REGS+(T0 * 4) 1452 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1453 sw t1, UADDR+U_PCB_REGS+(T1 * 4) 1454 sw t2, UADDR+U_PCB_REGS+(T2 * 4) 1455 sw t3, UADDR+U_PCB_REGS+(T3 * 4) 1456 sw t4, UADDR+U_PCB_REGS+(T4 * 4) 1457 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1458 sw t5, UADDR+U_PCB_REGS+(T5 * 4) 1459 sw t6, UADDR+U_PCB_REGS+(T6 * 4) 1460 sw t7, UADDR+U_PCB_REGS+(T7 * 4) 1461 sw t8, UADDR+U_PCB_REGS+(T8 * 4) 1462 mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc. 1463 sw t9, UADDR+U_PCB_REGS+(T9 * 4) 1464 sw gp, UADDR+U_PCB_REGS+(GP * 4) 1465 sw sp, UADDR+U_PCB_REGS+(SP * 4) 1466 sw ra, UADDR+U_PCB_REGS+(RA * 4) 1467 li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP 1468 sw v0, UADDR+U_PCB_REGS+(MULLO * 4) 1469 sw v1, UADDR+U_PCB_REGS+(MULHI * 4) 1470 sw a0, UADDR+U_PCB_REGS+(SR * 4) 1471 sw a2, UADDR+U_PCB_REGS+(PC * 4) 1472 la gp, _gp # switch to kernel GP 1473 and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU. 1474 mtc0 t0, MACH_COP_0_STATUS_REG 1475/* 1476 * Call the interrupt handler. 1477 */ 1478 jal interrupt 1479 sw a2, STAND_RA_OFFSET(sp) # for debugging 1480/* 1481 * Restore registers and return from the interrupt. 1482 */ 1483 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1484 lw v0, astpending # any pending interrupts? 1485 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1486 bne v0, zero, 1f # don't restore, call softintr 1487 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1488 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1489 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1490 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1491 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1492 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1493 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1494 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1495 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1496 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1497 mtlo t0 1498 mthi t1 1499 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1500 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1501 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1502 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1503 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1504 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1505 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1506 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1507 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1508 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1509 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1510 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1511 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1512 j k0 # Now return from the 1513 rfe # interrupt. 1514 15151: 1516/* 1517 * We have pending software interrupts; save remaining user state in u.u_pcb. 1518 */ 1519 sw s0, UADDR+U_PCB_REGS+(S0 * 4) 1520 sw s1, UADDR+U_PCB_REGS+(S1 * 4) 1521 sw s2, UADDR+U_PCB_REGS+(S2 * 4) 1522 sw s3, UADDR+U_PCB_REGS+(S3 * 4) 1523 sw s4, UADDR+U_PCB_REGS+(S4 * 4) 1524 sw s5, UADDR+U_PCB_REGS+(S5 * 4) 1525 sw s6, UADDR+U_PCB_REGS+(S6 * 4) 1526 sw s7, UADDR+U_PCB_REGS+(S7 * 4) 1527 sw s8, UADDR+U_PCB_REGS+(S8 * 4) 1528 li t0, MACH_HARD_INT_MASK | MACH_SR_INT_ENA_CUR 1529/* 1530 * Call the software interrupt handler. 1531 */ 1532 jal softintr 1533 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts (spl0) 1534/* 1535 * Restore user registers and return. NOTE: interrupts are enabled. 1536 */ 1537 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1538 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1539 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1540 mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts 1541 mtlo t0 1542 mthi t1 1543 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1544 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1545 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1546 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1547 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1548 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1549 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1550 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1551 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1552 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1553 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1554 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1555 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1556 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1557 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1558 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1559 lw s0, UADDR+U_PCB_REGS+(S0 * 4) 1560 lw s1, UADDR+U_PCB_REGS+(S1 * 4) 1561 lw s2, UADDR+U_PCB_REGS+(S2 * 4) 1562 lw s3, UADDR+U_PCB_REGS+(S3 * 4) 1563 lw s4, UADDR+U_PCB_REGS+(S4 * 4) 1564 lw s5, UADDR+U_PCB_REGS+(S5 * 4) 1565 lw s6, UADDR+U_PCB_REGS+(S6 * 4) 1566 lw s7, UADDR+U_PCB_REGS+(S7 * 4) 1567 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1568 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1569 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1570 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1571 lw s8, UADDR+U_PCB_REGS+(S8 * 4) 1572 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1573 j k0 1574 rfe 1575 .set at 1576 .set reorder 1577END(MachUserIntr) 1578 1579/*---------------------------------------------------------------------------- 1580 * 1581 * MachTLBModException -- 1582 * 1583 * Handle a TLB modified exception. 1584 * The BaddVAddr, Context, and EntryHi registers contain the failed 1585 * virtual address. 1586 * 1587 * Results: 1588 * None. 1589 * 1590 * Side effects: 1591 * None. 1592 * 1593 *---------------------------------------------------------------------------- 1594 */ 1595LEAF(MachTLBModException) 1596#if 0 1597 .set noreorder 1598 .set noat 1599 tlbp # find the TLB entry 1600 mfc0 k0, MACH_COP_0_TLB_LOW # get the physical address 1601 mfc0 k1, MACH_COP_0_TLB_INDEX # check to be sure its valid 1602 or k0, k0, VMMACH_TLB_MOD_BIT # update TLB 1603 blt k1, zero, 4f # not found!!! 1604 mtc0 k0, MACH_COP_0_TLB_LOW 1605 li k1, MACH_CACHED_MEMORY_ADDR 1606 subu k0, k0, k1 1607 srl k0, k0, VMMACH_TLB_PHYS_PAGE_SHIFT 1608 la k1, pmap_attributes 1609 add k0, k0, k1 1610 lbu k1, 0(k0) # fetch old value 1611 nop 1612 or k1, k1, 1 # set modified bit 1613 sb k1, 0(k0) # save new value 1614 mfc0 k0, MACH_COP_0_EXC_PC # get return address 1615 nop 1616 j k0 1617 rfe 16184: 1619 break 0 # panic 1620 .set reorder 1621 .set at 1622#endif 1623END(MachTLBModException) 1624 1625/*---------------------------------------------------------------------------- 1626 * 1627 * MachTLBMissException -- 1628 * 1629 * Handle a TLB miss exception from kernel mode. 1630 * The BaddVAddr, Context, and EntryHi registers contain the failed 1631 * virtual address. 1632 * 1633 * Results: 1634 * None. 1635 * 1636 * Side effects: 1637 * None. 1638 * 1639 *---------------------------------------------------------------------------- 1640 */ 1641LEAF(MachTLBMissException) 1642 .set noreorder 1643 .set noat 1644 mfc0 k0, MACH_COP_0_BAD_VADDR # get the fault address 1645 li k1, MACH_KSEG2_ADDR # compute index 1646 subu k0, k0, k1 1647 srl k0, k0, PGSHIFT 1648 li k1, PMAP_HASH_KPAGES * NPTEPG # index within range? 1649 sltu k1, k0, k1 1650 beq k1, zero, SlowFault # No. do it the long way 1651 sll k0, k0, 2 # compute offset from index 1652 lw k0, PMAP_HASH_KADDR(k0) # get PTE entry 1653 mfc0 k1, MACH_COP_0_EXC_PC # get return address 1654 mtc0 k0, MACH_COP_0_TLB_LOW # save PTE entry 1655 and k0, k0, PG_V # make sure it's valid 1656 beq k0, zero, SlowFault # No. do it the long way 1657 nop 1658 tlbwr # update TLB 1659 j k1 1660 rfe 1661 .set reorder 1662 .set at 1663END(MachTLBMissException) 1664 1665/* 1666 * Set/clear software interrupt routines. 1667 */ 1668 1669LEAF(setsoftclock) 1670 .set noreorder 1671 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1672 nop 1673 or v0, v0, MACH_SOFT_INT_MASK_0 # set soft clock interrupt 1674 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1675 j ra 1676 nop 1677 .set reorder 1678END(setsoftclock) 1679 1680LEAF(clearsoftclock) 1681 .set noreorder 1682 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1683 nop 1684 and v0, v0, ~MACH_SOFT_INT_MASK_0 # clear soft clock interrupt 1685 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1686 j ra 1687 nop 1688 .set reorder 1689END(clearsoftclock) 1690 1691LEAF(setsoftnet) 1692 .set noreorder 1693 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1694 nop 1695 or v0, v0, MACH_SOFT_INT_MASK_1 # set soft net interrupt 1696 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1697 j ra 1698 nop 1699 .set reorder 1700END(setsoftnet) 1701 1702LEAF(clearsoftnet) 1703 .set noreorder 1704 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1705 nop 1706 and v0, v0, ~MACH_SOFT_INT_MASK_1 # clear soft net interrupt 1707 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1708 j ra 1709 nop 1710 .set reorder 1711END(clearsoftnet) 1712 1713/* 1714 * Set/change interrupt priority routines. 1715 */ 1716 1717LEAF(MachEnableIntr) 1718 .set noreorder 1719 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1720 nop 1721 or v0, v0, MACH_SR_INT_ENA_CUR 1722 mtc0 v0, MACH_COP_0_STATUS_REG # enable all interrupts 1723 j ra 1724 nop 1725 .set reorder 1726END(MachEnableIntr) 1727 1728LEAF(spl0) 1729 .set noreorder 1730 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1731 nop 1732 or t0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1733 mtc0 t0, MACH_COP_0_STATUS_REG # enable all interrupts 1734 j ra 1735 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1736 .set reorder 1737END(spl0) 1738 1739LEAF(splsoftclock) 1740 .set noreorder 1741 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1742 li t0, ~MACH_SOFT_INT_MASK_0 # disable soft clock 1743 and t0, t0, v0 1744 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1745 j ra 1746 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1747 .set reorder 1748END(splsoftclock) 1749 1750LEAF(splnet) 1751 .set noreorder 1752 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1753 li t0, ~(MACH_SOFT_INT_MASK_0 | MACH_SOFT_INT_MASK_1) 1754 and t0, t0, v0 1755 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1756 j ra 1757 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1758 .set reorder 1759END(splnet) 1760 1761LEAF(splbio) 1762 .set noreorder 1763 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1764 li t0, ~(MACH_INT_MASK_0 | MACH_SOFT_INT_MASK_0 | MACH_SOFT_INT_MASK_1) 1765 and t0, t0, v0 1766 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1767 j ra 1768 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1769 .set reorder 1770END(splbio) 1771 1772LEAF(splimp) 1773 .set noreorder 1774 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1775 li t0, ~(MACH_INT_MASK_1 | MACH_SOFT_INT_MASK_1 | MACH_SOFT_INT_MASK_0) 1776 and t0, t0, v0 1777 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1778 j ra 1779 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1780 .set reorder 1781END(splnet) 1782 1783LEAF(spltty) 1784 .set noreorder 1785 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1786 li t0, ~(MACH_INT_MASK_2 | MACH_SOFT_INT_MASK_1 | MACH_SOFT_INT_MASK_0) 1787 and t0, t0, v0 1788 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1789 j ra 1790 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1791 .set reorder 1792END(spltty) 1793 1794LEAF(splclock) 1795 .set noreorder 1796 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1797 li t0, ~(MACH_INT_MASK_3 | MACH_SOFT_INT_MASK_1 | MACH_SOFT_INT_MASK_0) 1798 and t0, t0, v0 1799 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1800 j ra 1801 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1802 .set reorder 1803END(splclock) 1804 1805LEAF(splhigh) 1806 .set noreorder 1807 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1808 li t0, ~MACH_SR_INT_ENA_CUR # disable all interrupts 1809 and t0, t0, v0 1810 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1811 j ra 1812 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1813 .set reorder 1814END(splhigh) 1815 1816/* 1817 * Restore saved interrupt mask. 1818 */ 1819LEAF(splx) 1820 .set noreorder 1821 mfc0 v0, MACH_COP_0_STATUS_REG 1822 li t0, ~(MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1823 and t0, t0, v0 1824 or t0, t0, a0 1825 mtc0 t0, MACH_COP_0_STATUS_REG 1826 j ra 1827 nop 1828 .set reorder 1829END(splx) 1830 1831/*---------------------------------------------------------------------------- 1832 * 1833 * MachEmptyWriteBuffer -- 1834 * 1835 * Return when the write buffer is empty. 1836 * 1837 * MachEmptyWriteBuffer() 1838 * 1839 * Results: 1840 * None. 1841 * 1842 * Side effects: 1843 * None. 1844 * 1845 *---------------------------------------------------------------------------- 1846 */ 1847LEAF(MachEmptyWriteBuffer) 1848 .set noreorder 1849 nop 1850 nop 1851 nop 1852 nop 18531: bc0f 1b 1854 nop 1855 j ra 1856 nop 1857 .set reorder 1858END(MachEmptyWriteBuffer) 1859 1860/*-------------------------------------------------------------------------- 1861 * 1862 * MachTLBWriteIndexed -- 1863 * 1864 * Write the given entry into the TLB at the given index. 1865 * 1866 * MachTLBWriteIndexed(index, highEntry, lowEntry) 1867 * int index; 1868 * int highEntry; 1869 * int lowEntry; 1870 * 1871 * Results: 1872 * None. 1873 * 1874 * Side effects: 1875 * TLB entry set. 1876 * 1877 *-------------------------------------------------------------------------- 1878 */ 1879LEAF(MachTLBWriteIndexed) 1880 .set noreorder 1881 mfc0 t1, MACH_COP_0_STATUS_REG # Save the status register. 1882 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID. 1883 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 1884 1885 sll a0, a0, VMMACH_TLB_INDEX_SHIFT 1886 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index. 1887 mtc0 a1, MACH_COP_0_TLB_HI # Set up entry high. 1888 mtc0 a2, MACH_COP_0_TLB_LOW # Set up entry low. 1889 nop 1890 tlbwi # Write the TLB 1891 1892 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID. 1893 j ra 1894 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register 1895 .set reorder 1896END(MachTLBWriteIndexed) 1897 1898/*-------------------------------------------------------------------------- 1899 * 1900 * MachTLBWriteRandom -- 1901 * 1902 * Write the given entry into the TLB at a random location. 1903 * 1904 * MachTLBWriteRandom(highEntry, lowEntry) 1905 * unsigned highEntry; 1906 * unsigned lowEntry; 1907 * 1908 * Results: 1909 * None. 1910 * 1911 * Side effects: 1912 * TLB entry set. 1913 * 1914 *-------------------------------------------------------------------------- 1915 */ 1916LEAF(MachTLBWriteRandom) 1917 .set noreorder 1918 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 1919 mfc0 v0, MACH_COP_0_TLB_HI # Save the current PID. 1920 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 1921 1922 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high. 1923 mtc0 a1, MACH_COP_0_TLB_LOW # Set up entry low. 1924 nop 1925 tlbwr # Write the TLB 1926 1927 mtc0 v0, MACH_COP_0_TLB_HI # Restore the PID. 1928 j ra 1929 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 1930 .set reorder 1931END(MachTLBWriteRandom) 1932 1933/*-------------------------------------------------------------------------- 1934 * 1935 * MachSetPID -- 1936 * 1937 * Write the given pid into the TLB pid reg. 1938 * 1939 * MachSetPID(pid) 1940 * int pid; 1941 * 1942 * Results: 1943 * None. 1944 * 1945 * Side effects: 1946 * PID set in the entry hi register. 1947 * 1948 *-------------------------------------------------------------------------- 1949 */ 1950LEAF(MachSetPID) 1951 .set noreorder 1952 sll a0, a0, VMMACH_TLB_PID_SHIFT # put PID in right spot 1953 mtc0 a0, MACH_COP_0_TLB_HI # Write the hi reg value 1954 j ra 1955 nop 1956 .set reorder 1957END(MachSetPID) 1958 1959/*-------------------------------------------------------------------------- 1960 * 1961 * MachTLBFlush -- 1962 * 1963 * Flush the "random" entries from the TLB. 1964 * 1965 * MachTLBFlush() 1966 * 1967 * Results: 1968 * None. 1969 * 1970 * Side effects: 1971 * The TLB is flushed. 1972 * 1973 *-------------------------------------------------------------------------- 1974 */ 1975LEAF(MachTLBFlush) 1976 .set noreorder 1977 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 1978 mfc0 t0, MACH_COP_0_TLB_HI # Save the PID 1979 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 1980 li t1, MACH_RESERVED_ADDR # invalid address 1981 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid 1982 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 1983/* 1984 * Align the starting value (t1), the increment (t2) and the upper bound (t3). 1985 */ 1986 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT 1987 li t2, 1 << VMMACH_TLB_INDEX_SHIFT 1988 li t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 19891: 1990 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register. 1991 addu t1, t1, t2 # Increment index. 1992 bne t1, t3, 1b # NB: always executes next 1993 tlbwi # Write the TLB entry. 1994 1995 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID 1996 j ra 1997 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 1998 .set reorder 1999END(MachTLBFlush) 2000 2001/*-------------------------------------------------------------------------- 2002 * 2003 * MachTLBFlushPID -- 2004 * 2005 * Flush all entries with the given PID from the TLB. 2006 * 2007 * MachTLBFlushPID(pid) 2008 * int pid; 2009 * 2010 * Results: 2011 * None. 2012 * 2013 * Side effects: 2014 * All entries corresponding to this PID are flushed. 2015 * 2016 *-------------------------------------------------------------------------- 2017 */ 2018LEAF(MachTLBFlushPID) 2019 .set noreorder 2020 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2021 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID 2022 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2023 sll a0, a0, VMMACH_TLB_PID_SHIFT # Align the pid to flush. 2024/* 2025 * Align the starting value (t1), the increment (t2) and the upper bound (t3). 2026 */ 2027 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT 2028 li t2, 1 << VMMACH_TLB_INDEX_SHIFT 2029 li t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 2030 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register 20311: 2032 addu t1, t1, t2 # Increment index. 2033 tlbr # Read from the TLB 2034 mfc0 t4, MACH_COP_0_TLB_HI # Fetch the hi register. 2035 nop 2036 and t4, t4, VMMACH_TLB_PID # compare PID's 2037 bne t4, a0, 2f 2038 li v0, MACH_RESERVED_ADDR # invalid address 2039 mtc0 v0, MACH_COP_0_TLB_HI # Mark entry high as invalid 2040 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2041 nop 2042 tlbwi # Write the entry. 20432: 2044 bne t1, t3, 1b 2045 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register 2046 2047 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2048 j ra 2049 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2050 .set reorder 2051END(MachTLBFlushPID) 2052 2053/*-------------------------------------------------------------------------- 2054 * 2055 * MachTLBFlushAddr -- 2056 * 2057 * Flush any TLB entries for the given address. 2058 * 2059 * MachTLBFlushAddr(virtaddr) 2060 * unsigned virtaddr; 2061 * 2062 * Results: 2063 * None. 2064 * 2065 * Side effects: 2066 * The process's page is flushed from the TLB. 2067 * 2068 *-------------------------------------------------------------------------- 2069 */ 2070LEAF(MachTLBFlushAddr) 2071 .set noreorder 2072 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2073 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2074 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2075 mtc0 a0, MACH_COP_0_TLB_HI # look for addr & PID 2076 mtc0 zero, MACH_COP_0_TLB_LOW # look for matching PID 2077 nop 2078 tlbp # Probe for the entry. 2079 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2080 li t1, MACH_RESERVED_ADDR # Load invalid entry. 2081 bltz v0, 1f # index < 0 => !found 2082 mtc0 t1, MACH_COP_0_TLB_HI # Prepare index hi. 2083 nop 2084 tlbwi 20851: 2086 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2087 j ra 2088 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2089 .set reorder 2090END(MachTLBFlushAddr) 2091 2092/*-------------------------------------------------------------------------- 2093 * 2094 * MachTLBUpdate -- 2095 * 2096 * Update the TLB if highreg is found. 2097 * 2098 * MachTLBUpdate(highreg, lowreg) 2099 * unsigned highreg, lowreg; 2100 * 2101 * Results: 2102 * None. 2103 * 2104 * Side effects: 2105 * None. 2106 * 2107 *-------------------------------------------------------------------------- 2108 */ 2109LEAF(MachTLBUpdate) 2110 .set noreorder 2111 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2112 mfc0 t0, MACH_COP_0_TLB_HI # Save current PID 2113 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2114 mtc0 a0, MACH_COP_0_TLB_HI # init high reg. 2115 mtc0 a1, MACH_COP_0_TLB_LOW # init low reg. 2116 nop 2117 tlbp # Probe for the entry. 2118 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2119 nop 2120 bltz v0, 1f # index < 0 => !found 2121 nop 2122 tlbwi 21231: 2124 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2125 j ra 2126 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2127 .set reorder 2128END(MachTLBUpdate) 2129 2130#ifdef DEBUG 2131/*-------------------------------------------------------------------------- 2132 * 2133 * MachTLBDump -- 2134 * 2135 * Print all entries in the TLB if 'all' is true; otherwise, just 2136 * print valid entries. 2137 * 2138 * MachTLBDump(all) 2139 * int all; 2140 * 2141 * Results: 2142 * None. 2143 * 2144 * Side effects: 2145 * None. 2146 * 2147 *-------------------------------------------------------------------------- 2148 */ 2149 2150#define DUMP_FRAME_SIZE (STAND_FRAME_SIZE + 4*4) 2151 2152NON_LEAF(MachTLBDump, DUMP_FRAME_SIZE, ra) 2153 .set noreorder 2154 subu sp, sp, DUMP_FRAME_SIZE 2155 sw s0, STAND_RA_OFFSET(sp) 2156 sw s1, STAND_RA_OFFSET+4(sp) 2157 sw s2, STAND_RA_OFFSET+8(sp) 2158 sw s3, STAND_RA_OFFSET+12(sp) 2159 sw ra, STAND_RA_OFFSET+16(sp) 2160 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2161 2162 mfc0 s0, MACH_COP_0_TLB_HI # Save the current PID 2163 sw a0, DUMP_FRAME_SIZE(sp) # Save 'all' 2164/* 2165 * Align the starting value (s1), the increment (s2) and the upper bound (s3). 2166 */ 2167 move s1, zero 2168 li s2, 1 << VMMACH_TLB_INDEX_SHIFT 2169 li s3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 2170 mtc0 s1, MACH_COP_0_TLB_INDEX # Set the index register 21711: 2172 addu s1, s1, s2 # Increment index. 2173 tlbr # Read from the TLB 2174 bne a0, zero, 2f # skip valid check if 'all' 2175 mfc0 a3, MACH_COP_0_TLB_LOW # Fetch the low register. 2176 nop 2177 and t0, a3, PG_V # is it valid? 2178 beq t0, zero, 3f 2179 nop 21802: 2181 mfc0 a2, MACH_COP_0_TLB_HI # Fetch the hi register. 2182 PRINTF("%d: hi %x low %x\n") # print entry 2183 srl a1, s1, VMMACH_TLB_INDEX_SHIFT # this is in the delay slot 2184 lw a0, DUMP_FRAME_SIZE(sp) # get 'all' 21853: 2186 bne s1, s3, 1b 2187 mtc0 s1, MACH_COP_0_TLB_INDEX # Set the index register 2188 2189 mtc0 s0, MACH_COP_0_TLB_HI # restore PID 2190 nop 2191 lw ra, STAND_RA_OFFSET+16(sp) 2192 lw s0, STAND_RA_OFFSET(sp) 2193 lw s1, STAND_RA_OFFSET+4(sp) 2194 lw s2, STAND_RA_OFFSET+8(sp) 2195 lw s3, STAND_RA_OFFSET+12(sp) 2196 j ra 2197 addu sp, sp, DUMP_FRAME_SIZE 2198 .set reorder 2199END(MachTLBDump) 2200 2201 .comm tlbhi, 4 2202 .comm tlblo, 4 2203LEAF(MachTLBFind) 2204 .set noreorder 2205 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2206 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2207 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2208 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high. 2209 mtc0 a1, MACH_COP_0_TLB_LOW # Set up entry low. 2210 nop 2211 tlbp # Probe for the entry. 2212 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2213 mfc0 t1, MACH_COP_0_TLB_HI # See what we got 2214 mfc0 t2, MACH_COP_0_TLB_LOW # See what we got 2215 sw t1, tlbhi 2216 sw t2, tlblo 2217 mtc0 t0, MACH_COP_0_TLB_HI # Get current PID 2218 j ra 2219 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2220 .set reorder 2221END(MachTLBFind) 2222 2223/*-------------------------------------------------------------------------- 2224 * 2225 * MachGetPID -- 2226 * 2227 * MachGetPID() 2228 * 2229 * Results: 2230 * Returns the current TLB pid reg. 2231 * 2232 * Side effects: 2233 * None. 2234 * 2235 *-------------------------------------------------------------------------- 2236 */ 2237LEAF(MachGetPID) 2238 .set noreorder 2239 mfc0 v0, MACH_COP_0_TLB_HI # get PID 2240 nop 2241 and v0, v0, VMMACH_TLB_PID # mask off PID 2242 j ra 2243 srl v0, v0, VMMACH_TLB_PID_SHIFT # put PID in right spot 2244 .set reorder 2245END(MachGetPID) 2246#endif /* DEBUG */ 2247 2248/*---------------------------------------------------------------------------- 2249 * 2250 * MachSwitchFPState -- 2251 * 2252 * Save the current state into 'from' and restore it from 'to'. 2253 * 2254 * MachSwitchFPState(from, to) 2255 * struct proc *from; 2256 * struct user *to; 2257 * 2258 * Results: 2259 * None. 2260 * 2261 * Side effects: 2262 * None. 2263 * 2264 *---------------------------------------------------------------------------- 2265 */ 2266LEAF(MachSwitchFPState) 2267 .set noreorder 2268 mfc0 t1, MACH_COP_0_STATUS_REG # Save old SR 2269 li t0, MACH_SR_COP_1_BIT # Disable interrupts and 2270 mtc0 t0, MACH_COP_0_STATUS_REG # enable the coprocessor 2271 2272 beq a0, zero, 1f # skip save if NULL pointer 2273 nop 2274/* 2275 * First read out the status register to make sure that all FP operations 2276 * have completed. 2277 */ 2278 lw a0, P_ADDR(a0) # get pointer to pcb for proc 2279 cfc1 t0, MACH_FPC_CSR # stall til FP done, get status 2280 li t3, ~MACH_SR_COP_1_BIT 2281 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register 2282 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status 2283 and t2, t2, t3 # clear COP_1 enable bit 2284 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register 2285/* 2286 * Save the floating point registers. 2287 */ 2288 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) 2289 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) 2290 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) 2291 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) 2292 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) 2293 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) 2294 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) 2295 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) 2296 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) 2297 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) 2298 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) 2299 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) 2300 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) 2301 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) 2302 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) 2303 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) 2304 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) 2305 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) 2306 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) 2307 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) 2308 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) 2309 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) 2310 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) 2311 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) 2312 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) 2313 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) 2314 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) 2315 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) 2316 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) 2317 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) 2318 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) 2319 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) 2320 23211: 2322/* 2323 * Restore the floating point registers. 2324 */ 2325 lw t0, U_PCB_FPREGS+(32 * 4)(a1) # get status register 2326 lwc1 $f0, U_PCB_FPREGS+(0 * 4)(a1) 2327 lwc1 $f1, U_PCB_FPREGS+(1 * 4)(a1) 2328 lwc1 $f2, U_PCB_FPREGS+(2 * 4)(a1) 2329 lwc1 $f3, U_PCB_FPREGS+(3 * 4)(a1) 2330 lwc1 $f4, U_PCB_FPREGS+(4 * 4)(a1) 2331 lwc1 $f5, U_PCB_FPREGS+(5 * 4)(a1) 2332 lwc1 $f6, U_PCB_FPREGS+(6 * 4)(a1) 2333 lwc1 $f7, U_PCB_FPREGS+(7 * 4)(a1) 2334 lwc1 $f8, U_PCB_FPREGS+(8 * 4)(a1) 2335 lwc1 $f9, U_PCB_FPREGS+(9 * 4)(a1) 2336 lwc1 $f10, U_PCB_FPREGS+(10 * 4)(a1) 2337 lwc1 $f11, U_PCB_FPREGS+(11 * 4)(a1) 2338 lwc1 $f12, U_PCB_FPREGS+(12 * 4)(a1) 2339 lwc1 $f13, U_PCB_FPREGS+(13 * 4)(a1) 2340 lwc1 $f14, U_PCB_FPREGS+(14 * 4)(a1) 2341 lwc1 $f15, U_PCB_FPREGS+(15 * 4)(a1) 2342 lwc1 $f16, U_PCB_FPREGS+(16 * 4)(a1) 2343 lwc1 $f17, U_PCB_FPREGS+(17 * 4)(a1) 2344 lwc1 $f18, U_PCB_FPREGS+(18 * 4)(a1) 2345 lwc1 $f19, U_PCB_FPREGS+(19 * 4)(a1) 2346 lwc1 $f20, U_PCB_FPREGS+(20 * 4)(a1) 2347 lwc1 $f21, U_PCB_FPREGS+(21 * 4)(a1) 2348 lwc1 $f22, U_PCB_FPREGS+(22 * 4)(a1) 2349 lwc1 $f23, U_PCB_FPREGS+(23 * 4)(a1) 2350 lwc1 $f24, U_PCB_FPREGS+(24 * 4)(a1) 2351 lwc1 $f25, U_PCB_FPREGS+(25 * 4)(a1) 2352 lwc1 $f26, U_PCB_FPREGS+(26 * 4)(a1) 2353 lwc1 $f27, U_PCB_FPREGS+(27 * 4)(a1) 2354 lwc1 $f28, U_PCB_FPREGS+(28 * 4)(a1) 2355 lwc1 $f29, U_PCB_FPREGS+(29 * 4)(a1) 2356 lwc1 $f30, U_PCB_FPREGS+(30 * 4)(a1) 2357 lwc1 $f31, U_PCB_FPREGS+(31 * 4)(a1) 2358 2359 and t0, t0, ~MACH_FPC_EXCEPTION_BITS 2360 ctc1 t0, MACH_FPC_CSR 2361 nop 2362 2363 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register. 2364 j ra 2365 nop 2366 .set reorder 2367END(MachSwitchFPState) 2368 2369/*---------------------------------------------------------------------------- 2370 * 2371 * MachSaveCurFPState -- 2372 * 2373 * Save the current floating point coprocessor state. 2374 * 2375 * MachSaveCurFPState(p) 2376 * struct proc *p; 2377 * 2378 * Results: 2379 * None. 2380 * 2381 * Side effects: 2382 * None. 2383 * 2384 *---------------------------------------------------------------------------- 2385 */ 2386LEAF(MachSaveCurFPState) 2387 .set noreorder 2388 lw a0, P_ADDR(a0) # get pointer to pcb for proc 2389 mfc0 t1, MACH_COP_0_STATUS_REG # Disable interrupts and 2390 li t0, MACH_SR_COP_1_BIT # enable the coprocessor 2391 mtc0 t0, MACH_COP_0_STATUS_REG 2392 nop 2393/* 2394 * First read out the status register to make sure that all FP operations 2395 * have completed. 2396 */ 2397 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register 2398 li t3, ~MACH_SR_COP_1_BIT 2399 and t2, t2, t3 # clear COP_1 enable bit 2400 cfc1 t0, MACH_FPC_CSR # stall til FP done, get status 2401 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register 2402 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status 2403/* 2404 * Save the floating point registers. 2405 */ 2406 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) 2407 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) 2408 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) 2409 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) 2410 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) 2411 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) 2412 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) 2413 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) 2414 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) 2415 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) 2416 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) 2417 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) 2418 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) 2419 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) 2420 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) 2421 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) 2422 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) 2423 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) 2424 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) 2425 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) 2426 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) 2427 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) 2428 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) 2429 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) 2430 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) 2431 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) 2432 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) 2433 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) 2434 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) 2435 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) 2436 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) 2437 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) 2438 2439 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register. 2440 j ra 2441 nop 2442 .set reorder 2443END(MachSaveCurFPState) 2444 2445/*---------------------------------------------------------------------------- 2446 * 2447 * MachFPInterrupt -- 2448 * 2449 * Handle a floating point interrupt. 2450 * 2451 * MachFPInterrupt(statusReg, causeReg, pc) 2452 * unsigned statusReg; 2453 * unsigned causeReg; 2454 * unsigned pc; 2455 * 2456 * Results: 2457 * None. 2458 * 2459 * Side effects: 2460 * None. 2461 * 2462 *---------------------------------------------------------------------------- 2463 */ 2464NON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra) 2465 .set noreorder 2466 subu sp, sp, STAND_FRAME_SIZE 2467 mfc0 t0, MACH_COP_0_STATUS_REG 2468 sw ra, STAND_RA_OFFSET(sp) 2469 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2470 2471 or t1, t0, MACH_SR_COP_1_BIT 2472 mtc0 t1, MACH_COP_0_STATUS_REG 2473 nop 2474 nop 2475 cfc1 t1, MACH_FPC_CSR # stall til FP done, get status 2476 nop 2477 .set reorder 2478 sll t2, t1, (31 - 17) # unimplemented operation? 2479 bgez t2, 3f # no, normal trap 2480/* 2481 * We got an unimplemented operation trap so 2482 * fetch the instruction, compute the next PC and emulate the instruction. 2483 */ 2484 bgez a1, 1f # Check the branch delay bit. 2485/* 2486 * The instruction is in the branch delay slot so the branch will have to 2487 * be emulated to get the resulting PC. 2488 */ 2489 sw a2, STAND_FRAME_SIZE + 8(sp) 2490 li a0, UADDR+U_PCB_REGS # first arg is ptr to CPU registers 2491 move a1, a2 # second arg is instruction PC 2492 move a2, t1 # third arg is floating point CSR 2493 move a3, zero # fourth arg is FALSE 2494 jal MachEmulateBranch # compute PC after branch 2495/* 2496 * Now load the floating-point instruction in the branch delay slot 2497 * to be emulated. 2498 */ 2499 lw a2, STAND_FRAME_SIZE + 8(sp) # restore EXC pc 2500 lw a0, 4(a2) # a0 = coproc instruction 2501 b 2f 2502/* 2503 * This is not in the branch delay slot so calculate the resulting 2504 * PC (epc + 4) into v0 and continue to MachEmulateFP(). 2505 */ 25061: 2507 lw a0, 0(a2) # a0 = coproc instruction 2508 addu v0, a2, 4 # v0 = next pc 25092: 2510 sw v0, UADDR+U_PCB_REGS+(PC * 4) # save new pc 2511/* 2512 * Check to see if the instruction to be emulated is a floating-point 2513 * instruction. 2514 */ 2515 srl a3, a0, MACH_OPCODE_SHIFT 2516 beq a3, MACH_OPCODE_C1, 4f # this should never fail 2517/* 2518 * Send a floating point exception signal to the current process. 2519 */ 25203: 2521 lw a0, curproc # get current process 2522 cfc1 a2, MACH_FPC_CSR # code = FP execptions 2523 li a1, SIGFPE 2524 ctc1 zero, MACH_FPC_CSR # Clear exceptions 2525 jal trapsignal 2526 b FPReturn 2527 2528/* 2529 * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate. 2530 */ 25314: 2532 jal MachEmulateFP 2533 2534/* 2535 * Turn off the floating point coprocessor and return. 2536 */ 2537FPReturn: 2538 .set noreorder 2539 mfc0 t0, MACH_COP_0_STATUS_REG 2540 lw ra, STAND_RA_OFFSET(sp) 2541 and t0, t0, ~MACH_SR_COP_1_BIT 2542 mtc0 t0, MACH_COP_0_STATUS_REG 2543 j ra 2544 addu sp, sp, STAND_FRAME_SIZE 2545 .set reorder 2546END(MachFPInterrupt) 2547 2548/*---------------------------------------------------------------------------- 2549 * 2550 * MachConfigCache -- 2551 * 2552 * Size the caches. 2553 * NOTE: should only be called from mach_init(). 2554 * 2555 * Results: 2556 * None. 2557 * 2558 * Side effects: 2559 * The size of the data cache is stored into machDataCacheSize and the 2560 * size of instruction cache is stored into machInstCacheSize. 2561 * 2562 *---------------------------------------------------------------------------- 2563 */ 2564NON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra) 2565 .set noreorder 2566 subu sp, sp, STAND_FRAME_SIZE 2567 sw ra, STAND_RA_OFFSET(sp) # Save return address. 2568 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2569 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2570 la v0, 1f 2571 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2572 j v0 2573 nop 25741: 2575/* 2576 * This works because jal doesn't change pc[31..28] and the 2577 * linker still thinks SizeCache is in the cached region so it computes 2578 * the correct address without complaining. 2579 */ 2580 jal SizeCache # Get the size of the d-cache. 2581 nop 2582 sw v0, machDataCacheSize 2583 nop # Make sure sw out of pipe 2584 nop 2585 nop 2586 nop 2587 li v0, MACH_SR_SWAP_CACHES # Swap caches 2588 mtc0 v0, MACH_COP_0_STATUS_REG 2589 nop # Insure caches stable 2590 nop 2591 nop 2592 nop 2593 jal SizeCache # Get the size of the i-cache. 2594 nop 2595 sw v0, machInstCacheSize 2596 nop # Make sure sw out of pipe 2597 nop 2598 nop 2599 nop 2600 mtc0 zero, MACH_COP_0_STATUS_REG # Swap back caches. 2601 nop 2602 nop 2603 nop 2604 nop 2605 la t0, 1f 2606 j t0 # Back to cached mode 2607 nop 26081: 2609 lw ra, STAND_RA_OFFSET(sp) # Restore return addr 2610 addu sp, sp, STAND_FRAME_SIZE # Restore sp. 2611 j ra 2612 nop 2613 .set reorder 2614END(MachConfigCache) 2615 2616/*---------------------------------------------------------------------------- 2617 * 2618 * SizeCache -- 2619 * 2620 * Get the size of the cache. 2621 * 2622 * Results: 2623 * The size of the cache. 2624 * 2625 * Side effects: 2626 * None. 2627 * 2628 *---------------------------------------------------------------------------- 2629 */ 2630LEAF(SizeCache) 2631 .set noreorder 2632 mfc0 t0, MACH_COP_0_STATUS_REG # Save the current status reg. 2633 nop 2634 or v0, t0, MACH_SR_ISOL_CACHES # Isolate the caches. 2635 nop # Make sure no stores in pipe 2636 mtc0 v0, MACH_COP_0_STATUS_REG 2637 nop # Make sure isolated 2638 nop 2639 nop 2640/* 2641 * Clear cache size boundaries. 2642 */ 2643 li v0, MACH_MIN_CACHE_SIZE 26441: 2645 sw zero, MACH_CACHED_MEMORY_ADDR(v0) # Clear cache memory 2646 sll v0, v0, 1 2647 bleu v0, +MACH_MAX_CACHE_SIZE, 1b 2648 nop 2649 li v0, -1 2650 sw v0, MACH_CACHED_MEMORY_ADDR(zero) # Store marker in cache 2651 li v0, MACH_MIN_CACHE_SIZE 26522: 2653 lw v1, MACH_CACHED_MEMORY_ADDR(v0) # Look for marker 2654 nop 2655 bne v1, zero, 3f # Found marker. 2656 nop 2657 sll v0, v0, 1 # cache size * 2 2658 bleu v0, +MACH_MAX_CACHE_SIZE, 2b # keep looking 2659 nop 2660 move v0, zero # must be no cache 26613: 2662 mtc0 t0, MACH_COP_0_STATUS_REG 2663 nop # Make sure unisolated 2664 nop 2665 nop 2666 nop 2667 j ra 2668 nop 2669 .set reorder 2670END(SizeCache) 2671 2672/*---------------------------------------------------------------------------- 2673 * 2674 * MachFlushCache -- 2675 * 2676 * Flush the caches. 2677 * 2678 * Results: 2679 * None. 2680 * 2681 * Side effects: 2682 * The contents of the caches is flushed. 2683 * 2684 *---------------------------------------------------------------------------- 2685 */ 2686LEAF(MachFlushCache) 2687 .set noreorder 2688 lw t1, machInstCacheSize # Must load before isolating 2689 lw t2, machDataCacheSize # Must load before isolating 2690 mfc0 t3, MACH_COP_0_STATUS_REG # Save the status register. 2691 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2692 la v0, 1f 2693 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2694 j v0 2695 nop 2696/* 2697 * Flush the instruction cache. 2698 */ 26991: 2700 li v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES 2701 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap caches. 2702 li t0, MACH_UNCACHED_MEMORY_ADDR 2703 subu t0, t0, t1 2704 li t1, MACH_UNCACHED_MEMORY_ADDR 2705 la v0, 1f # Run cached 2706 j v0 2707 nop 27081: 2709 sb zero, 0(t0) 2710 sb zero, 4(t0) 2711 sb zero, 8(t0) 2712 sb zero, 12(t0) 2713 sb zero, 16(t0) 2714 sb zero, 20(t0) 2715 sb zero, 24(t0) 2716 addu t0, t0, 32 2717 bne t0, t1, 1b 2718 sb zero, -4(t0) 2719 2720 la v0, 1f 2721 or v0, MACH_UNCACHED_MEMORY_ADDR 2722 j v0 # Run uncached 2723 nop 2724/* 2725 * Flush the data cache. 2726 */ 27271: 2728 li v0, MACH_SR_ISOL_CACHES 2729 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap back caches 2730 li t0, MACH_UNCACHED_MEMORY_ADDR 2731 subu t0, t0, t2 2732 la v0, 1f 2733 j v0 # Back to cached mode 2734 nop 27351: 2736 sb zero, 0(t0) 2737 sb zero, 4(t0) 2738 sb zero, 8(t0) 2739 sb zero, 12(t0) 2740 sb zero, 16(t0) 2741 sb zero, 20(t0) 2742 sb zero, 24(t0) 2743 addu t0, t0, 32 2744 bne t0, t1, 1b 2745 sb zero, -4(t0) 2746 2747 nop # Insure isolated stores 2748 nop # out of pipe. 2749 nop 2750 nop 2751 mtc0 t3, MACH_COP_0_STATUS_REG # Restore status reg. 2752 nop # Insure cache unisolated. 2753 nop 2754 nop 2755 nop 2756 j ra 2757 nop 2758 .set reorder 2759END(MachFlushCache) 2760 2761/*---------------------------------------------------------------------------- 2762 * 2763 * MachFlushICache -- 2764 * 2765 * MachFlushICache(addr, len) 2766 * 2767 * Flush instruction cache for range of addr to addr + len - 1. 2768 * 2769 * Results: 2770 * None. 2771 * 2772 * Side effects: 2773 * The contents of the cache is flushed. 2774 * 2775 *---------------------------------------------------------------------------- 2776 */ 2777LEAF(MachFlushICache) 2778 .set noreorder 2779 lw t1, machInstCacheSize 2780 mfc0 t3, MACH_COP_0_STATUS_REG # Save SR 2781 subu t0, t1, 1 # t0 = size - 1 2782 and a0, a0, t0 # mask off address bits 2783 addu t0, t0, MACH_UNCACHED_MEMORY_ADDR 2784 subu t0, t0, t1 2785 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2786 2787 la v0, 1f 2788 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2789 j v0 2790 nop 27911: 2792 li v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES 2793 mtc0 v0, MACH_COP_0_STATUS_REG 2794 bltu t1, a1, 1f # cache is smaller than region 2795 nop 2796 move t1, a1 27971: 2798 addu t1, t1, t0 # compute ending address 2799 la v0, 1f # run cached 2800 j v0 2801 nop 28021: 2803 sb zero, 0(t0) 2804 sb zero, 4(t0) 2805 sb zero, 8(t0) 2806 sb zero, 12(t0) 2807 sb zero, 16(t0) 2808 sb zero, 20(t0) 2809 sb zero, 24(t0) 2810 addu t0, t0, 32 2811 bltu t0, t1, 1b 2812 sb zero, -4(t0) 2813 2814 la v0, 1f 2815 or v0, MACH_UNCACHED_MEMORY_ADDR 2816 j v0 # Run uncached 2817 nop 28181: 2819 nop # insure isolated stores out of pipe 2820 mtc0 zero, MACH_COP_0_STATUS_REG # unisolate, unswap 2821 nop # keep pipeline clean 2822 nop 2823 nop 2824 mtc0 t3, MACH_COP_0_STATUS_REG # enable interrupts 2825 j ra # return and run cached 2826 nop 2827 .set reorder 2828END(MachFlushICache) 2829