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