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