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