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