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