1/* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Digital Equipment Corporation, 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 8.3 (Berkeley) 09/23/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_CACHED_MEMORY_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_switch(). 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_switch() 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 * The following primitives manipulate the run queues. _whichqs tells which 776 * of the 32 queues _qs have processes in them. Setrunqueue puts processes 777 * into queues, Remrq removes them from queues. The running process is on 778 * no queue, other processes are on a queue related to p->p_priority, divided 779 * by 4 actually to shrink the 0-127 range of priorities into the 32 available 780 * queues. 781 */ 782/* 783 * setrunqueue(p) 784 * proc *p; 785 * 786 * Call should be made at splclock(), and p->p_stat should be SRUN. 787 */ 788NON_LEAF(setrunqueue, STAND_FRAME_SIZE, ra) 789 subu sp, sp, STAND_FRAME_SIZE 790 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 791 lw t0, P_BACK(a0) ## firewall: p->p_back must be 0 792 sw ra, STAND_RA_OFFSET(sp) ## 793 beq t0, zero, 1f ## 794 PANIC("setrunqueue") ## 7951: 796 lbu t0, P_PRIORITY(a0) # put on p->p_priority / 4 queue 797 srl t0, t0, 2 # compute index into 'whichqs' 798 li t1, 1 # compute corresponding bit 799 sll t1, t1, t0 800 lw t2, whichqs # set corresponding bit 801 or t2, t2, t1 802 sw t2, whichqs 803 sll t0, t0, 3 # compute index into 'qs' 804 la t1, qs 805 addu t0, t0, t1 # t0 = qp = &qs[pri >> 2] 806 lw t1, P_BACK(t0) # t1 = qp->ph_rlink 807 sw t0, P_FORW(a0) # p->p_forw = qp 808 sw t1, P_BACK(a0) # p->p_back = qp->ph_rlink 809 sw a0, P_FORW(t1) # p->p_back->p_forw = p; 810 sw a0, P_BACK(t0) # qp->ph_rlink = p 811 addu sp, sp, STAND_FRAME_SIZE 812 j ra 813END(setrunqueue) 814 815/* 816 * Remrq(p) 817 * 818 * Call should be made at splclock(). 819 */ 820NON_LEAF(remrq, STAND_FRAME_SIZE, ra) 821 subu sp, sp, STAND_FRAME_SIZE 822 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 823 lbu t0, P_PRIORITY(a0) # get from p->p_priority / 4 queue 824 srl t0, t0, 2 # compute index into 'whichqs' 825 li t1, 1 # compute corresponding bit 826 sll t1, t1, t0 827 lw t2, whichqs # check corresponding bit 828 and v0, t2, t1 829 sw ra, STAND_RA_OFFSET(sp) ## 830 bne v0, zero, 1f ## 831 PANIC("remrq") ## it wasn't recorded to be on its q 8321: 833 lw v0, P_BACK(a0) # v0 = p->p_back 834 lw v1, P_FORW(a0) # v1 = p->p_forw 835 sw v1, P_FORW(v0) # p->p_back->p_forw = p->p_forw; 836 sw v0, P_BACK(v1) # p->p_forw->p_back = p->r_rlink 837 sll t0, t0, 3 # compute index into 'qs' 838 la v0, qs 839 addu t0, t0, v0 # t0 = qp = &qs[pri >> 2] 840 lw v0, P_FORW(t0) # check if queue empty 841 bne v0, t0, 2f # No. qp->ph_link != qp 842 xor t2, t2, t1 # clear corresponding bit in 'whichqs' 843 sw t2, whichqs 8442: 845 sw zero, P_BACK(a0) ## for firewall checking 846 addu sp, sp, STAND_FRAME_SIZE 847 j ra 848END(remrq) 849 850/* 851 * switch_exit() 852 * 853 * At exit of a process, do a cpu_switch for the last time. The mapping 854 * of the pcb at p->p_addr has already been deleted, and the memory for 855 * the pcb+stack has been freed. All interrupts should be blocked at this 856 * point. 857 */ 858LEAF(switch_exit) 859 .set noreorder 860 la v1, nullproc # save state into garbage proc 861 lw t0, P_UPTE+0(v1) # t0 = first u. pte 862 lw t1, P_UPTE+4(v1) # t1 = 2nd u. pte 863 li v0, UADDR # v0 = first HI entry 864 mtc0 zero, MACH_COP_0_TLB_INDEX # set the index register 865 mtc0 v0, MACH_COP_0_TLB_HI # init high entry 866 mtc0 t0, MACH_COP_0_TLB_LOW # init low entry 867 li t0, 1 << VMMACH_TLB_INDEX_SHIFT 868 tlbwi # Write the TLB entry. 869 addu v0, v0, NBPG # 2nd HI entry 870 mtc0 t0, MACH_COP_0_TLB_INDEX # set the index register 871 mtc0 v0, MACH_COP_0_TLB_HI # init high entry 872 mtc0 t1, MACH_COP_0_TLB_LOW # init low entry 873 sw zero, curproc 874 tlbwi # Write the TLB entry. 875 .set reorder 876 li sp, KERNELSTACK - START_FRAME # switch to standard stack 877 b cpu_switch 878END(switch_exit) 879 880/* 881 * When no processes are on the runq, cpu_switch branches to idle to wait 882 * for something to come ready. Note: this is really a part of cpu_switch() 883 * but defined here for kernel profiling. 884 */ 885LEAF(idle) 886 .set noreorder 887 li t0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 888 mtc0 t0, MACH_COP_0_STATUS_REG # enable all interrupts 889 sw zero, curproc # set curproc NULL for stats 8901: 891 lw t0, whichqs # look for non-empty queue 892 nop 893 beq t0, zero, 1b 894 nop 895 b sw1 896 mtc0 zero, MACH_COP_0_STATUS_REG # Disable all interrupts 897 .set reorder 898END(idle) 899 900/* 901 * cpu_switch() 902 * Find the highest priority process and resume it. 903 */ 904NON_LEAF(cpu_switch, STAND_FRAME_SIZE, ra) 905 .set noreorder 906 sw sp, UADDR+U_PCB_CONTEXT+32 # save old sp 907 subu sp, sp, STAND_FRAME_SIZE 908 sw ra, STAND_RA_OFFSET(sp) 909 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 910 lw t2, cnt+V_SWTCH # for statistics 911 lw t1, whichqs # look for non-empty queue 912 sw s0, UADDR+U_PCB_CONTEXT+0 # do a 'savectx()' 913 sw s1, UADDR+U_PCB_CONTEXT+4 914 sw s2, UADDR+U_PCB_CONTEXT+8 915 sw s3, UADDR+U_PCB_CONTEXT+12 916 mfc0 t0, MACH_COP_0_STATUS_REG # t0 = saved status register 917 sw s4, UADDR+U_PCB_CONTEXT+16 918 sw s5, UADDR+U_PCB_CONTEXT+20 919 sw s6, UADDR+U_PCB_CONTEXT+24 920 sw s7, UADDR+U_PCB_CONTEXT+28 921 sw s8, UADDR+U_PCB_CONTEXT+36 922 sw ra, UADDR+U_PCB_CONTEXT+40 # save return address 923 sw t0, UADDR+U_PCB_CONTEXT+44 # save status register 924 addu t2, t2, 1 925 sw t2, cnt+V_SWTCH 926 beq t1, zero, idle # if none, idle 927 mtc0 zero, MACH_COP_0_STATUS_REG # Disable all interrupts 928sw1: 929 nop # wait for intrs disabled 930 nop 931 lw t0, whichqs # look for non-empty queue 932 li t2, -1 # t2 = lowest bit set 933 beq t0, zero, idle # if none, idle 934 move t3, t0 # t3 = saved whichqs 9351: 936 add t2, t2, 1 937 and t1, t0, 1 # bit set? 938 beq t1, zero, 1b 939 srl t0, t0, 1 # try next bit 940/* 941 * Remove process from queue. 942 */ 943 sll t0, t2, 3 944 la t1, qs 945 addu t0, t0, t1 # t0 = qp = &qs[highbit] 946 lw a0, P_FORW(t0) # a0 = p = highest pri process 947 nop 948 lw v0, P_FORW(a0) # v0 = p->p_forw 949 bne t0, a0, 2f # make sure something in queue 950 sw v0, P_FORW(t0) # qp->ph_link = p->p_forw; 951 PANIC("cpu_switch") # nothing in queue 9522: 953 sw t0, P_BACK(v0) # p->p_forw->p_back = qp 954 bne v0, t0, 3f # queue still not empty 955 sw zero, P_BACK(a0) ## for firewall checking 956 li v1, 1 # compute bit in 'whichqs' 957 sll v1, v1, t2 958 xor t3, t3, v1 # clear bit in 'whichqs' 959 sw t3, whichqs 9603: 961/* 962 * Switch to new context. 963 */ 964 sw zero, want_resched 965 jal pmap_alloc_tlbpid # v0 = TLB PID 966 move s0, a0 # save p 967 move a0, s0 # restore p 968 sw a0, curproc # set curproc 969 sll v0, v0, VMMACH_TLB_PID_SHIFT # v0 = aligned PID 970 lw t0, P_UPTE+0(a0) # t0 = first u. pte 971 lw t1, P_UPTE+4(a0) # t1 = 2nd u. pte 972 or v0, v0, UADDR # v0 = first HI entry 973/* 974 * Resume process indicated by the pte's for its u struct 975 * NOTE: This is hard coded to UPAGES == 2. 976 * Also, there should be no TLB faults at this point. 977 */ 978 mtc0 zero, MACH_COP_0_TLB_INDEX # set the index register 979 mtc0 v0, MACH_COP_0_TLB_HI # init high entry 980 mtc0 t0, MACH_COP_0_TLB_LOW # init low entry 981 li t0, 1 << VMMACH_TLB_INDEX_SHIFT 982 tlbwi # Write the TLB entry. 983 addu v0, v0, NBPG # 2nd HI entry 984 mtc0 t0, MACH_COP_0_TLB_INDEX # set the index register 985 mtc0 v0, MACH_COP_0_TLB_HI # init high entry 986 mtc0 t1, MACH_COP_0_TLB_LOW # init low entry 987 nop 988 tlbwi # Write the TLB entry. 989/* 990 * Now running on new u struct. 991 * Restore registers and return. 992 */ 993 lw v0, UADDR+U_PCB_CONTEXT+44 # restore kernel context 994 lw ra, UADDR+U_PCB_CONTEXT+40 995 lw s0, UADDR+U_PCB_CONTEXT+0 996 lw s1, UADDR+U_PCB_CONTEXT+4 997 lw s2, UADDR+U_PCB_CONTEXT+8 998 lw s3, UADDR+U_PCB_CONTEXT+12 999 lw s4, UADDR+U_PCB_CONTEXT+16 1000 lw s5, UADDR+U_PCB_CONTEXT+20 1001 lw s6, UADDR+U_PCB_CONTEXT+24 1002 lw s7, UADDR+U_PCB_CONTEXT+28 1003 lw sp, UADDR+U_PCB_CONTEXT+32 1004 lw s8, UADDR+U_PCB_CONTEXT+36 1005 mtc0 v0, MACH_COP_0_STATUS_REG 1006 j ra 1007 li v0, 1 # possible return to 'savectx()' 1008 .set reorder 1009END(cpu_switch) 1010 1011/* 1012 * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to 1013 * user text space. 1014 * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to 1015 * user data space. 1016 */ 1017LEAF(fuword) 1018ALEAF(fuiword) 1019 li v0, FSWBERR 1020 blt a0, zero, fswberr # make sure address is in user space 1021 sw v0, UADDR+U_PCB_ONFAULT 1022 lw v0, 0(a0) # fetch word 1023 sw zero, UADDR+U_PCB_ONFAULT 1024 j ra 1025END(fuword) 1026 1027LEAF(fusword) 1028ALEAF(fuisword) 1029 li v0, FSWBERR 1030 blt a0, zero, fswberr # make sure address is in user space 1031 sw v0, UADDR+U_PCB_ONFAULT 1032 lhu v0, 0(a0) # fetch short 1033 sw zero, UADDR+U_PCB_ONFAULT 1034 j ra 1035END(fusword) 1036 1037LEAF(fubyte) 1038ALEAF(fuibyte) 1039 li v0, FSWBERR 1040 blt a0, zero, fswberr # make sure address is in user space 1041 sw v0, UADDR+U_PCB_ONFAULT 1042 lbu v0, 0(a0) # fetch byte 1043 sw zero, UADDR+U_PCB_ONFAULT 1044 j ra 1045END(fubyte) 1046 1047LEAF(suword) 1048 li v0, FSWBERR 1049 blt a0, zero, fswberr # make sure address is in user space 1050 sw v0, UADDR+U_PCB_ONFAULT 1051 sw a1, 0(a0) # store word 1052 sw zero, UADDR+U_PCB_ONFAULT 1053 move v0, zero 1054 j ra 1055END(suword) 1056 1057/* 1058 * Have to flush instruction cache afterwards. 1059 */ 1060LEAF(suiword) 1061 li v0, FSWBERR 1062 blt a0, zero, fswberr # make sure address is in user space 1063 sw v0, UADDR+U_PCB_ONFAULT 1064 sw a1, 0(a0) # store word 1065 sw zero, UADDR+U_PCB_ONFAULT 1066 move v0, zero 1067 li a1, 4 # size of word 1068 b MachFlushICache # NOTE: this should not clobber v0! 1069END(suiword) 1070 1071/* 1072 * Will have to flush the instruction cache if byte merging is done in hardware. 1073 */ 1074LEAF(susword) 1075ALEAF(suisword) 1076 li v0, FSWBERR 1077 blt a0, zero, fswberr # make sure address is in user space 1078 sw v0, UADDR+U_PCB_ONFAULT 1079 sh a1, 0(a0) # store short 1080 sw zero, UADDR+U_PCB_ONFAULT 1081 move v0, zero 1082 j ra 1083END(susword) 1084 1085LEAF(subyte) 1086ALEAF(suibyte) 1087 li v0, FSWBERR 1088 blt a0, zero, fswberr # make sure address is in user space 1089 sw v0, UADDR+U_PCB_ONFAULT 1090 sb a1, 0(a0) # store byte 1091 sw zero, UADDR+U_PCB_ONFAULT 1092 move v0, zero 1093 j ra 1094END(subyte) 1095 1096LEAF(fswberr) 1097 li v0, -1 1098 j ra 1099END(fswberr) 1100 1101/* 1102 * fuswintr and suswintr are just like fusword and susword except that if 1103 * the page is not in memory or would cause a trap, then we return an error. 1104 * The important thing is to prevent sleep() and switching. 1105 */ 1106LEAF(fuswintr) 1107 li v0, FSWINTRBERR 1108 blt a0, zero, fswintrberr # make sure address is in user space 1109 sw v0, UADDR+U_PCB_ONFAULT 1110 lhu v0, 0(a0) # fetch short 1111 sw zero, UADDR+U_PCB_ONFAULT 1112 j ra 1113END(fuswintr) 1114 1115LEAF(suswintr) 1116 li v0, FSWINTRBERR 1117 blt a0, zero, fswintrberr # make sure address is in user space 1118 sw v0, UADDR+U_PCB_ONFAULT 1119 sh a1, 0(a0) # store short 1120 sw zero, UADDR+U_PCB_ONFAULT 1121 move v0, zero 1122 j ra 1123END(suswintr) 1124 1125LEAF(fswintrberr) 1126 li v0, -1 1127 j ra 1128END(fswintrberr) 1129 1130/* 1131 * Insert 'p' after 'q'. 1132 * _insque(p, q) 1133 * caddr_t p, q; 1134 */ 1135LEAF(_insque) 1136 lw v0, 0(a1) # v0 = q->next 1137 sw a1, 4(a0) # p->prev = q 1138 sw v0, 0(a0) # p->next = q->next 1139 sw a0, 4(v0) # q->next->prev = p 1140 sw a0, 0(a1) # q->next = p 1141 j ra 1142END(_insque) 1143 1144/* 1145 * Remove item 'p' from queue. 1146 * _remque(p) 1147 * caddr_t p; 1148 */ 1149LEAF(_remque) 1150 lw v0, 0(a0) # v0 = p->next 1151 lw v1, 4(a0) # v1 = p->prev 1152 sw v0, 0(v1) # p->prev->next = p->next 1153 sw v1, 4(v0) # p->next->prev = p->prev 1154 j ra 1155END(_remque) 1156 1157/* 1158 * This code is copied to the UTLB exception vector address to 1159 * handle user level TLB translation misses. 1160 * NOTE: This code must be relocatable!!! 1161 */ 1162 .globl MachUTLBMiss 1163MachUTLBMiss: 1164 .set noat 1165 .set noreorder 1166 mfc0 k0, MACH_COP_0_BAD_VADDR # get the virtual address 1167 lw k1, UADDR+U_PCB_SEGTAB # get the current segment table 1168 bltz k0, 1f # R3000 chip bug 1169 srl k0, k0, SEGSHIFT # compute segment table index 1170 sll k0, k0, 2 1171 addu k1, k1, k0 1172 mfc0 k0, MACH_COP_0_BAD_VADDR # get the virtual address 1173 lw k1, 0(k1) # get pointer to segment map 1174 srl k0, k0, PGSHIFT - 2 # compute segment map index 1175 andi k0, k0, (NPTEPG - 1) << 2 1176 beq k1, zero, 2f # invalid segment map 1177 addu k1, k1, k0 # index into segment map 1178 lw k0, 0(k1) # get page PTE 1179 nop 1180 beq k0, zero, 2f # dont load invalid entries 1181 mtc0 k0, MACH_COP_0_TLB_LOW 1182 mfc0 k1, MACH_COP_0_EXC_PC # get return address 1183 tlbwr # update TLB 1184 j k1 1185 rfe 11861: 1187 mfc0 k1, MACH_COP_0_EXC_PC # get return address 1188 nop 1189 j k1 1190 rfe 11912: 1192 j SlowFault # handle the rest 1193 nop 1194 .set reorder 1195 .set at 1196 .globl MachUTLBMissEnd 1197MachUTLBMissEnd: 1198 1199/* 1200 * This code is copied to the general exception vector address to 1201 * handle all execptions except RESET and UTLBMiss. 1202 * NOTE: This code must be relocatable!!! 1203 */ 1204 .globl MachException 1205MachException: 1206/* 1207 * Find out what mode we came from and jump to the proper handler. 1208 */ 1209 .set noat 1210 .set noreorder 1211 mfc0 k0, MACH_COP_0_STATUS_REG # Get the status register 1212 mfc0 k1, MACH_COP_0_CAUSE_REG # Get the cause register value. 1213 and k0, k0, MACH_SR_KU_PREV # test for user mode 1214 sll k0, k0, 3 # shift user bit for cause index 1215 and k1, k1, MACH_CR_EXC_CODE # Mask out the cause bits. 1216 or k1, k1, k0 # change index to user table 12171: 1218 la k0, machExceptionTable # get base of the jump table 1219 addu k0, k0, k1 # Get the address of the 1220 # function entry. Note that 1221 # the cause is already 1222 # shifted left by 2 bits so 1223 # we don't have to shift. 1224 lw k0, 0(k0) # Get the function address 1225 nop 1226 j k0 # Jump to the function. 1227 nop 1228 .set reorder 1229 .set at 1230 .globl MachExceptionEnd 1231MachExceptionEnd: 1232 1233/* 1234 * We couldn't find a TLB entry. 1235 * Find out what mode we came from and call the appropriate handler. 1236 */ 1237SlowFault: 1238 .set noat 1239 .set noreorder 1240 mfc0 k0, MACH_COP_0_STATUS_REG 1241 nop 1242 and k0, k0, MACH_SR_KU_PREV 1243 bne k0, zero, MachUserGenException 1244 nop 1245 .set reorder 1246 .set at 1247/* 1248 * Fall though ... 1249 */ 1250 1251/*---------------------------------------------------------------------------- 1252 * 1253 * MachKernGenException -- 1254 * 1255 * Handle an exception from kernel mode. 1256 * 1257 * Results: 1258 * None. 1259 * 1260 * Side effects: 1261 * None. 1262 * 1263 *---------------------------------------------------------------------------- 1264 */ 1265 1266/* 1267 * The kernel exception stack contains 18 saved general registers, 1268 * the status register and the multiply lo and high registers. 1269 * In addition, we set this up for linkage conventions. 1270 */ 1271#define KERN_REG_SIZE (18 * 4) 1272#define KERN_REG_OFFSET (STAND_FRAME_SIZE) 1273#define KERN_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) 1274#define KERN_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) 1275#define KERN_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) 1276#define KERN_EXC_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) 1277 1278NNON_LEAF(MachKernGenException, KERN_EXC_FRAME_SIZE, ra) 1279 .set noreorder 1280 .set noat 1281#ifdef KADB 1282 la k0, kdbpcb # save registers for kadb 1283 sw s0, (S0 * 4)(k0) 1284 sw s1, (S1 * 4)(k0) 1285 sw s2, (S2 * 4)(k0) 1286 sw s3, (S3 * 4)(k0) 1287 sw s4, (S4 * 4)(k0) 1288 sw s5, (S5 * 4)(k0) 1289 sw s6, (S6 * 4)(k0) 1290 sw s7, (S7 * 4)(k0) 1291 sw s8, (S8 * 4)(k0) 1292 sw gp, (GP * 4)(k0) 1293 sw sp, (SP * 4)(k0) 1294#endif 1295 subu sp, sp, KERN_EXC_FRAME_SIZE 1296 .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE) 1297/* 1298 * Save the relevant kernel registers onto the stack. 1299 * We don't need to save s0 - s8, sp and gp because 1300 * the compiler does it for us. 1301 */ 1302 sw AT, KERN_REG_OFFSET + 0(sp) 1303 sw v0, KERN_REG_OFFSET + 4(sp) 1304 sw v1, KERN_REG_OFFSET + 8(sp) 1305 sw a0, KERN_REG_OFFSET + 12(sp) 1306 mflo v0 1307 mfhi v1 1308 sw a1, KERN_REG_OFFSET + 16(sp) 1309 sw a2, KERN_REG_OFFSET + 20(sp) 1310 sw a3, KERN_REG_OFFSET + 24(sp) 1311 sw t0, KERN_REG_OFFSET + 28(sp) 1312 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1313 sw t1, KERN_REG_OFFSET + 32(sp) 1314 sw t2, KERN_REG_OFFSET + 36(sp) 1315 sw t3, KERN_REG_OFFSET + 40(sp) 1316 sw t4, KERN_REG_OFFSET + 44(sp) 1317 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1318 sw t5, KERN_REG_OFFSET + 48(sp) 1319 sw t6, KERN_REG_OFFSET + 52(sp) 1320 sw t7, KERN_REG_OFFSET + 56(sp) 1321 sw t8, KERN_REG_OFFSET + 60(sp) 1322 mfc0 a2, MACH_COP_0_BAD_VADDR # Third arg is the fault addr. 1323 sw t9, KERN_REG_OFFSET + 64(sp) 1324 sw ra, KERN_REG_OFFSET + 68(sp) 1325 sw v0, KERN_MULT_LO_OFFSET(sp) 1326 sw v1, KERN_MULT_HI_OFFSET(sp) 1327 mfc0 a3, MACH_COP_0_EXC_PC # Fourth arg is the pc. 1328 sw a0, KERN_SR_OFFSET(sp) 1329/* 1330 * Call the exception handler. 1331 */ 1332 jal trap 1333 sw a3, STAND_RA_OFFSET(sp) # for debugging 1334/* 1335 * Restore registers and return from the exception. 1336 * v0 contains the return address. 1337 */ 1338 lw a0, KERN_SR_OFFSET(sp) 1339 lw t0, KERN_MULT_LO_OFFSET(sp) 1340 lw t1, KERN_MULT_HI_OFFSET(sp) 1341 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1342 mtlo t0 1343 mthi t1 1344 move k0, v0 1345 lw AT, KERN_REG_OFFSET + 0(sp) 1346 lw v0, KERN_REG_OFFSET + 4(sp) 1347 lw v1, KERN_REG_OFFSET + 8(sp) 1348 lw a0, KERN_REG_OFFSET + 12(sp) 1349 lw a1, KERN_REG_OFFSET + 16(sp) 1350 lw a2, KERN_REG_OFFSET + 20(sp) 1351 lw a3, KERN_REG_OFFSET + 24(sp) 1352 lw t0, KERN_REG_OFFSET + 28(sp) 1353 lw t1, KERN_REG_OFFSET + 32(sp) 1354 lw t2, KERN_REG_OFFSET + 36(sp) 1355 lw t3, KERN_REG_OFFSET + 40(sp) 1356 lw t4, KERN_REG_OFFSET + 44(sp) 1357 lw t5, KERN_REG_OFFSET + 48(sp) 1358 lw t6, KERN_REG_OFFSET + 52(sp) 1359 lw t7, KERN_REG_OFFSET + 56(sp) 1360 lw t8, KERN_REG_OFFSET + 60(sp) 1361 lw t9, KERN_REG_OFFSET + 64(sp) 1362 lw ra, KERN_REG_OFFSET + 68(sp) 1363 addu sp, sp, KERN_EXC_FRAME_SIZE 1364 j k0 # Now return from the 1365 rfe # exception. 1366 .set at 1367 .set reorder 1368END(MachKernGenException) 1369 .globl MachKernGenExceptionEnd 1370MachKernGenExceptionEnd: 1371 1372/*---------------------------------------------------------------------------- 1373 * 1374 * MachUserGenException -- 1375 * 1376 * Handle an exception from user mode. 1377 * 1378 * Results: 1379 * None. 1380 * 1381 * Side effects: 1382 * None. 1383 * 1384 *---------------------------------------------------------------------------- 1385 */ 1386NNON_LEAF(MachUserGenException, STAND_FRAME_SIZE, ra) 1387 .set noreorder 1388 .set noat 1389 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 1390/* 1391 * Save all of the registers except for the kernel temporaries in u.u_pcb. 1392 */ 1393 sw AT, UADDR+U_PCB_REGS+(AST * 4) 1394 sw v0, UADDR+U_PCB_REGS+(V0 * 4) 1395 sw v1, UADDR+U_PCB_REGS+(V1 * 4) 1396 sw a0, UADDR+U_PCB_REGS+(A0 * 4) 1397 mflo v0 1398 sw a1, UADDR+U_PCB_REGS+(A1 * 4) 1399 sw a2, UADDR+U_PCB_REGS+(A2 * 4) 1400 sw a3, UADDR+U_PCB_REGS+(A3 * 4) 1401 sw t0, UADDR+U_PCB_REGS+(T0 * 4) 1402 mfhi v1 1403 sw t1, UADDR+U_PCB_REGS+(T1 * 4) 1404 sw t2, UADDR+U_PCB_REGS+(T2 * 4) 1405 sw t3, UADDR+U_PCB_REGS+(T3 * 4) 1406 sw t4, UADDR+U_PCB_REGS+(T4 * 4) 1407 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1408 sw t5, UADDR+U_PCB_REGS+(T5 * 4) 1409 sw t6, UADDR+U_PCB_REGS+(T6 * 4) 1410 sw t7, UADDR+U_PCB_REGS+(T7 * 4) 1411 sw s0, UADDR+U_PCB_REGS+(S0 * 4) 1412 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1413 sw s1, UADDR+U_PCB_REGS+(S1 * 4) 1414 sw s2, UADDR+U_PCB_REGS+(S2 * 4) 1415 sw s3, UADDR+U_PCB_REGS+(S3 * 4) 1416 sw s4, UADDR+U_PCB_REGS+(S4 * 4) 1417 mfc0 a2, MACH_COP_0_BAD_VADDR # Third arg is the fault addr 1418 sw s5, UADDR+U_PCB_REGS+(S5 * 4) 1419 sw s6, UADDR+U_PCB_REGS+(S6 * 4) 1420 sw s7, UADDR+U_PCB_REGS+(S7 * 4) 1421 sw t8, UADDR+U_PCB_REGS+(T8 * 4) 1422 mfc0 a3, MACH_COP_0_EXC_PC # Fourth arg is the pc. 1423 sw t9, UADDR+U_PCB_REGS+(T9 * 4) 1424 sw gp, UADDR+U_PCB_REGS+(GP * 4) 1425 sw sp, UADDR+U_PCB_REGS+(SP * 4) 1426 sw s8, UADDR+U_PCB_REGS+(S8 * 4) 1427 li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP 1428 sw ra, UADDR+U_PCB_REGS+(RA * 4) 1429 sw v0, UADDR+U_PCB_REGS+(MULLO * 4) 1430 sw v1, UADDR+U_PCB_REGS+(MULHI * 4) 1431 sw a0, UADDR+U_PCB_REGS+(SR * 4) 1432 la gp, _gp # switch to kernel GP 1433 sw a3, UADDR+U_PCB_REGS+(PC * 4) 1434 sw a3, STAND_RA_OFFSET(sp) # for debugging 1435 and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU. 1436/* 1437 * Call the exception handler. 1438 */ 1439 jal trap 1440 mtc0 t0, MACH_COP_0_STATUS_REG 1441/* 1442 * Restore user registers and return. NOTE: interrupts are enabled. 1443 */ 1444 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1445 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1446 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1447 mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts 1448 mtlo t0 1449 mthi t1 1450 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1451 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1452 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1453 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1454 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1455 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1456 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1457 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1458 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1459 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1460 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1461 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1462 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1463 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1464 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1465 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1466 lw s0, UADDR+U_PCB_REGS+(S0 * 4) 1467 lw s1, UADDR+U_PCB_REGS+(S1 * 4) 1468 lw s2, UADDR+U_PCB_REGS+(S2 * 4) 1469 lw s3, UADDR+U_PCB_REGS+(S3 * 4) 1470 lw s4, UADDR+U_PCB_REGS+(S4 * 4) 1471 lw s5, UADDR+U_PCB_REGS+(S5 * 4) 1472 lw s6, UADDR+U_PCB_REGS+(S6 * 4) 1473 lw s7, UADDR+U_PCB_REGS+(S7 * 4) 1474 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1475 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1476 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1477 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1478 lw s8, UADDR+U_PCB_REGS+(S8 * 4) 1479 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1480 j k0 1481 rfe 1482 .set at 1483 .set reorder 1484END(MachUserGenException) 1485 1486/*---------------------------------------------------------------------------- 1487 * 1488 * MachKernIntr -- 1489 * 1490 * Handle an interrupt from kernel mode. 1491 * Interrupts use the standard kernel stack. 1492 * switch_exit sets up a kernel stack after exit so interrupts won't fail. 1493 * 1494 * Results: 1495 * None. 1496 * 1497 * Side effects: 1498 * None. 1499 * 1500 *---------------------------------------------------------------------------- 1501 */ 1502#define KINTR_REG_OFFSET (STAND_FRAME_SIZE) 1503#define KINTR_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) 1504#define KINTR_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) 1505#define KINTR_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) 1506#define KINTR_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) 1507 1508NNON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra) 1509 .set noreorder 1510 .set noat 1511 subu sp, sp, KINTR_FRAME_SIZE # allocate stack frame 1512 .mask 0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE) 1513/* 1514 * Save the relevant kernel registers onto the stack. 1515 * We don't need to save s0 - s8, sp and gp because 1516 * the compiler does it for us. 1517 */ 1518 sw AT, KINTR_REG_OFFSET + 0(sp) 1519 sw v0, KINTR_REG_OFFSET + 4(sp) 1520 sw v1, KINTR_REG_OFFSET + 8(sp) 1521 sw a0, KINTR_REG_OFFSET + 12(sp) 1522 mflo v0 1523 mfhi v1 1524 sw a1, KINTR_REG_OFFSET + 16(sp) 1525 sw a2, KINTR_REG_OFFSET + 20(sp) 1526 sw a3, KINTR_REG_OFFSET + 24(sp) 1527 sw t0, KINTR_REG_OFFSET + 28(sp) 1528 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1529 sw t1, KINTR_REG_OFFSET + 32(sp) 1530 sw t2, KINTR_REG_OFFSET + 36(sp) 1531 sw t3, KINTR_REG_OFFSET + 40(sp) 1532 sw t4, KINTR_REG_OFFSET + 44(sp) 1533 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1534 sw t5, KINTR_REG_OFFSET + 48(sp) 1535 sw t6, KINTR_REG_OFFSET + 52(sp) 1536 sw t7, KINTR_REG_OFFSET + 56(sp) 1537 sw t8, KINTR_REG_OFFSET + 60(sp) 1538 mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc. 1539 sw t9, KINTR_REG_OFFSET + 64(sp) 1540 sw ra, KINTR_REG_OFFSET + 68(sp) 1541 sw v0, KINTR_MULT_LO_OFFSET(sp) 1542 sw v1, KINTR_MULT_HI_OFFSET(sp) 1543 sw a0, KINTR_SR_OFFSET(sp) 1544/* 1545 * Call the interrupt handler. 1546 */ 1547 jal interrupt 1548 sw a2, STAND_RA_OFFSET(sp) # for debugging 1549/* 1550 * Restore registers and return from the interrupt. 1551 */ 1552 lw a0, KINTR_SR_OFFSET(sp) 1553 lw t0, KINTR_MULT_LO_OFFSET(sp) 1554 lw t1, KINTR_MULT_HI_OFFSET(sp) 1555 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1556 mtlo t0 1557 mthi t1 1558 lw k0, STAND_RA_OFFSET(sp) 1559 lw AT, KINTR_REG_OFFSET + 0(sp) 1560 lw v0, KINTR_REG_OFFSET + 4(sp) 1561 lw v1, KINTR_REG_OFFSET + 8(sp) 1562 lw a0, KINTR_REG_OFFSET + 12(sp) 1563 lw a1, KINTR_REG_OFFSET + 16(sp) 1564 lw a2, KINTR_REG_OFFSET + 20(sp) 1565 lw a3, KINTR_REG_OFFSET + 24(sp) 1566 lw t0, KINTR_REG_OFFSET + 28(sp) 1567 lw t1, KINTR_REG_OFFSET + 32(sp) 1568 lw t2, KINTR_REG_OFFSET + 36(sp) 1569 lw t3, KINTR_REG_OFFSET + 40(sp) 1570 lw t4, KINTR_REG_OFFSET + 44(sp) 1571 lw t5, KINTR_REG_OFFSET + 48(sp) 1572 lw t6, KINTR_REG_OFFSET + 52(sp) 1573 lw t7, KINTR_REG_OFFSET + 56(sp) 1574 lw t8, KINTR_REG_OFFSET + 60(sp) 1575 lw t9, KINTR_REG_OFFSET + 64(sp) 1576 lw ra, KINTR_REG_OFFSET + 68(sp) 1577 addu sp, sp, KINTR_FRAME_SIZE 1578 j k0 # Now return from the 1579 rfe # interrupt. 1580 .set at 1581 .set reorder 1582END(MachKernIntr) 1583 1584/*---------------------------------------------------------------------------- 1585 * 1586 * MachUserIntr -- 1587 * 1588 * Handle an interrupt from user mode. 1589 * Note: we save minimal state in the u.u_pcb struct and use the standard 1590 * kernel stack since there has to be a u page if we came from user mode. 1591 * If there is a pending software interrupt, then save the remaining state 1592 * and call softintr(). This is all because if we call mi_switch() inside 1593 * interrupt(), not all the user registers have been saved in u.u_pcb. 1594 * 1595 * Results: 1596 * None. 1597 * 1598 * Side effects: 1599 * None. 1600 * 1601 *---------------------------------------------------------------------------- 1602 */ 1603NNON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra) 1604 .set noreorder 1605 .set noat 1606 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 1607/* 1608 * Save the relevant user registers into the u.u_pcb struct. 1609 * We don't need to save s0 - s8 because 1610 * the compiler does it for us. 1611 */ 1612 sw AT, UADDR+U_PCB_REGS+(AST * 4) 1613 sw v0, UADDR+U_PCB_REGS+(V0 * 4) 1614 sw v1, UADDR+U_PCB_REGS+(V1 * 4) 1615 sw a0, UADDR+U_PCB_REGS+(A0 * 4) 1616 mflo v0 1617 mfhi v1 1618 sw a1, UADDR+U_PCB_REGS+(A1 * 4) 1619 sw a2, UADDR+U_PCB_REGS+(A2 * 4) 1620 sw a3, UADDR+U_PCB_REGS+(A3 * 4) 1621 sw t0, UADDR+U_PCB_REGS+(T0 * 4) 1622 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1623 sw t1, UADDR+U_PCB_REGS+(T1 * 4) 1624 sw t2, UADDR+U_PCB_REGS+(T2 * 4) 1625 sw t3, UADDR+U_PCB_REGS+(T3 * 4) 1626 sw t4, UADDR+U_PCB_REGS+(T4 * 4) 1627 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1628 sw t5, UADDR+U_PCB_REGS+(T5 * 4) 1629 sw t6, UADDR+U_PCB_REGS+(T6 * 4) 1630 sw t7, UADDR+U_PCB_REGS+(T7 * 4) 1631 sw t8, UADDR+U_PCB_REGS+(T8 * 4) 1632 mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc. 1633 sw t9, UADDR+U_PCB_REGS+(T9 * 4) 1634 sw gp, UADDR+U_PCB_REGS+(GP * 4) 1635 sw sp, UADDR+U_PCB_REGS+(SP * 4) 1636 sw ra, UADDR+U_PCB_REGS+(RA * 4) 1637 li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP 1638 sw v0, UADDR+U_PCB_REGS+(MULLO * 4) 1639 sw v1, UADDR+U_PCB_REGS+(MULHI * 4) 1640 sw a0, UADDR+U_PCB_REGS+(SR * 4) 1641 sw a2, UADDR+U_PCB_REGS+(PC * 4) 1642 la gp, _gp # switch to kernel GP 1643 and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU. 1644 mtc0 t0, MACH_COP_0_STATUS_REG 1645/* 1646 * Call the interrupt handler. 1647 */ 1648 jal interrupt 1649 sw a2, STAND_RA_OFFSET(sp) # for debugging 1650/* 1651 * Restore registers and return from the interrupt. 1652 */ 1653 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1654 lw v0, astpending # any pending interrupts? 1655 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1656 bne v0, zero, 1f # don't restore, call softintr 1657 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1658 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1659 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1660 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1661 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1662 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1663 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1664 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1665 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1666 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1667 mtlo t0 1668 mthi t1 1669 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1670 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1671 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1672 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1673 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1674 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1675 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1676 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1677 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1678 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1679 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1680 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1681 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1682 j k0 # Now return from the 1683 rfe # interrupt. 1684 16851: 1686/* 1687 * We have pending software interrupts; save remaining user state in u.u_pcb. 1688 */ 1689 sw s0, UADDR+U_PCB_REGS+(S0 * 4) 1690 sw s1, UADDR+U_PCB_REGS+(S1 * 4) 1691 sw s2, UADDR+U_PCB_REGS+(S2 * 4) 1692 sw s3, UADDR+U_PCB_REGS+(S3 * 4) 1693 sw s4, UADDR+U_PCB_REGS+(S4 * 4) 1694 sw s5, UADDR+U_PCB_REGS+(S5 * 4) 1695 sw s6, UADDR+U_PCB_REGS+(S6 * 4) 1696 sw s7, UADDR+U_PCB_REGS+(S7 * 4) 1697 sw s8, UADDR+U_PCB_REGS+(S8 * 4) 1698 li t0, MACH_HARD_INT_MASK | MACH_SR_INT_ENA_CUR 1699/* 1700 * Call the software interrupt handler. 1701 */ 1702 jal softintr 1703 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts (spl0) 1704/* 1705 * Restore user registers and return. NOTE: interrupts are enabled. 1706 */ 1707 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1708 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1709 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1710 mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts 1711 mtlo t0 1712 mthi t1 1713 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1714 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1715 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1716 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1717 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1718 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1719 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1720 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1721 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1722 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1723 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1724 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1725 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1726 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1727 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1728 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1729 lw s0, UADDR+U_PCB_REGS+(S0 * 4) 1730 lw s1, UADDR+U_PCB_REGS+(S1 * 4) 1731 lw s2, UADDR+U_PCB_REGS+(S2 * 4) 1732 lw s3, UADDR+U_PCB_REGS+(S3 * 4) 1733 lw s4, UADDR+U_PCB_REGS+(S4 * 4) 1734 lw s5, UADDR+U_PCB_REGS+(S5 * 4) 1735 lw s6, UADDR+U_PCB_REGS+(S6 * 4) 1736 lw s7, UADDR+U_PCB_REGS+(S7 * 4) 1737 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1738 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1739 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1740 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1741 lw s8, UADDR+U_PCB_REGS+(S8 * 4) 1742 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1743 j k0 1744 rfe 1745 .set at 1746 .set reorder 1747END(MachUserIntr) 1748 1749#if 0 1750/*---------------------------------------------------------------------------- 1751 * 1752 * MachTLBModException -- 1753 * 1754 * Handle a TLB modified exception. 1755 * The BaddVAddr, Context, and EntryHi registers contain the failed 1756 * virtual address. 1757 * 1758 * Results: 1759 * None. 1760 * 1761 * Side effects: 1762 * None. 1763 * 1764 *---------------------------------------------------------------------------- 1765 */ 1766#ifdef NOTDEF 1767NLEAF(MachTLBModException) 1768 .set noreorder 1769 .set noat 1770 tlbp # find the TLB entry 1771 mfc0 k0, MACH_COP_0_TLB_LOW # get the physical address 1772 mfc0 k1, MACH_COP_0_TLB_INDEX # check to be sure its valid 1773 or k0, k0, VMMACH_TLB_MOD_BIT # update TLB 1774 blt k1, zero, 4f # not found!!! 1775 mtc0 k0, MACH_COP_0_TLB_LOW 1776 li k1, MACH_CACHED_MEMORY_ADDR 1777 subu k0, k0, k1 1778 srl k0, k0, VMMACH_TLB_PHYS_PAGE_SHIFT 1779 la k1, pmap_attributes 1780 add k0, k0, k1 1781 lbu k1, 0(k0) # fetch old value 1782 nop 1783 or k1, k1, 1 # set modified bit 1784 sb k1, 0(k0) # save new value 1785 mfc0 k0, MACH_COP_0_EXC_PC # get return address 1786 nop 1787 j k0 1788 rfe 17894: 1790 break 0 # panic 1791 .set reorder 1792 .set at 1793END(MachTLBModException) 1794#endif /* NOTDEF */ 1795#endif 1796 1797/*---------------------------------------------------------------------------- 1798 * 1799 * MachTLBMissException -- 1800 * 1801 * Handle a TLB miss exception from kernel mode. 1802 * The BaddVAddr, Context, and EntryHi registers contain the failed 1803 * virtual address. 1804 * 1805 * Results: 1806 * None. 1807 * 1808 * Side effects: 1809 * None. 1810 * 1811 *---------------------------------------------------------------------------- 1812 */ 1813NLEAF(MachTLBMissException) 1814 .set noreorder 1815 .set noat 1816 mfc0 k0, MACH_COP_0_BAD_VADDR # get the fault address 1817 li k1, VM_MIN_KERNEL_ADDRESS # compute index 1818 subu k0, k0, k1 1819 lw k1, Sysmapsize # index within range? 1820 srl k0, k0, PGSHIFT 1821 sltu k1, k0, k1 1822 beq k1, zero, 1f # No. check for valid stack 1823 nop 1824 lw k1, Sysmap 1825 sll k0, k0, 2 # compute offset from index 1826 addu k1, k1, k0 1827 lw k0, 0(k1) # get PTE entry 1828 mfc0 k1, MACH_COP_0_EXC_PC # get return address 1829 mtc0 k0, MACH_COP_0_TLB_LOW # save PTE entry 1830 and k0, k0, PG_V # check for valid entry 1831 beq k0, zero, MachKernGenException # PTE invalid 1832 nop 1833 tlbwr # update TLB 1834 j k1 1835 rfe 1836 18371: 1838 subu k0, sp, UADDR + 0x200 # check to see if we have a 1839 sltiu k0, UPAGES*NBPG - 0x200 # valid kernel stack 1840 bne k0, zero, MachKernGenException # Go panic 1841 nop 1842 1843 la a0, start - START_FRAME - 8 # set sp to a valid place 1844 sw sp, 24(a0) 1845 move sp, a0 1846 la a0, 1f 1847 mfc0 a2, MACH_COP_0_STATUS_REG 1848 mfc0 a3, MACH_COP_0_CAUSE_REG 1849 mfc0 a1, MACH_COP_0_EXC_PC 1850 sw a2, 16(sp) 1851 sw a3, 20(sp) 1852 sw sp, 24(sp) 1853 move a2, ra 1854 jal printf 1855 mfc0 a3, MACH_COP_0_BAD_VADDR 1856 .data 18571: 1858 .asciiz "ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n" 1859 .text 1860 1861 la sp, start - START_FRAME # set sp to a valid place 1862 PANIC("kernel stack overflow") 1863 .set reorder 1864 .set at 1865END(MachTLBMissException) 1866 1867/* 1868 * Set/clear software interrupt routines. 1869 */ 1870 1871LEAF(setsoftclock) 1872 .set noreorder 1873 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1874 nop 1875 or v0, v0, MACH_SOFT_INT_MASK_0 # set soft clock interrupt 1876 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1877 j ra 1878 nop 1879 .set reorder 1880END(setsoftclock) 1881 1882LEAF(clearsoftclock) 1883 .set noreorder 1884 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1885 nop 1886 and v0, v0, ~MACH_SOFT_INT_MASK_0 # clear soft clock interrupt 1887 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1888 j ra 1889 nop 1890 .set reorder 1891END(clearsoftclock) 1892 1893LEAF(setsoftnet) 1894 .set noreorder 1895 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1896 nop 1897 or v0, v0, MACH_SOFT_INT_MASK_1 # set soft net interrupt 1898 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1899 j ra 1900 nop 1901 .set reorder 1902END(setsoftnet) 1903 1904LEAF(clearsoftnet) 1905 .set noreorder 1906 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1907 nop 1908 and v0, v0, ~MACH_SOFT_INT_MASK_1 # clear soft net interrupt 1909 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1910 j ra 1911 nop 1912 .set reorder 1913END(clearsoftnet) 1914 1915/* 1916 * Set/change interrupt priority routines. 1917 */ 1918#ifdef NOTDEF 1919LEAF(MachEnableIntr) 1920 .set noreorder 1921 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1922 nop 1923 or v0, v0, MACH_SR_INT_ENA_CUR 1924 mtc0 v0, MACH_COP_0_STATUS_REG # enable all interrupts 1925 j ra 1926 nop 1927 .set reorder 1928END(MachEnableIntr) 1929#endif /* NOTDEF */ 1930 1931#include <sys/cdefs.h> 1932 1933#define SPL(level) \ 1934LEAF(__CONCAT(spl,level)); \ 1935 .set noreorder; \ 1936 mfc0 v0, MACH_COP_0_STATUS_REG; \ 1937 li t0, __CONCAT(MACH_SPL_MASK_,level) | MACH_SR_INT_ENA_CUR; \ 1938 and t0, t0, v0; \ 1939 j ra; \ 1940 mtc0 t0, MACH_COP_0_STATUS_REG; \ 1941 .set reorder; \ 1942END(__CONCAT(spl,level)) \ 1943 1944LEAF(spl0) 1945 .set noreorder 1946 mfc0 v0, MACH_COP_0_STATUS_REG 1947 li t0, MACH_SPL_MASK_0 | MACH_SR_INT_ENA_CUR 1948 j ra 1949 mtc0 t0, MACH_COP_0_STATUS_REG 1950 .set reorder 1951END(spl0) 1952 1953SPL(1); SPL(2); SPL(3); SPL(4); SPL(5); SPL(6); SPL(7) 1954 1955LEAF(spl8) 1956ALEAF(splhigh) 1957ALEAF(_splhigh) 1958 .set noreorder 1959 mfc0 v0, MACH_COP_0_STATUS_REG 1960 li t0, MACH_SPL_MASK_8 | MACH_SR_INT_ENA_CUR 1961 j ra 1962 mtc0 t0, MACH_COP_0_STATUS_REG 1963 .set reorder 1964END(spl8) 1965 1966/* 1967 * Restore saved interrupt mask. 1968 */ 1969LEAF(splx) 1970ALEAF(_splx) 1971 .set noreorder 1972 mfc0 v0, MACH_COP_0_STATUS_REG 1973 j ra 1974 mtc0 a0, MACH_COP_0_STATUS_REG 1975 .set reorder 1976END(splx) 1977 1978/*---------------------------------------------------------------------------- 1979 * 1980 * MachEmptyWriteBuffer -- 1981 * 1982 * Return when the write buffer is empty. 1983 * 1984 * MachEmptyWriteBuffer() 1985 * 1986 * Results: 1987 * None. 1988 * 1989 * Side effects: 1990 * None. 1991 * 1992 *---------------------------------------------------------------------------- 1993 */ 1994LEAF(MachEmptyWriteBuffer) 1995 .set noreorder 1996 nop 1997 nop 1998 nop 1999 nop 20001: bc0t 1b 2001 nop 2002 j ra 2003 nop 2004 .set reorder 2005END(MachEmptyWriteBuffer) 2006 2007/*-------------------------------------------------------------------------- 2008 * 2009 * MachTLBWriteIndexed -- 2010 * 2011 * Write the given entry into the TLB at the given index. 2012 * 2013 * MachTLBWriteIndexed(index, highEntry, lowEntry) 2014 * int index; 2015 * int highEntry; 2016 * int lowEntry; 2017 * 2018 * Results: 2019 * None. 2020 * 2021 * Side effects: 2022 * TLB entry set. 2023 * 2024 *-------------------------------------------------------------------------- 2025 */ 2026LEAF(MachTLBWriteIndexed) 2027 .set noreorder 2028 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2029 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2030 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID. 2031 2032 sll a0, a0, VMMACH_TLB_INDEX_SHIFT 2033 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index. 2034 mtc0 a1, MACH_COP_0_TLB_HI # Set up entry high. 2035 mtc0 a2, MACH_COP_0_TLB_LOW # Set up entry low. 2036 nop 2037 tlbwi # Write the TLB 2038 2039 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID. 2040 j ra 2041 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2042 .set reorder 2043END(MachTLBWriteIndexed) 2044 2045#if 0 2046/*-------------------------------------------------------------------------- 2047 * 2048 * MachTLBWriteRandom -- 2049 * 2050 * Write the given entry into the TLB at a random location. 2051 * 2052 * MachTLBWriteRandom(highEntry, lowEntry) 2053 * unsigned highEntry; 2054 * unsigned lowEntry; 2055 * 2056 * Results: 2057 * None. 2058 * 2059 * Side effects: 2060 * TLB entry set. 2061 * 2062 *-------------------------------------------------------------------------- 2063 */ 2064LEAF(MachTLBWriteRandom) 2065 .set noreorder 2066 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2067 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2068 mfc0 v0, MACH_COP_0_TLB_HI # Save the current PID. 2069 nop 2070 2071 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high. 2072 mtc0 a1, MACH_COP_0_TLB_LOW # Set up entry low. 2073 nop 2074 tlbwr # Write the TLB 2075 2076 mtc0 v0, MACH_COP_0_TLB_HI # Restore the PID. 2077 j ra 2078 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2079 .set reorder 2080END(MachTLBWriteRandom) 2081#endif 2082 2083/*-------------------------------------------------------------------------- 2084 * 2085 * MachSetPID -- 2086 * 2087 * Write the given pid into the TLB pid reg. 2088 * 2089 * MachSetPID(pid) 2090 * int pid; 2091 * 2092 * Results: 2093 * None. 2094 * 2095 * Side effects: 2096 * PID set in the entry hi register. 2097 * 2098 *-------------------------------------------------------------------------- 2099 */ 2100LEAF(MachSetPID) 2101 .set noreorder 2102 sll a0, a0, VMMACH_TLB_PID_SHIFT # put PID in right spot 2103 mtc0 a0, MACH_COP_0_TLB_HI # Write the hi reg value 2104 j ra 2105 nop 2106 .set reorder 2107END(MachSetPID) 2108 2109/*-------------------------------------------------------------------------- 2110 * 2111 * MachTLBFlush -- 2112 * 2113 * Flush the "random" entries from the TLB. 2114 * 2115 * MachTLBFlush() 2116 * 2117 * Results: 2118 * None. 2119 * 2120 * Side effects: 2121 * The TLB is flushed. 2122 * 2123 *-------------------------------------------------------------------------- 2124 */ 2125LEAF(MachTLBFlush) 2126 .set noreorder 2127 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2128 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2129 mfc0 t0, MACH_COP_0_TLB_HI # Save the PID 2130 li t1, MACH_CACHED_MEMORY_ADDR # invalid address 2131 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid 2132 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2133/* 2134 * Align the starting value (t1) and the upper bound (t2). 2135 */ 2136 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT 2137 li t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 21381: 2139 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register. 2140 addu t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT # Increment index. 2141 bne t1, t2, 1b 2142 tlbwi # Write the TLB entry. 2143 2144 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID 2145 j ra 2146 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2147 .set reorder 2148END(MachTLBFlush) 2149 2150#if 0 2151/*-------------------------------------------------------------------------- 2152 * 2153 * MachTLBFlushPID -- 2154 * 2155 * Flush all entries with the given PID from the TLB. 2156 * 2157 * MachTLBFlushPID(pid) 2158 * int pid; 2159 * 2160 * Results: 2161 * None. 2162 * 2163 * Side effects: 2164 * All entries corresponding to this PID are flushed. 2165 * 2166 *-------------------------------------------------------------------------- 2167 */ 2168LEAF(MachTLBFlushPID) 2169 .set noreorder 2170 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2171 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2172 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID 2173 sll a0, a0, VMMACH_TLB_PID_SHIFT # Align the pid to flush. 2174/* 2175 * Align the starting value (t1) and the upper bound (t2). 2176 */ 2177 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT 2178 li t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 2179 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register 21801: 2181 addu t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT # Increment index. 2182 tlbr # Read from the TLB 2183 mfc0 t4, MACH_COP_0_TLB_HI # Fetch the hi register. 2184 nop 2185 and t4, t4, VMMACH_TLB_PID # compare PID's 2186 bne t4, a0, 2f 2187 li v0, MACH_CACHED_MEMORY_ADDR # invalid address 2188 mtc0 v0, MACH_COP_0_TLB_HI # Mark entry high as invalid 2189 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2190 nop 2191 tlbwi # Write the entry. 21922: 2193 bne t1, t2, 1b 2194 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register 2195 2196 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2197 j ra 2198 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2199 .set reorder 2200END(MachTLBFlushPID) 2201#endif 2202 2203/*-------------------------------------------------------------------------- 2204 * 2205 * MachTLBFlushAddr -- 2206 * 2207 * Flush any TLB entries for the given address and TLB PID. 2208 * 2209 * MachTLBFlushAddr(highreg) 2210 * unsigned highreg; 2211 * 2212 * Results: 2213 * None. 2214 * 2215 * Side effects: 2216 * The process's page is flushed from the TLB. 2217 * 2218 *-------------------------------------------------------------------------- 2219 */ 2220LEAF(MachTLBFlushAddr) 2221 .set noreorder 2222 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2223 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2224 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2225 nop 2226 2227 mtc0 a0, MACH_COP_0_TLB_HI # look for addr & PID 2228 nop 2229 tlbp # Probe for the entry. 2230 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2231 li t1, MACH_CACHED_MEMORY_ADDR # Load invalid entry. 2232 bltz v0, 1f # index < 0 => !found 2233 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid 2234 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2235 nop 2236 tlbwi 22371: 2238 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2239 j ra 2240 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2241 .set reorder 2242END(MachTLBFlushAddr) 2243 2244/*-------------------------------------------------------------------------- 2245 * 2246 * MachTLBUpdate -- 2247 * 2248 * Update the TLB if highreg is found; otherwise, enter the data. 2249 * 2250 * MachTLBUpdate(highreg, lowreg) 2251 * unsigned highreg, lowreg; 2252 * 2253 * Results: 2254 * None. 2255 * 2256 * Side effects: 2257 * None. 2258 * 2259 *-------------------------------------------------------------------------- 2260 */ 2261LEAF(MachTLBUpdate) 2262 .set noreorder 2263 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2264 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2265 mfc0 t0, MACH_COP_0_TLB_HI # Save current PID 2266 nop # 2 cycles before intr disabled 2267 mtc0 a0, MACH_COP_0_TLB_HI # init high reg. 2268 nop 2269 tlbp # Probe for the entry. 2270 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2271 nop 2272 mtc0 a1, MACH_COP_0_TLB_LOW # init low reg. 2273 nop 2274 bltz v0, 1f # index < 0 => !found 2275 sra v0, v0, VMMACH_TLB_INDEX_SHIFT # convert index to regular num 2276 b 2f 2277 tlbwi # update slot found 22781: 2279 mtc0 a0, MACH_COP_0_TLB_HI # init high reg. 2280 nop 2281 tlbwr # enter into a random slot 22822: 2283 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2284 j ra 2285 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2286 .set reorder 2287END(MachTLBUpdate) 2288 2289#if defined(DEBUG) 2290/*-------------------------------------------------------------------------- 2291 * 2292 * MachTLBFind -- 2293 * 2294 * Search the TLB for the given entry. 2295 * 2296 * MachTLBFind(hi) 2297 * unsigned hi; 2298 * 2299 * Results: 2300 * Returns a value >= 0 if the entry was found (the index). 2301 * Returns a value < 0 if the entry was not found. 2302 * 2303 * Side effects: 2304 * tlbhi and tlblo will contain the TLB entry found. 2305 * 2306 *-------------------------------------------------------------------------- 2307 */ 2308 .comm tlbhi, 4 2309 .comm tlblo, 4 2310LEAF(MachTLBFind) 2311 .set noreorder 2312 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2313 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2314 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2315 nop 2316 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high. 2317 nop 2318 tlbp # Probe for the entry. 2319 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2320 nop 2321 bltz v0, 1f # not found 2322 nop 2323 tlbr # read TLB 2324 mfc0 t1, MACH_COP_0_TLB_HI # See what we got 2325 mfc0 t2, MACH_COP_0_TLB_LOW # See what we got 2326 sw t1, tlbhi 2327 sw t2, tlblo 2328 srl v0, v0, VMMACH_TLB_INDEX_SHIFT # convert index to regular num 23291: 2330 mtc0 t0, MACH_COP_0_TLB_HI # Restore current PID 2331 j ra 2332 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2333 .set reorder 2334END(MachTLBFind) 2335 2336/*-------------------------------------------------------------------------- 2337 * 2338 * MachTLBRead -- 2339 * 2340 * Read the TLB entry. 2341 * 2342 * MachTLBRead(entry) 2343 * unsigned entry; 2344 * 2345 * Results: 2346 * None. 2347 * 2348 * Side effects: 2349 * tlbhi and tlblo will contain the TLB entry found. 2350 * 2351 *-------------------------------------------------------------------------- 2352 */ 2353LEAF(MachTLBRead) 2354 .set noreorder 2355 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2356 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2357 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2358 2359 sll a0, a0, VMMACH_TLB_INDEX_SHIFT 2360 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index register 2361 nop 2362 tlbr # Read from the TLB 2363 mfc0 t3, MACH_COP_0_TLB_HI # fetch the hi entry 2364 mfc0 t4, MACH_COP_0_TLB_LOW # fetch the low entry 2365 sw t3, tlbhi 2366 sw t4, tlblo 2367 2368 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2369 j ra 2370 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2371 .set reorder 2372END(MachTLBRead) 2373 2374/*-------------------------------------------------------------------------- 2375 * 2376 * MachTLBGetPID -- 2377 * 2378 * MachTLBGetPID() 2379 * 2380 * Results: 2381 * Returns the current TLB pid reg. 2382 * 2383 * Side effects: 2384 * None. 2385 * 2386 *-------------------------------------------------------------------------- 2387 */ 2388#ifdef NOTDEF 2389LEAF(MachTLBGetPID) 2390 .set noreorder 2391 mfc0 v0, MACH_COP_0_TLB_HI # get PID 2392 nop 2393 and v0, v0, VMMACH_TLB_PID # mask off PID 2394 j ra 2395 srl v0, v0, VMMACH_TLB_PID_SHIFT # put PID in right spot 2396 .set reorder 2397END(MachTLBGetPID) 2398#endif /* NOTDEF */ 2399 2400/* 2401 * Return the current value of the cause register. 2402 */ 2403#ifdef NOTDEF 2404LEAF(MachGetCauseReg) 2405 .set noreorder 2406 mfc0 v0, MACH_COP_0_CAUSE_REG 2407 j ra 2408 nop 2409 .set reorder 2410END(MachGetCauseReg) 2411#endif /* NOTDEF */ 2412#endif /* DEBUG */ 2413 2414/*---------------------------------------------------------------------------- 2415 * 2416 * MachSwitchFPState -- 2417 * 2418 * Save the current state into 'from' and restore it from 'to'. 2419 * 2420 * MachSwitchFPState(from, to) 2421 * struct proc *from; 2422 * struct user *to; 2423 * 2424 * Results: 2425 * None. 2426 * 2427 * Side effects: 2428 * None. 2429 * 2430 *---------------------------------------------------------------------------- 2431 */ 2432LEAF(MachSwitchFPState) 2433 .set noreorder 2434 mfc0 t1, MACH_COP_0_STATUS_REG # Save old SR 2435 li t0, MACH_SR_COP_1_BIT # enable the coprocessor 2436 mtc0 t0, MACH_COP_0_STATUS_REG 2437 2438 beq a0, zero, 1f # skip save if NULL pointer 2439 nop 2440/* 2441 * First read out the status register to make sure that all FP operations 2442 * have completed. 2443 */ 2444 lw a0, P_ADDR(a0) # get pointer to pcb for proc 2445 cfc1 t0, MACH_FPC_CSR # stall til FP done 2446 cfc1 t0, MACH_FPC_CSR # now get status 2447 li t3, ~MACH_SR_COP_1_BIT 2448 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register 2449 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status 2450 and t2, t2, t3 # clear COP_1 enable bit 2451 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register 2452/* 2453 * Save the floating point registers. 2454 */ 2455 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) 2456 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) 2457 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) 2458 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) 2459 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) 2460 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) 2461 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) 2462 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) 2463 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) 2464 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) 2465 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) 2466 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) 2467 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) 2468 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) 2469 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) 2470 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) 2471 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) 2472 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) 2473 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) 2474 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) 2475 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) 2476 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) 2477 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) 2478 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) 2479 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) 2480 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) 2481 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) 2482 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) 2483 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) 2484 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) 2485 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) 2486 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) 2487 24881: 2489/* 2490 * Restore the floating point registers. 2491 */ 2492 lw t0, U_PCB_FPREGS+(32 * 4)(a1) # get status register 2493 lwc1 $f0, U_PCB_FPREGS+(0 * 4)(a1) 2494 lwc1 $f1, U_PCB_FPREGS+(1 * 4)(a1) 2495 lwc1 $f2, U_PCB_FPREGS+(2 * 4)(a1) 2496 lwc1 $f3, U_PCB_FPREGS+(3 * 4)(a1) 2497 lwc1 $f4, U_PCB_FPREGS+(4 * 4)(a1) 2498 lwc1 $f5, U_PCB_FPREGS+(5 * 4)(a1) 2499 lwc1 $f6, U_PCB_FPREGS+(6 * 4)(a1) 2500 lwc1 $f7, U_PCB_FPREGS+(7 * 4)(a1) 2501 lwc1 $f8, U_PCB_FPREGS+(8 * 4)(a1) 2502 lwc1 $f9, U_PCB_FPREGS+(9 * 4)(a1) 2503 lwc1 $f10, U_PCB_FPREGS+(10 * 4)(a1) 2504 lwc1 $f11, U_PCB_FPREGS+(11 * 4)(a1) 2505 lwc1 $f12, U_PCB_FPREGS+(12 * 4)(a1) 2506 lwc1 $f13, U_PCB_FPREGS+(13 * 4)(a1) 2507 lwc1 $f14, U_PCB_FPREGS+(14 * 4)(a1) 2508 lwc1 $f15, U_PCB_FPREGS+(15 * 4)(a1) 2509 lwc1 $f16, U_PCB_FPREGS+(16 * 4)(a1) 2510 lwc1 $f17, U_PCB_FPREGS+(17 * 4)(a1) 2511 lwc1 $f18, U_PCB_FPREGS+(18 * 4)(a1) 2512 lwc1 $f19, U_PCB_FPREGS+(19 * 4)(a1) 2513 lwc1 $f20, U_PCB_FPREGS+(20 * 4)(a1) 2514 lwc1 $f21, U_PCB_FPREGS+(21 * 4)(a1) 2515 lwc1 $f22, U_PCB_FPREGS+(22 * 4)(a1) 2516 lwc1 $f23, U_PCB_FPREGS+(23 * 4)(a1) 2517 lwc1 $f24, U_PCB_FPREGS+(24 * 4)(a1) 2518 lwc1 $f25, U_PCB_FPREGS+(25 * 4)(a1) 2519 lwc1 $f26, U_PCB_FPREGS+(26 * 4)(a1) 2520 lwc1 $f27, U_PCB_FPREGS+(27 * 4)(a1) 2521 lwc1 $f28, U_PCB_FPREGS+(28 * 4)(a1) 2522 lwc1 $f29, U_PCB_FPREGS+(29 * 4)(a1) 2523 lwc1 $f30, U_PCB_FPREGS+(30 * 4)(a1) 2524 lwc1 $f31, U_PCB_FPREGS+(31 * 4)(a1) 2525 2526 and t0, t0, ~MACH_FPC_EXCEPTION_BITS 2527 ctc1 t0, MACH_FPC_CSR 2528 nop 2529 2530 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register. 2531 j ra 2532 nop 2533 .set reorder 2534END(MachSwitchFPState) 2535 2536/*---------------------------------------------------------------------------- 2537 * 2538 * MachSaveCurFPState -- 2539 * 2540 * Save the current floating point coprocessor state. 2541 * 2542 * MachSaveCurFPState(p) 2543 * struct proc *p; 2544 * 2545 * Results: 2546 * None. 2547 * 2548 * Side effects: 2549 * machFPCurProcPtr is cleared. 2550 * 2551 *---------------------------------------------------------------------------- 2552 */ 2553LEAF(MachSaveCurFPState) 2554 .set noreorder 2555 lw a0, P_ADDR(a0) # get pointer to pcb for proc 2556 mfc0 t1, MACH_COP_0_STATUS_REG # Disable interrupts and 2557 li t0, MACH_SR_COP_1_BIT # enable the coprocessor 2558 mtc0 t0, MACH_COP_0_STATUS_REG 2559 sw zero, machFPCurProcPtr # indicate state has been saved 2560/* 2561 * First read out the status register to make sure that all FP operations 2562 * have completed. 2563 */ 2564 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register 2565 li t3, ~MACH_SR_COP_1_BIT 2566 and t2, t2, t3 # clear COP_1 enable bit 2567 cfc1 t0, MACH_FPC_CSR # stall til FP done 2568 cfc1 t0, MACH_FPC_CSR # now get status 2569 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register 2570 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status 2571/* 2572 * Save the floating point registers. 2573 */ 2574 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) 2575 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) 2576 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) 2577 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) 2578 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) 2579 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) 2580 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) 2581 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) 2582 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) 2583 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) 2584 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) 2585 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) 2586 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) 2587 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) 2588 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) 2589 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) 2590 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) 2591 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) 2592 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) 2593 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) 2594 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) 2595 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) 2596 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) 2597 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) 2598 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) 2599 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) 2600 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) 2601 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) 2602 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) 2603 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) 2604 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) 2605 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) 2606 2607 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register. 2608 j ra 2609 nop 2610 .set reorder 2611END(MachSaveCurFPState) 2612 2613/*---------------------------------------------------------------------------- 2614 * 2615 * MachFPInterrupt -- 2616 * 2617 * Handle a floating point interrupt. 2618 * 2619 * MachFPInterrupt(statusReg, causeReg, pc) 2620 * unsigned statusReg; 2621 * unsigned causeReg; 2622 * unsigned pc; 2623 * 2624 * Results: 2625 * None. 2626 * 2627 * Side effects: 2628 * None. 2629 * 2630 *---------------------------------------------------------------------------- 2631 */ 2632NON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra) 2633 .set noreorder 2634 subu sp, sp, STAND_FRAME_SIZE 2635 mfc0 t0, MACH_COP_0_STATUS_REG 2636 sw ra, STAND_RA_OFFSET(sp) 2637 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2638 2639 or t1, t0, MACH_SR_COP_1_BIT 2640 mtc0 t1, MACH_COP_0_STATUS_REG 2641 nop 2642 nop 2643 cfc1 t1, MACH_FPC_CSR # stall til FP done 2644 cfc1 t1, MACH_FPC_CSR # now get status 2645 nop 2646 .set reorder 2647 sll t2, t1, (31 - 17) # unimplemented operation? 2648 bgez t2, 3f # no, normal trap 2649/* 2650 * We got an unimplemented operation trap so 2651 * fetch the instruction, compute the next PC and emulate the instruction. 2652 */ 2653 bgez a1, 1f # Check the branch delay bit. 2654/* 2655 * The instruction is in the branch delay slot so the branch will have to 2656 * be emulated to get the resulting PC. 2657 */ 2658 sw a2, STAND_FRAME_SIZE + 8(sp) 2659 li a0, UADDR+U_PCB_REGS # first arg is ptr to CPU registers 2660 move a1, a2 # second arg is instruction PC 2661 move a2, t1 # third arg is floating point CSR 2662 move a3, zero # fourth arg is FALSE 2663 jal MachEmulateBranch # compute PC after branch 2664/* 2665 * Now load the floating-point instruction in the branch delay slot 2666 * to be emulated. 2667 */ 2668 lw a2, STAND_FRAME_SIZE + 8(sp) # restore EXC pc 2669 lw a0, 4(a2) # a0 = coproc instruction 2670 b 2f 2671/* 2672 * This is not in the branch delay slot so calculate the resulting 2673 * PC (epc + 4) into v0 and continue to MachEmulateFP(). 2674 */ 26751: 2676 lw a0, 0(a2) # a0 = coproc instruction 2677 addu v0, a2, 4 # v0 = next pc 26782: 2679 sw v0, UADDR+U_PCB_REGS+(PC * 4) # save new pc 2680/* 2681 * Check to see if the instruction to be emulated is a floating-point 2682 * instruction. 2683 */ 2684 srl a3, a0, MACH_OPCODE_SHIFT 2685 beq a3, MACH_OPCODE_C1, 4f # this should never fail 2686/* 2687 * Send a floating point exception signal to the current process. 2688 */ 26893: 2690 lw a0, curproc # get current process 2691 cfc1 a2, MACH_FPC_CSR # code = FP execptions 2692 li a1, SIGFPE 2693 ctc1 zero, MACH_FPC_CSR # Clear exceptions 2694 jal trapsignal 2695 b FPReturn 2696 2697/* 2698 * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate. 2699 */ 27004: 2701 jal MachEmulateFP 2702 2703/* 2704 * Turn off the floating point coprocessor and return. 2705 */ 2706FPReturn: 2707 .set noreorder 2708 mfc0 t0, MACH_COP_0_STATUS_REG 2709 lw ra, STAND_RA_OFFSET(sp) 2710 and t0, t0, ~MACH_SR_COP_1_BIT 2711 mtc0 t0, MACH_COP_0_STATUS_REG 2712 j ra 2713 addu sp, sp, STAND_FRAME_SIZE 2714 .set reorder 2715END(MachFPInterrupt) 2716 2717/*---------------------------------------------------------------------------- 2718 * 2719 * MachConfigCache -- 2720 * 2721 * Size the caches. 2722 * NOTE: should only be called from mach_init(). 2723 * 2724 * Results: 2725 * None. 2726 * 2727 * Side effects: 2728 * The size of the data cache is stored into machDataCacheSize and the 2729 * size of instruction cache is stored into machInstCacheSize. 2730 * 2731 *---------------------------------------------------------------------------- 2732 */ 2733NON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra) 2734 .set noreorder 2735 subu sp, sp, STAND_FRAME_SIZE 2736 sw ra, STAND_RA_OFFSET(sp) # Save return address. 2737 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2738 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2739 la v0, 1f 2740 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2741 j v0 2742 nop 27431: 2744/* 2745 * This works because jal doesn't change pc[31..28] and the 2746 * linker still thinks SizeCache is in the cached region so it computes 2747 * the correct address without complaining. 2748 */ 2749 jal SizeCache # Get the size of the d-cache. 2750 nop 2751 sw v0, machDataCacheSize 2752 nop # Make sure sw out of pipe 2753 nop 2754 nop 2755 nop 2756 li v0, MACH_SR_SWAP_CACHES # Swap caches 2757 mtc0 v0, MACH_COP_0_STATUS_REG 2758 nop # Insure caches stable 2759 nop 2760 nop 2761 nop 2762 jal SizeCache # Get the size of the i-cache. 2763 nop 2764 sw v0, machInstCacheSize 2765 nop # Make sure sw out of pipe 2766 nop 2767 nop 2768 nop 2769 mtc0 zero, MACH_COP_0_STATUS_REG # Swap back caches. 2770 nop 2771 nop 2772 nop 2773 nop 2774 la t0, 1f 2775 j t0 # Back to cached mode 2776 nop 27771: 2778 lw ra, STAND_RA_OFFSET(sp) # Restore return addr 2779 addu sp, sp, STAND_FRAME_SIZE # Restore sp. 2780 j ra 2781 nop 2782 .set reorder 2783END(MachConfigCache) 2784 2785/*---------------------------------------------------------------------------- 2786 * 2787 * SizeCache -- 2788 * 2789 * Get the size of the cache. 2790 * 2791 * Results: 2792 * The size of the cache. 2793 * 2794 * Side effects: 2795 * None. 2796 * 2797 *---------------------------------------------------------------------------- 2798 */ 2799LEAF(SizeCache) 2800 .set noreorder 2801 mfc0 t0, MACH_COP_0_STATUS_REG # Save the current status reg. 2802 nop 2803 or v0, t0, MACH_SR_ISOL_CACHES # Isolate the caches. 2804 nop # Make sure no stores in pipe 2805 mtc0 v0, MACH_COP_0_STATUS_REG 2806 nop # Make sure isolated 2807 nop 2808 nop 2809/* 2810 * Clear cache size boundaries. 2811 */ 2812 li v0, MACH_MIN_CACHE_SIZE 28131: 2814 sw zero, MACH_CACHED_MEMORY_ADDR(v0) # Clear cache memory 2815 sll v0, v0, 1 2816 bleu v0, +MACH_MAX_CACHE_SIZE, 1b 2817 nop 2818 li v0, -1 2819 sw v0, MACH_CACHED_MEMORY_ADDR(zero) # Store marker in cache 2820 li v0, MACH_MIN_CACHE_SIZE 28212: 2822 lw v1, MACH_CACHED_MEMORY_ADDR(v0) # Look for marker 2823 nop 2824 bne v1, zero, 3f # Found marker. 2825 nop 2826 sll v0, v0, 1 # cache size * 2 2827 bleu v0, +MACH_MAX_CACHE_SIZE, 2b # keep looking 2828 nop 2829 move v0, zero # must be no cache 28303: 2831 mtc0 t0, MACH_COP_0_STATUS_REG 2832 nop # Make sure unisolated 2833 nop 2834 nop 2835 nop 2836 j ra 2837 nop 2838 .set reorder 2839END(SizeCache) 2840 2841/*---------------------------------------------------------------------------- 2842 * 2843 * MachFlushCache -- 2844 * 2845 * Flush the caches. 2846 * 2847 * Results: 2848 * None. 2849 * 2850 * Side effects: 2851 * The contents of the caches is flushed. 2852 * 2853 *---------------------------------------------------------------------------- 2854 */ 2855LEAF(MachFlushCache) 2856 .set noreorder 2857 lw t1, machInstCacheSize # Must load before isolating 2858 lw t2, machDataCacheSize # Must load before isolating 2859 mfc0 t3, MACH_COP_0_STATUS_REG # Save the status register. 2860 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2861 la v0, 1f 2862 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2863 j v0 2864 nop 2865/* 2866 * Flush the instruction cache. 2867 */ 28681: 2869 li v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES 2870 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap caches. 2871 li t0, MACH_UNCACHED_MEMORY_ADDR 2872 subu t0, t0, t1 2873 li t1, MACH_UNCACHED_MEMORY_ADDR 2874 la v0, 1f # Run cached 2875 j v0 2876 nop 28771: 2878 addu t0, t0, 4 2879 bne t0, t1, 1b 2880 sb zero, -4(t0) 2881 2882 la v0, 1f 2883 or v0, MACH_UNCACHED_MEMORY_ADDR 2884 j v0 # Run uncached 2885 nop 2886/* 2887 * Flush the data cache. 2888 */ 28891: 2890 li v0, MACH_SR_ISOL_CACHES 2891 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap back caches 2892 li t0, MACH_UNCACHED_MEMORY_ADDR 2893 subu t0, t0, t2 2894 la v0, 1f 2895 j v0 # Back to cached mode 2896 nop 28971: 2898 addu t0, t0, 4 2899 bne t0, t1, 1b 2900 sb zero, -4(t0) 2901 2902 nop # Insure isolated stores 2903 nop # out of pipe. 2904 nop 2905 nop 2906 mtc0 t3, MACH_COP_0_STATUS_REG # Restore status reg. 2907 nop # Insure cache unisolated. 2908 nop 2909 nop 2910 nop 2911 j ra 2912 nop 2913 .set reorder 2914END(MachFlushCache) 2915 2916/*---------------------------------------------------------------------------- 2917 * 2918 * MachFlushICache -- 2919 * 2920 * void MachFlushICache(addr, len) 2921 * vm_offset_t addr, len; 2922 * 2923 * Flush instruction cache for range of addr to addr + len - 1. 2924 * The address can be any valid address so long as no TLB misses occur. 2925 * 2926 * Results: 2927 * None. 2928 * 2929 * Side effects: 2930 * The contents of the cache is flushed. 2931 * 2932 *---------------------------------------------------------------------------- 2933 */ 2934LEAF(MachFlushICache) 2935 .set noreorder 2936 mfc0 t0, MACH_COP_0_STATUS_REG # Save SR 2937 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2938 2939 la v1, 1f 2940 or v1, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2941 j v1 2942 nop 29431: 2944 bc0t 1b # make sure stores are complete 2945 li v1, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES 2946 mtc0 v1, MACH_COP_0_STATUS_REG 2947 nop 2948 addu a1, a1, a0 # compute ending address 29491: 2950 addu a0, a0, 4 2951 bne a0, a1, 1b 2952 sb zero, -4(a0) 2953 2954 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts 2955 j ra # return and run cached 2956 nop 2957 .set reorder 2958END(MachFlushICache) 2959 2960#ifndef NOTDEF /* I don't know why Ralph's code doesn't work. KU:XXX */ 2961/*---------------------------------------------------------------------------- 2962 * 2963 * MachFlushDCache -- 2964 * 2965 * void MachFlushDCache(addr, len) 2966 * vm_offset_t addr, len; 2967 * 2968 * Flush data cache for range of addr to addr + len - 1. 2969 * The address can be any valid address so long as no TLB misses occur. 2970 * 2971 * Results: 2972 * None. 2973 * 2974 * Side effects: 2975 * The contents of the cache is flushed. 2976 * 2977 *---------------------------------------------------------------------------- 2978 */ 2979LEAF(MachFlushDCache) 2980 .set noreorder 2981 lw t2, machDataCacheSize # Must load before isolating 2982 mfc0 t0, MACH_COP_0_STATUS_REG # Save SR 2983#ifdef notyet /* KU:??? why? */ 2984 bltu a1, t2, 1f # if (length < cachesize) 2985#endif 2986 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2987 move a1, t2 # length = cachesize 29881: 2989 li v1, MACH_SR_ISOL_CACHES # isolate dcache 2990 mtc0 v1, MACH_COP_0_STATUS_REG 2991 addu a1, a1, a0 # compute ending address 2992 nop 29931: 2994 addu a0, a0, 4 2995 bltu a0, a1, 1b 2996 sb zero, -4(a0) 2997 2998 nop # Insure isolated stores 2999 nop # out of pipe. 3000 nop 3001 nop 3002 mtc0 t0, MACH_COP_0_STATUS_REG # Restore status reg. 3003 nop # Insure cache unisolated. 3004 nop 3005 nop 3006 nop 3007 j ra # return and run cached 3008 nop 3009 .set reorder 3010END(MachFlushDCache) 3011#else 3012/*---------------------------------------------------------------------------- 3013 * 3014 * MachFlushDCache -- 3015 * 3016 * void MachFlushDCache(addr, len) 3017 * vm_offset_t addr, len; 3018 * 3019 * Flush data cache for range of addr to addr + len - 1. 3020 * The address can be any valid address so long as no TLB misses occur. 3021 * (Be sure to use cached K0SEG kernel addresses) 3022 * Results: 3023 * None. 3024 * 3025 * Side effects: 3026 * The contents of the cache is flushed. 3027 * 3028 *---------------------------------------------------------------------------- 3029 */ 3030LEAF(MachFlushDCache) 3031 .set noreorder 3032 mfc0 t0, MACH_COP_0_STATUS_REG # Save SR 3033 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 3034 3035 la v1, 1f 3036 or v1, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 3037 j v1 3038 nop 30391: 3040 bc0t 1b # make sure stores are complete 3041 li v1, MACH_SR_ISOL_CACHES 3042 mtc0 v1, MACH_COP_0_STATUS_REG 3043 nop 3044 addu a1, a1, a0 # compute ending address 30451: 3046 addu a0, a0, 4 3047 bne a0, a1, 1b 3048 sb zero, -4(a0) 3049 3050 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts 3051 j ra # return and run cached 3052 nop 3053 .set reorder 3054END(MachFlushDCache) 3055#endif /* NOTDEF */ 3056 3057#ifdef KADB 3058/* 3059 * Read a long and return it. 3060 * Note: addresses can be unaligned! 3061 * 3062 * long 3063L* kdbpeek(addr) 3064L* caddt_t addr; 3065L* { 3066L* return (*(long *)addr); 3067L* } 3068 */ 3069#ifdef NOTDEF 3070LEAF(kdbpeek) 3071 li v0, KADBERR 3072 sw v0, UADDR+U_PCB_ONFAULT 3073 and v0, a0, 3 # unaligned address? 3074 bne v0, zero, 1f 3075 lw v0, (a0) # aligned access 3076 b 2f 30771: 3078 LWHI v0, 0(a0) # get next 4 bytes (unaligned) 3079 LWLO v0, 3(a0) 30802: 3081 sw zero, UADDR+U_PCB_ONFAULT 3082 j ra # made it w/o errors 3083kadberr: 3084 li v0, 1 # trap sends us here 3085 sw v0, kdbmkfault 3086 j ra 3087END(kdbpeek) 3088#endif /* NOTDEF */ 3089 3090/* 3091 * Write a long to 'addr'. 3092 * Note: addresses can be unaligned! 3093 * 3094L* void 3095L* kdbpoke(addr, value) 3096L* caddt_t addr; 3097L* long value; 3098L* { 3099L* *(long *)addr = value; 3100L* } 3101 */ 3102#ifdef NOTDEF 3103LEAF(kdbpoke) 3104 li v0, KADBERR 3105 sw v0, UADDR+U_PCB_ONFAULT 3106 and v0, a0, 3 # unaligned address? 3107 bne v0, zero, 1f 3108 sw a1, (a0) # aligned access 3109 b 2f 31101: 3111 SWHI a1, 0(a0) # store next 4 bytes (unaligned) 3112 SWLO a1, 3(a0) 3113 and a0, a0, ~3 # align address for cache flush 31142: 3115 sw zero, UADDR+U_PCB_ONFAULT 3116 li a1, 8 3117 b MachFlushICache # flush instruction cache 3118END(kdbpoke) 3119#endif /* NOTDEF */ 3120 3121/* 3122 * Save registers and state so we can do a 'kdbreset' (like longjmp) later. 3123 * Always returns zero. 3124 * 3125L* int kdb_savearea[11]; 3126L* 3127L* int 3128L* kdbsetexit() 3129L* { 3130L* kdb_savearea[0] = 0; 3131L* return (0); 3132L* } 3133 */ 3134 .comm kdb_savearea, (11 * 4) 3135 3136#ifdef NOTDEF 3137LEAF(kdbsetexit) 3138 .set noreorder 3139 la a0, kdb_savearea 3140 sw s0, 0(a0) 3141 sw s1, 4(a0) 3142 sw s2, 8(a0) 3143 sw s3, 12(a0) 3144 sw s4, 16(a0) 3145 sw s5, 20(a0) 3146 sw s6, 24(a0) 3147 sw s7, 28(a0) 3148 sw sp, 32(a0) 3149 sw s8, 36(a0) 3150 sw ra, 40(a0) 3151 j ra 3152 move v0, zero 3153 .set reorder 3154END(kdbsetexit) 3155#endif /* NOTDEF */ 3156 3157/* 3158 * Restore registers and state (like longjmp) and return x. 3159 * 3160L* int 3161L* kdbreset(x) 3162L* { 3163L* return (x); 3164L* } 3165 */ 3166#ifdef NOTDEF 3167LEAF(kdbreset) 3168 .set noreorder 3169 la v0, kdb_savearea 3170 lw ra, 40(v0) 3171 lw s0, 0(v0) 3172 lw s1, 4(v0) 3173 lw s2, 8(v0) 3174 lw s3, 12(v0) 3175 lw s4, 16(v0) 3176 lw s5, 20(v0) 3177 lw s6, 24(v0) 3178 lw s7, 28(v0) 3179 lw sp, 32(v0) 3180 lw s8, 36(v0) 3181 j ra 3182 move v0, a0 3183 .set reorder 3184END(kdbreset) 3185#endif /* NOTDEF */ 3186 3187/* 3188 * Trap into the debugger. 3189 * 3190L* void 3191L* kdbpanic() 3192L* { 3193L* } 3194 */ 3195#ifdef NOTDEF 3196LEAF(kdbpanic) 3197 break MACH_BREAK_KDB_VAL 3198 j ra 3199END(kdbpanic) 3200#endif /* NOTDEF */ 3201#endif /* KADB */ 3202 3203LEAF(to_monitor) 3204 .set noreorder 3205#ifdef RB_PWOFF 3206 andi a0, RB_PWOFF 3207 beq a0, zero, 1f 3208 nop 32091: 3210#endif 3211 li v0, MACH_SR_BOOT_EXC_VEC # no interrupt and 3212 mtc0 v0, MACH_COP_0_STATUS_REG # boot strap exception vector 3213 nop 3214 nop 3215 nop 3216 nop 3217 li a1, MACH_MONARG_ADDR|MACH_UNCACHED_MEMORY_ADDR 3218 sw a0, (a1) # pass argument(howto) 3219 move a0, zero # syscall(#0) 3220 syscall 3221 nop 3222 .set reorder 3223END(to_monitor) 3224 3225/* 3226 * getpcps(pc, sp) 3227 * int *pc, *sp; 3228 * return value: sr 3229 */ 3230LEAF(getpcsp) 3231 .set noreorder 3232 mfc0 v0, MACH_COP_0_STATUS_REG 3233 sw ra, (a0) 3234 .set reorder 3235 sw sp, (a1) 3236 j ra 3237 .set reorder 3238END(getpcps) 3239