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