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