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.7 (Berkeley) 06/20/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 sw zero, curproc # set curproc NULL for stats 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 UtlbFault # handle the rest 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 * Handle the rest of the UTLB miss. 1113 */ 1114UtlbFault: 1115 .set noreorder 1116 .set noat 1117 mfc0 k0, MACH_COP_0_BAD_VADDR # get the virtual address 1118 nop 1119 srl k0, k0, PMAP_HASH_SHIFT1 # get page in low bits 1120 srl k1, k0, PMAP_HASH_SHIFT2 - PMAP_HASH_SHIFT1 1121 and k0, k0, PMAP_HASH_MASK1 1122 and k1, k1, PMAP_HASH_MASK2 1123 or k1, k1, k0 1124 sll k1, k1, PMAP_HASH_SIZE_SHIFT # compute index 1125 lw k0, PMAP_HASH_LOW_OFFSET+8(k1) # get cached low PTE entry 1126 lw k1, PMAP_HASH_HIGH_OFFSET+8(k1) # get cached high PTE entry 1127 mtc0 k0, MACH_COP_0_TLB_LOW 1128 mfc0 k0, MACH_COP_0_TLB_HI # get actual high PTE entry 1129 nop 1130 bne k0, k1, SlowFault # non-matching PTE 1131 mfc0 k0, MACH_COP_0_EXC_PC # get return address 1132 tlbwr # update TLB 1133 j k0 1134 rfe 1135/* 1136 * We couldn't find a TLB entry. 1137 * Find out what mode we came from and call the appropriate handler. 1138 */ 1139SlowFault: 1140 mfc0 k0, MACH_COP_0_STATUS_REG 1141 nop 1142 and k0, k0, MACH_SR_KU_PREV 1143 bne k0, zero, MachUserGenException 1144 nop 1145 .set reorder 1146 .set at 1147/* 1148 * Fall though ... 1149 */ 1150 1151/*---------------------------------------------------------------------------- 1152 * 1153 * MachKernGenException -- 1154 * 1155 * Handle an exception from kernel mode. 1156 * 1157 * Results: 1158 * None. 1159 * 1160 * Side effects: 1161 * None. 1162 * 1163 *---------------------------------------------------------------------------- 1164 */ 1165 1166/* 1167 * The kernel exception stack contains 18 saved general registers, 1168 * the status register and the multiply lo and high registers. 1169 * In addition, we set this up for linkage conventions. 1170 */ 1171#define KERN_REG_SIZE (18 * 4) 1172#define KERN_REG_OFFSET (STAND_FRAME_SIZE) 1173#define KERN_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) 1174#define KERN_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) 1175#define KERN_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) 1176#define KERN_EXC_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) 1177 1178NON_LEAF(MachKernGenException, KERN_EXC_FRAME_SIZE, ra) 1179 .set noreorder 1180 .set noat 1181#ifdef KADB 1182 la k0, kdbpcb # save registers for kadb 1183 sw s0, (S0 * 4)(k0) 1184 sw s1, (S1 * 4)(k0) 1185 sw s2, (S2 * 4)(k0) 1186 sw s3, (S3 * 4)(k0) 1187 sw s4, (S4 * 4)(k0) 1188 sw s5, (S5 * 4)(k0) 1189 sw s6, (S6 * 4)(k0) 1190 sw s7, (S7 * 4)(k0) 1191 sw s8, (S8 * 4)(k0) 1192 sw gp, (GP * 4)(k0) 1193 sw sp, (SP * 4)(k0) 1194#endif 1195 subu sp, sp, KERN_EXC_FRAME_SIZE 1196 .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE) 1197/* 1198 * Save the relevant kernel registers onto the stack. 1199 * We don't need to save s0 - s8, sp and gp because 1200 * the compiler does it for us. 1201 */ 1202 sw AT, KERN_REG_OFFSET + 0(sp) 1203 sw v0, KERN_REG_OFFSET + 4(sp) 1204 sw v1, KERN_REG_OFFSET + 8(sp) 1205 sw a0, KERN_REG_OFFSET + 12(sp) 1206 mflo v0 1207 mfhi v1 1208 sw a1, KERN_REG_OFFSET + 16(sp) 1209 sw a2, KERN_REG_OFFSET + 20(sp) 1210 sw a3, KERN_REG_OFFSET + 24(sp) 1211 sw t0, KERN_REG_OFFSET + 28(sp) 1212 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1213 sw t1, KERN_REG_OFFSET + 32(sp) 1214 sw t2, KERN_REG_OFFSET + 36(sp) 1215 sw t3, KERN_REG_OFFSET + 40(sp) 1216 sw t4, KERN_REG_OFFSET + 44(sp) 1217 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1218 sw t5, KERN_REG_OFFSET + 48(sp) 1219 sw t6, KERN_REG_OFFSET + 52(sp) 1220 sw t7, KERN_REG_OFFSET + 56(sp) 1221 sw t8, KERN_REG_OFFSET + 60(sp) 1222 mfc0 a2, MACH_COP_0_BAD_VADDR # Third arg is the fault addr. 1223 sw t9, KERN_REG_OFFSET + 64(sp) 1224 sw ra, KERN_REG_OFFSET + 68(sp) 1225 sw v0, KERN_MULT_LO_OFFSET(sp) 1226 sw v1, KERN_MULT_HI_OFFSET(sp) 1227 mfc0 a3, MACH_COP_0_EXC_PC # Fourth arg is the pc. 1228 sw a0, KERN_SR_OFFSET(sp) 1229/* 1230 * Call the exception handler. 1231 */ 1232 jal trap 1233 sw a3, STAND_RA_OFFSET(sp) # for debugging 1234/* 1235 * Restore registers and return from the exception. 1236 * v0 contains the return address. 1237 */ 1238 lw a0, KERN_SR_OFFSET(sp) 1239 lw t0, KERN_MULT_LO_OFFSET(sp) 1240 lw t1, KERN_MULT_HI_OFFSET(sp) 1241 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1242 mtlo t0 1243 mthi t1 1244 move k0, v0 1245 lw AT, KERN_REG_OFFSET + 0(sp) 1246 lw v0, KERN_REG_OFFSET + 4(sp) 1247 lw v1, KERN_REG_OFFSET + 8(sp) 1248 lw a0, KERN_REG_OFFSET + 12(sp) 1249 lw a1, KERN_REG_OFFSET + 16(sp) 1250 lw a2, KERN_REG_OFFSET + 20(sp) 1251 lw a3, KERN_REG_OFFSET + 24(sp) 1252 lw t0, KERN_REG_OFFSET + 28(sp) 1253 lw t1, KERN_REG_OFFSET + 32(sp) 1254 lw t2, KERN_REG_OFFSET + 36(sp) 1255 lw t3, KERN_REG_OFFSET + 40(sp) 1256 lw t4, KERN_REG_OFFSET + 44(sp) 1257 lw t5, KERN_REG_OFFSET + 48(sp) 1258 lw t6, KERN_REG_OFFSET + 52(sp) 1259 lw t7, KERN_REG_OFFSET + 56(sp) 1260 lw t8, KERN_REG_OFFSET + 60(sp) 1261 lw t9, KERN_REG_OFFSET + 64(sp) 1262 lw ra, KERN_REG_OFFSET + 68(sp) 1263 addu sp, sp, KERN_EXC_FRAME_SIZE 1264 j k0 # Now return from the 1265 rfe # exception. 1266 .set at 1267 .set reorder 1268END(MachKernGenException) 1269 1270/*---------------------------------------------------------------------------- 1271 * 1272 * MachUserGenException -- 1273 * 1274 * Handle an exception from user mode. 1275 * 1276 * Results: 1277 * None. 1278 * 1279 * Side effects: 1280 * None. 1281 * 1282 *---------------------------------------------------------------------------- 1283 */ 1284NON_LEAF(MachUserGenException, STAND_FRAME_SIZE, ra) 1285 .set noreorder 1286 .set noat 1287 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 1288/* 1289 * Save all of the registers except for the kernel temporaries in u.u_pcb. 1290 */ 1291 sw AT, UADDR+U_PCB_REGS+(AST * 4) 1292 sw v0, UADDR+U_PCB_REGS+(V0 * 4) 1293 sw v1, UADDR+U_PCB_REGS+(V1 * 4) 1294 sw a0, UADDR+U_PCB_REGS+(A0 * 4) 1295 mflo v0 1296 sw a1, UADDR+U_PCB_REGS+(A1 * 4) 1297 sw a2, UADDR+U_PCB_REGS+(A2 * 4) 1298 sw a3, UADDR+U_PCB_REGS+(A3 * 4) 1299 sw t0, UADDR+U_PCB_REGS+(T0 * 4) 1300 mfhi v1 1301 sw t1, UADDR+U_PCB_REGS+(T1 * 4) 1302 sw t2, UADDR+U_PCB_REGS+(T2 * 4) 1303 sw t3, UADDR+U_PCB_REGS+(T3 * 4) 1304 sw t4, UADDR+U_PCB_REGS+(T4 * 4) 1305 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1306 sw t5, UADDR+U_PCB_REGS+(T5 * 4) 1307 sw t6, UADDR+U_PCB_REGS+(T6 * 4) 1308 sw t7, UADDR+U_PCB_REGS+(T7 * 4) 1309 sw s0, UADDR+U_PCB_REGS+(S0 * 4) 1310 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1311 sw s1, UADDR+U_PCB_REGS+(S1 * 4) 1312 sw s2, UADDR+U_PCB_REGS+(S2 * 4) 1313 sw s3, UADDR+U_PCB_REGS+(S3 * 4) 1314 sw s4, UADDR+U_PCB_REGS+(S4 * 4) 1315 mfc0 a2, MACH_COP_0_BAD_VADDR # Third arg is the fault addr 1316 sw s5, UADDR+U_PCB_REGS+(S5 * 4) 1317 sw s6, UADDR+U_PCB_REGS+(S6 * 4) 1318 sw s7, UADDR+U_PCB_REGS+(S7 * 4) 1319 sw t8, UADDR+U_PCB_REGS+(T8 * 4) 1320 mfc0 a3, MACH_COP_0_EXC_PC # Fourth arg is the pc. 1321 sw t9, UADDR+U_PCB_REGS+(T9 * 4) 1322 sw gp, UADDR+U_PCB_REGS+(GP * 4) 1323 sw sp, UADDR+U_PCB_REGS+(SP * 4) 1324 sw s8, UADDR+U_PCB_REGS+(S8 * 4) 1325 li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP 1326 sw ra, UADDR+U_PCB_REGS+(RA * 4) 1327 sw v0, UADDR+U_PCB_REGS+(MULLO * 4) 1328 sw v1, UADDR+U_PCB_REGS+(MULHI * 4) 1329 sw a0, UADDR+U_PCB_REGS+(SR * 4) 1330 la gp, _gp # switch to kernel GP 1331 sw a3, UADDR+U_PCB_REGS+(PC * 4) 1332 sw a3, STAND_RA_OFFSET(sp) # for debugging 1333 and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU. 1334/* 1335 * Call the exception handler. 1336 */ 1337 jal trap 1338 mtc0 t0, MACH_COP_0_STATUS_REG 1339/* 1340 * Restore user registers and return. NOTE: interrupts are enabled. 1341 */ 1342 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1343 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1344 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1345 mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts 1346 mtlo t0 1347 mthi t1 1348 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1349 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1350 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1351 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1352 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1353 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1354 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1355 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1356 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1357 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1358 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1359 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1360 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1361 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1362 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1363 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1364 lw s0, UADDR+U_PCB_REGS+(S0 * 4) 1365 lw s1, UADDR+U_PCB_REGS+(S1 * 4) 1366 lw s2, UADDR+U_PCB_REGS+(S2 * 4) 1367 lw s3, UADDR+U_PCB_REGS+(S3 * 4) 1368 lw s4, UADDR+U_PCB_REGS+(S4 * 4) 1369 lw s5, UADDR+U_PCB_REGS+(S5 * 4) 1370 lw s6, UADDR+U_PCB_REGS+(S6 * 4) 1371 lw s7, UADDR+U_PCB_REGS+(S7 * 4) 1372 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1373 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1374 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1375 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1376 lw s8, UADDR+U_PCB_REGS+(S8 * 4) 1377 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1378 j k0 1379 rfe 1380 .set at 1381 .set reorder 1382END(MachUserGenException) 1383 1384/*---------------------------------------------------------------------------- 1385 * 1386 * MachKernIntr -- 1387 * 1388 * Handle an interrupt from kernel mode. 1389 * Interrupts must use a separate stack since during exit() 1390 * there is a window of time when there is no kernel stack. 1391 * 1392 * Results: 1393 * None. 1394 * 1395 * Side effects: 1396 * None. 1397 * 1398 *---------------------------------------------------------------------------- 1399 */ 1400#define KINTR_REG_OFFSET (STAND_FRAME_SIZE) 1401#define KINTR_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) 1402#define KINTR_SP_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) 1403#define KINTR_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) 1404#define KINTR_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) 1405#define KINTR_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 16) 1406 1407NON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra) 1408 .set noreorder 1409 .set noat 1410 .mask 0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE) 1411/* 1412 * Check to see if we are already on the interrupt stack. 1413 */ 1414 li k0, MACH_CODE_START # interrupt stack below code 1415 sltu k1, sp, k0 1416 beq k1, zero, 1f # no, init sp 1417 nop 1418 sw sp, KINTR_SP_OFFSET - KINTR_FRAME_SIZE(sp) # save old sp 1419 b 2f 1420 subu sp, sp, KINTR_FRAME_SIZE # allocate stack frame 14211: 1422 sw sp, KINTR_SP_OFFSET - KINTR_FRAME_SIZE(k0) # save old sp 1423 subu sp, k0, KINTR_FRAME_SIZE # switch to interrupt stack 14242: 1425/* 1426 * Save the relevant kernel registers onto the stack. 1427 * We don't need to save s0 - s8, sp and gp because 1428 * the compiler does it for us. 1429 */ 1430 sw AT, KINTR_REG_OFFSET + 0(sp) 1431 sw v0, KINTR_REG_OFFSET + 4(sp) 1432 sw v1, KINTR_REG_OFFSET + 8(sp) 1433 sw a0, KINTR_REG_OFFSET + 12(sp) 1434 mflo v0 1435 mfhi v1 1436 sw a1, KINTR_REG_OFFSET + 16(sp) 1437 sw a2, KINTR_REG_OFFSET + 20(sp) 1438 sw a3, KINTR_REG_OFFSET + 24(sp) 1439 sw t0, KINTR_REG_OFFSET + 28(sp) 1440 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1441 sw t1, KINTR_REG_OFFSET + 32(sp) 1442 sw t2, KINTR_REG_OFFSET + 36(sp) 1443 sw t3, KINTR_REG_OFFSET + 40(sp) 1444 sw t4, KINTR_REG_OFFSET + 44(sp) 1445 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1446 sw t5, KINTR_REG_OFFSET + 48(sp) 1447 sw t6, KINTR_REG_OFFSET + 52(sp) 1448 sw t7, KINTR_REG_OFFSET + 56(sp) 1449 sw t8, KINTR_REG_OFFSET + 60(sp) 1450 mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc. 1451 sw t9, KINTR_REG_OFFSET + 64(sp) 1452 sw ra, KINTR_REG_OFFSET + 68(sp) 1453 sw v0, KINTR_MULT_LO_OFFSET(sp) 1454 sw v1, KINTR_MULT_HI_OFFSET(sp) 1455 sw a0, KINTR_SR_OFFSET(sp) 1456/* 1457 * Call the interrupt handler. 1458 */ 1459 jal interrupt 1460 sw a2, STAND_RA_OFFSET(sp) # for debugging 1461/* 1462 * Restore registers and return from the interrupt. 1463 */ 1464 lw a0, KINTR_SR_OFFSET(sp) 1465 lw t0, KINTR_MULT_LO_OFFSET(sp) 1466 lw t1, KINTR_MULT_HI_OFFSET(sp) 1467 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1468 mtlo t0 1469 mthi t1 1470 lw k0, STAND_RA_OFFSET(sp) 1471 lw AT, KINTR_REG_OFFSET + 0(sp) 1472 lw v0, KINTR_REG_OFFSET + 4(sp) 1473 lw v1, KINTR_REG_OFFSET + 8(sp) 1474 lw a0, KINTR_REG_OFFSET + 12(sp) 1475 lw a1, KINTR_REG_OFFSET + 16(sp) 1476 lw a2, KINTR_REG_OFFSET + 20(sp) 1477 lw a3, KINTR_REG_OFFSET + 24(sp) 1478 lw t0, KINTR_REG_OFFSET + 28(sp) 1479 lw t1, KINTR_REG_OFFSET + 32(sp) 1480 lw t2, KINTR_REG_OFFSET + 36(sp) 1481 lw t3, KINTR_REG_OFFSET + 40(sp) 1482 lw t4, KINTR_REG_OFFSET + 44(sp) 1483 lw t5, KINTR_REG_OFFSET + 48(sp) 1484 lw t6, KINTR_REG_OFFSET + 52(sp) 1485 lw t7, KINTR_REG_OFFSET + 56(sp) 1486 lw t8, KINTR_REG_OFFSET + 60(sp) 1487 lw t9, KINTR_REG_OFFSET + 64(sp) 1488 lw ra, KINTR_REG_OFFSET + 68(sp) 1489 lw sp, KINTR_SP_OFFSET(sp) # restore orig sp 1490 j k0 # Now return from the 1491 rfe # interrupt. 1492 .set at 1493 .set reorder 1494END(MachKernIntr) 1495 1496/*---------------------------------------------------------------------------- 1497 * 1498 * MachUserIntr -- 1499 * 1500 * Handle an interrupt from user mode. 1501 * Note: we save minimal state in the u.u_pcb struct and use the standard 1502 * kernel stack since there has to be a u page if we came from user mode. 1503 * If there is a pending software interrupt, then save the remaining state 1504 * and call softintr(). This is all because if we call swtch() inside 1505 * interrupt(), not all the user registers have been saved in u.u_pcb. 1506 * 1507 * Results: 1508 * None. 1509 * 1510 * Side effects: 1511 * None. 1512 * 1513 *---------------------------------------------------------------------------- 1514 */ 1515NON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra) 1516 .set noreorder 1517 .set noat 1518 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 1519/* 1520 * Save the relevant user registers into the u.u_pcb struct. 1521 * We don't need to save s0 - s8 because 1522 * the compiler does it for us. 1523 */ 1524 sw AT, UADDR+U_PCB_REGS+(AST * 4) 1525 sw v0, UADDR+U_PCB_REGS+(V0 * 4) 1526 sw v1, UADDR+U_PCB_REGS+(V1 * 4) 1527 sw a0, UADDR+U_PCB_REGS+(A0 * 4) 1528 mflo v0 1529 mfhi v1 1530 sw a1, UADDR+U_PCB_REGS+(A1 * 4) 1531 sw a2, UADDR+U_PCB_REGS+(A2 * 4) 1532 sw a3, UADDR+U_PCB_REGS+(A3 * 4) 1533 sw t0, UADDR+U_PCB_REGS+(T0 * 4) 1534 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1535 sw t1, UADDR+U_PCB_REGS+(T1 * 4) 1536 sw t2, UADDR+U_PCB_REGS+(T2 * 4) 1537 sw t3, UADDR+U_PCB_REGS+(T3 * 4) 1538 sw t4, UADDR+U_PCB_REGS+(T4 * 4) 1539 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1540 sw t5, UADDR+U_PCB_REGS+(T5 * 4) 1541 sw t6, UADDR+U_PCB_REGS+(T6 * 4) 1542 sw t7, UADDR+U_PCB_REGS+(T7 * 4) 1543 sw t8, UADDR+U_PCB_REGS+(T8 * 4) 1544 mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc. 1545 sw t9, UADDR+U_PCB_REGS+(T9 * 4) 1546 sw gp, UADDR+U_PCB_REGS+(GP * 4) 1547 sw sp, UADDR+U_PCB_REGS+(SP * 4) 1548 sw ra, UADDR+U_PCB_REGS+(RA * 4) 1549 li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP 1550 sw v0, UADDR+U_PCB_REGS+(MULLO * 4) 1551 sw v1, UADDR+U_PCB_REGS+(MULHI * 4) 1552 sw a0, UADDR+U_PCB_REGS+(SR * 4) 1553 sw a2, UADDR+U_PCB_REGS+(PC * 4) 1554 la gp, _gp # switch to kernel GP 1555 and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU. 1556 mtc0 t0, MACH_COP_0_STATUS_REG 1557/* 1558 * Call the interrupt handler. 1559 */ 1560 jal interrupt 1561 sw a2, STAND_RA_OFFSET(sp) # for debugging 1562/* 1563 * Restore registers and return from the interrupt. 1564 */ 1565 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1566 lw v0, astpending # any pending interrupts? 1567 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1568 bne v0, zero, 1f # don't restore, call softintr 1569 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1570 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1571 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1572 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1573 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1574 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1575 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1576 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1577 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1578 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1579 mtlo t0 1580 mthi t1 1581 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1582 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1583 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1584 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1585 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1586 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1587 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1588 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1589 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1590 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1591 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1592 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1593 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1594 j k0 # Now return from the 1595 rfe # interrupt. 1596 15971: 1598/* 1599 * We have pending software interrupts; save remaining user state in u.u_pcb. 1600 */ 1601 sw s0, UADDR+U_PCB_REGS+(S0 * 4) 1602 sw s1, UADDR+U_PCB_REGS+(S1 * 4) 1603 sw s2, UADDR+U_PCB_REGS+(S2 * 4) 1604 sw s3, UADDR+U_PCB_REGS+(S3 * 4) 1605 sw s4, UADDR+U_PCB_REGS+(S4 * 4) 1606 sw s5, UADDR+U_PCB_REGS+(S5 * 4) 1607 sw s6, UADDR+U_PCB_REGS+(S6 * 4) 1608 sw s7, UADDR+U_PCB_REGS+(S7 * 4) 1609 sw s8, UADDR+U_PCB_REGS+(S8 * 4) 1610 li t0, MACH_HARD_INT_MASK | MACH_SR_INT_ENA_CUR 1611/* 1612 * Call the software interrupt handler. 1613 */ 1614 jal softintr 1615 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts (spl0) 1616/* 1617 * Restore user registers and return. NOTE: interrupts are enabled. 1618 */ 1619 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1620 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1621 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1622 mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts 1623 mtlo t0 1624 mthi t1 1625 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1626 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1627 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1628 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1629 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1630 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1631 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1632 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1633 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1634 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1635 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1636 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1637 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1638 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1639 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1640 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1641 lw s0, UADDR+U_PCB_REGS+(S0 * 4) 1642 lw s1, UADDR+U_PCB_REGS+(S1 * 4) 1643 lw s2, UADDR+U_PCB_REGS+(S2 * 4) 1644 lw s3, UADDR+U_PCB_REGS+(S3 * 4) 1645 lw s4, UADDR+U_PCB_REGS+(S4 * 4) 1646 lw s5, UADDR+U_PCB_REGS+(S5 * 4) 1647 lw s6, UADDR+U_PCB_REGS+(S6 * 4) 1648 lw s7, UADDR+U_PCB_REGS+(S7 * 4) 1649 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1650 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1651 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1652 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1653 lw s8, UADDR+U_PCB_REGS+(S8 * 4) 1654 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1655 j k0 1656 rfe 1657 .set at 1658 .set reorder 1659END(MachUserIntr) 1660 1661#if 0 1662/*---------------------------------------------------------------------------- 1663 * 1664 * MachTLBModException -- 1665 * 1666 * Handle a TLB modified exception. 1667 * The BaddVAddr, Context, and EntryHi registers contain the failed 1668 * virtual address. 1669 * 1670 * Results: 1671 * None. 1672 * 1673 * Side effects: 1674 * None. 1675 * 1676 *---------------------------------------------------------------------------- 1677 */ 1678LEAF(MachTLBModException) 1679 .set noreorder 1680 .set noat 1681 tlbp # find the TLB entry 1682 mfc0 k0, MACH_COP_0_TLB_LOW # get the physical address 1683 mfc0 k1, MACH_COP_0_TLB_INDEX # check to be sure its valid 1684 or k0, k0, VMMACH_TLB_MOD_BIT # update TLB 1685 blt k1, zero, 4f # not found!!! 1686 mtc0 k0, MACH_COP_0_TLB_LOW 1687 li k1, MACH_CACHED_MEMORY_ADDR 1688 subu k0, k0, k1 1689 srl k0, k0, VMMACH_TLB_PHYS_PAGE_SHIFT 1690 la k1, pmap_attributes 1691 add k0, k0, k1 1692 lbu k1, 0(k0) # fetch old value 1693 nop 1694 or k1, k1, 1 # set modified bit 1695 sb k1, 0(k0) # save new value 1696 mfc0 k0, MACH_COP_0_EXC_PC # get return address 1697 nop 1698 j k0 1699 rfe 17004: 1701 break 0 # panic 1702 .set reorder 1703 .set at 1704END(MachTLBModException) 1705#endif 1706 1707/*---------------------------------------------------------------------------- 1708 * 1709 * MachTLBMissException -- 1710 * 1711 * Handle a TLB miss exception from kernel mode. 1712 * The BaddVAddr, Context, and EntryHi registers contain the failed 1713 * virtual address. 1714 * 1715 * Results: 1716 * None. 1717 * 1718 * Side effects: 1719 * None. 1720 * 1721 *---------------------------------------------------------------------------- 1722 */ 1723LEAF(MachTLBMissException) 1724 .set noreorder 1725 .set noat 1726 mfc0 k0, MACH_COP_0_BAD_VADDR # get the fault address 1727 li k1, MACH_KSEG2_ADDR # compute index 1728 subu k0, k0, k1 1729 srl k0, k0, PGSHIFT 1730 li k1, PMAP_HASH_KPAGES * NPTEPG # index within range? 1731 sltu k1, k0, k1 1732 beq k1, zero, SlowFault # No. do it the long way 1733 sll k0, k0, 2 # compute offset from index 1734 lw k0, PMAP_HASH_KADDR(k0) # get PTE entry 1735 mfc0 k1, MACH_COP_0_EXC_PC # get return address 1736 mtc0 k0, MACH_COP_0_TLB_LOW # save PTE entry 1737 and k0, k0, PG_V # make sure it's valid 1738 beq k0, zero, SlowFault # No. do it the long way 1739 nop 1740 tlbwr # update TLB 1741 j k1 1742 rfe 1743 .set reorder 1744 .set at 1745END(MachTLBMissException) 1746 1747/* 1748 * Set/clear software interrupt routines. 1749 */ 1750 1751LEAF(setsoftclock) 1752 .set noreorder 1753 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1754 nop 1755 or v0, v0, MACH_SOFT_INT_MASK_0 # set soft clock interrupt 1756 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1757 j ra 1758 nop 1759 .set reorder 1760END(setsoftclock) 1761 1762LEAF(clearsoftclock) 1763 .set noreorder 1764 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1765 nop 1766 and v0, v0, ~MACH_SOFT_INT_MASK_0 # clear soft clock interrupt 1767 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1768 j ra 1769 nop 1770 .set reorder 1771END(clearsoftclock) 1772 1773LEAF(setsoftnet) 1774 .set noreorder 1775 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1776 nop 1777 or v0, v0, MACH_SOFT_INT_MASK_1 # set soft net interrupt 1778 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1779 j ra 1780 nop 1781 .set reorder 1782END(setsoftnet) 1783 1784LEAF(clearsoftnet) 1785 .set noreorder 1786 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1787 nop 1788 and v0, v0, ~MACH_SOFT_INT_MASK_1 # clear soft net interrupt 1789 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1790 j ra 1791 nop 1792 .set reorder 1793END(clearsoftnet) 1794 1795/* 1796 * Set/change interrupt priority routines. 1797 */ 1798 1799LEAF(MachEnableIntr) 1800 .set noreorder 1801 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1802 nop 1803 or v0, v0, MACH_SR_INT_ENA_CUR 1804 mtc0 v0, MACH_COP_0_STATUS_REG # enable all interrupts 1805 j ra 1806 nop 1807 .set reorder 1808END(MachEnableIntr) 1809 1810LEAF(spl0) 1811 .set noreorder 1812 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1813 nop 1814 or t0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1815 mtc0 t0, MACH_COP_0_STATUS_REG # enable all interrupts 1816 j ra 1817 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1818 .set reorder 1819END(spl0) 1820 1821LEAF(splsoftclock) 1822 .set noreorder 1823 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1824 li t0, ~MACH_SOFT_INT_MASK_0 # disable soft clock 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(splsoftclock) 1831 1832LEAF(Mach_spl0) 1833 .set noreorder 1834 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1835 li t0, ~(MACH_INT_MASK_0|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_spl0) 1842 1843LEAF(Mach_spl1) 1844 .set noreorder 1845 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1846 li t0, ~(MACH_INT_MASK_1|MACH_SOFT_INT_MASK_0|MACH_SOFT_INT_MASK_1) 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_spl1) 1853 1854LEAF(Mach_spl2) 1855 .set noreorder 1856 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1857 li t0, ~(MACH_INT_MASK_2|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) 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(Mach_spl2) 1864 1865LEAF(Mach_spl3) 1866 .set noreorder 1867 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1868 li t0, ~(MACH_INT_MASK_3|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) 1869 and t0, t0, v0 1870 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1871 j ra 1872 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1873 .set reorder 1874END(Mach_spl3) 1875 1876LEAF(splhigh) 1877 .set noreorder 1878 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1879 li t0, ~MACH_SR_INT_ENA_CUR # disable all interrupts 1880 and t0, t0, v0 1881 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1882 j ra 1883 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1884 .set reorder 1885END(splhigh) 1886 1887/* 1888 * Restore saved interrupt mask. 1889 */ 1890LEAF(splx) 1891 .set noreorder 1892 mfc0 v0, MACH_COP_0_STATUS_REG 1893 li t0, ~(MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1894 and t0, t0, v0 1895 or t0, t0, a0 1896 mtc0 t0, MACH_COP_0_STATUS_REG 1897 j ra 1898 nop 1899 .set reorder 1900END(splx) 1901 1902/*---------------------------------------------------------------------------- 1903 * 1904 * MachEmptyWriteBuffer -- 1905 * 1906 * Return when the write buffer is empty. 1907 * 1908 * MachEmptyWriteBuffer() 1909 * 1910 * Results: 1911 * None. 1912 * 1913 * Side effects: 1914 * None. 1915 * 1916 *---------------------------------------------------------------------------- 1917 */ 1918LEAF(MachEmptyWriteBuffer) 1919 .set noreorder 1920 nop 1921 nop 1922 nop 1923 nop 19241: bc0f 1b 1925 nop 1926 j ra 1927 nop 1928 .set reorder 1929END(MachEmptyWriteBuffer) 1930 1931/*-------------------------------------------------------------------------- 1932 * 1933 * MachTLBWriteIndexed -- 1934 * 1935 * Write the given entry into the TLB at the given index. 1936 * 1937 * MachTLBWriteIndexed(index, highEntry, lowEntry) 1938 * int index; 1939 * int highEntry; 1940 * int lowEntry; 1941 * 1942 * Results: 1943 * None. 1944 * 1945 * Side effects: 1946 * TLB entry set. 1947 * 1948 *-------------------------------------------------------------------------- 1949 */ 1950LEAF(MachTLBWriteIndexed) 1951 .set noreorder 1952 mfc0 t1, MACH_COP_0_STATUS_REG # Save the status register. 1953 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 1954 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID. 1955 1956 sll a0, a0, VMMACH_TLB_INDEX_SHIFT 1957 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index. 1958 mtc0 a1, MACH_COP_0_TLB_HI # Set up entry high. 1959 mtc0 a2, MACH_COP_0_TLB_LOW # Set up entry low. 1960 nop 1961 tlbwi # Write the TLB 1962 1963 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID. 1964 j ra 1965 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register 1966 .set reorder 1967END(MachTLBWriteIndexed) 1968 1969/*-------------------------------------------------------------------------- 1970 * 1971 * MachTLBWriteRandom -- 1972 * 1973 * Write the given entry into the TLB at a random location. 1974 * 1975 * MachTLBWriteRandom(highEntry, lowEntry) 1976 * unsigned highEntry; 1977 * unsigned lowEntry; 1978 * 1979 * Results: 1980 * None. 1981 * 1982 * Side effects: 1983 * TLB entry set. 1984 * 1985 *-------------------------------------------------------------------------- 1986 */ 1987LEAF(MachTLBWriteRandom) 1988 .set noreorder 1989 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 1990 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 1991 mfc0 v0, MACH_COP_0_TLB_HI # Save the current PID. 1992 1993 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high. 1994 mtc0 a1, MACH_COP_0_TLB_LOW # Set up entry low. 1995 nop 1996 tlbwr # Write the TLB 1997 1998 mtc0 v0, MACH_COP_0_TLB_HI # Restore the PID. 1999 j ra 2000 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2001 .set reorder 2002END(MachTLBWriteRandom) 2003 2004/*-------------------------------------------------------------------------- 2005 * 2006 * MachSetPID -- 2007 * 2008 * Write the given pid into the TLB pid reg. 2009 * 2010 * MachSetPID(pid) 2011 * int pid; 2012 * 2013 * Results: 2014 * None. 2015 * 2016 * Side effects: 2017 * PID set in the entry hi register. 2018 * 2019 *-------------------------------------------------------------------------- 2020 */ 2021LEAF(MachSetPID) 2022 .set noreorder 2023 sll a0, a0, VMMACH_TLB_PID_SHIFT # put PID in right spot 2024 mtc0 a0, MACH_COP_0_TLB_HI # Write the hi reg value 2025 j ra 2026 nop 2027 .set reorder 2028END(MachSetPID) 2029 2030/*-------------------------------------------------------------------------- 2031 * 2032 * MachTLBFlush -- 2033 * 2034 * Flush the "random" entries from the TLB. 2035 * 2036 * MachTLBFlush() 2037 * 2038 * Results: 2039 * None. 2040 * 2041 * Side effects: 2042 * The TLB is flushed. 2043 * 2044 *-------------------------------------------------------------------------- 2045 */ 2046LEAF(MachTLBFlush) 2047 .set noreorder 2048 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2049 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2050 mfc0 t0, MACH_COP_0_TLB_HI # Save the PID 2051 li t1, MACH_RESERVED_ADDR # invalid address 2052 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid 2053 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2054/* 2055 * Align the starting value (t1) and the upper bound (t2). 2056 */ 2057 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT 2058 li t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 20591: 2060 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register. 2061 addu t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT # Increment index. 2062 bne t1, t2, 1b # NB: always executes next 2063 tlbwi # Write the TLB entry. 2064 2065 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID 2066 j ra 2067 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2068 .set reorder 2069END(MachTLBFlush) 2070 2071/*-------------------------------------------------------------------------- 2072 * 2073 * MachTLBFlushPID -- 2074 * 2075 * Flush all entries with the given PID from the TLB. 2076 * 2077 * MachTLBFlushPID(pid) 2078 * int pid; 2079 * 2080 * Results: 2081 * None. 2082 * 2083 * Side effects: 2084 * All entries corresponding to this PID are flushed. 2085 * 2086 *-------------------------------------------------------------------------- 2087 */ 2088LEAF(MachTLBFlushPID) 2089 .set noreorder 2090 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2091 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2092 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID 2093 sll a0, a0, VMMACH_TLB_PID_SHIFT # Align the pid to flush. 2094/* 2095 * Align the starting value (t1) and the upper bound (t2). 2096 */ 2097 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT 2098 li t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 2099 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register 21001: 2101 addu t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT # Increment index. 2102 tlbr # Read from the TLB 2103 mfc0 t4, MACH_COP_0_TLB_HI # Fetch the hi register. 2104 nop 2105 and t4, t4, VMMACH_TLB_PID # compare PID's 2106 bne t4, a0, 2f 2107 li v0, MACH_RESERVED_ADDR # invalid address 2108 mtc0 v0, MACH_COP_0_TLB_HI # Mark entry high as invalid 2109 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2110 nop 2111 tlbwi # Write the entry. 21122: 2113 bne t1, t2, 1b 2114 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register 2115 2116 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2117 j ra 2118 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2119 .set reorder 2120END(MachTLBFlushPID) 2121 2122/*-------------------------------------------------------------------------- 2123 * 2124 * MachTLBFlushAddr -- 2125 * 2126 * Flush any TLB entries for the given address and TLB PID. 2127 * 2128 * MachTLBFlushAddr(highreg) 2129 * unsigned highreg; 2130 * 2131 * Results: 2132 * None. 2133 * 2134 * Side effects: 2135 * The process's page is flushed from the TLB. 2136 * 2137 *-------------------------------------------------------------------------- 2138 */ 2139LEAF(MachTLBFlushAddr) 2140 .set noreorder 2141 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2142 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2143 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2144 2145 mtc0 a0, MACH_COP_0_TLB_HI # look for addr & PID 2146 nop 2147 tlbp # Probe for the entry. 2148 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2149 li t1, MACH_RESERVED_ADDR # Load invalid entry. 2150 bltz v0, 1f # index < 0 => !found 2151 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid 2152 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2153 nop 2154 tlbwi 21551: 2156 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2157 j ra 2158 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2159 .set reorder 2160END(MachTLBFlushAddr) 2161 2162/*-------------------------------------------------------------------------- 2163 * 2164 * MachTLBUpdate -- 2165 * 2166 * Update the TLB if highreg is found. 2167 * 2168 * MachTLBUpdate(highreg, lowreg) 2169 * unsigned highreg, lowreg; 2170 * 2171 * Results: 2172 * None. 2173 * 2174 * Side effects: 2175 * None. 2176 * 2177 *-------------------------------------------------------------------------- 2178 */ 2179LEAF(MachTLBUpdate) 2180 .set noreorder 2181 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2182 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2183 mfc0 t0, MACH_COP_0_TLB_HI # Save current PID 2184 2185 mtc0 a0, MACH_COP_0_TLB_HI # init high reg. 2186 mtc0 a1, MACH_COP_0_TLB_LOW # init low reg. 2187 nop 2188 tlbp # Probe for the entry. 2189 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2190 nop 2191 bltz v0, 1f # index < 0 => !found 2192 nop 2193 tlbwi 21941: 2195 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2196 j ra 2197 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2198 .set reorder 2199END(MachTLBUpdate) 2200 2201#if defined(DEBUG) || defined(KADB) 2202/*-------------------------------------------------------------------------- 2203 * 2204 * MachTLBFind -- 2205 * 2206 * Search the TLB for the given entry. 2207 * 2208 * MachTLBFind(hi) 2209 * unsigned hi; 2210 * 2211 * Results: 2212 * Returns a value >= 0 if the entry was found (the index). 2213 * Returns a value < 0 if the entry was not found. 2214 * 2215 * Side effects: 2216 * tlbhi and tlblo will contain the TLB entry found. 2217 * 2218 *-------------------------------------------------------------------------- 2219 */ 2220 .comm tlbhi, 4 2221 .comm tlblo, 4 2222LEAF(MachTLBFind) 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 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high. 2229 nop 2230 tlbp # Probe for the entry. 2231 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2232 nop 2233 bltz v0, 1f # not found 2234 nop 2235 tlbr # read TLB 2236 mfc0 t1, MACH_COP_0_TLB_HI # See what we got 2237 mfc0 t2, MACH_COP_0_TLB_LOW # See what we got 2238 sw t1, tlbhi 2239 sw t2, tlblo 22401: 2241 mtc0 t0, MACH_COP_0_TLB_HI # Restore current PID 2242 j ra 2243 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2244 .set reorder 2245END(MachTLBFind) 2246 2247/*-------------------------------------------------------------------------- 2248 * 2249 * MachTLBRead -- 2250 * 2251 * Read the TLB entry. 2252 * 2253 * MachTLBRead(entry) 2254 * unsigned entry; 2255 * 2256 * Results: 2257 * None. 2258 * 2259 * Side effects: 2260 * tlbhi and tlblo will contain the TLB entry found. 2261 * 2262 *-------------------------------------------------------------------------- 2263 */ 2264LEAF(MachTLBRead) 2265 .set noreorder 2266 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2267 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2268 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2269 2270 sll a0, a0, VMMACH_TLB_INDEX_SHIFT 2271 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index register 2272 nop 2273 tlbr # Read from the TLB 2274 mfc0 t3, MACH_COP_0_TLB_HI # fetch the hi entry 2275 mfc0 t4, MACH_COP_0_TLB_LOW # fetch the low entry 2276 sw t3, tlbhi 2277 sw t4, tlblo 2278 2279 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2280 j ra 2281 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2282 .set reorder 2283END(MachTLBRead) 2284 2285/*-------------------------------------------------------------------------- 2286 * 2287 * MachTLBGetPID -- 2288 * 2289 * MachTLBGetPID() 2290 * 2291 * Results: 2292 * Returns the current TLB pid reg. 2293 * 2294 * Side effects: 2295 * None. 2296 * 2297 *-------------------------------------------------------------------------- 2298 */ 2299LEAF(MachTLBGetPID) 2300 .set noreorder 2301 mfc0 v0, MACH_COP_0_TLB_HI # get PID 2302 nop 2303 and v0, v0, VMMACH_TLB_PID # mask off PID 2304 j ra 2305 srl v0, v0, VMMACH_TLB_PID_SHIFT # put PID in right spot 2306 .set reorder 2307END(MachTLBGetPID) 2308 2309/* 2310 * Return the current value of the cause register. 2311 */ 2312LEAF(MachGetCauseReg) 2313 .set noreorder 2314 mfc0 v0, MACH_COP_0_CAUSE_REG 2315 j ra 2316 nop 2317 .set reorder 2318END(MachGetCauseReg) 2319#endif /* DEBUG */ 2320 2321/*---------------------------------------------------------------------------- 2322 * 2323 * MachSwitchFPState -- 2324 * 2325 * Save the current state into 'from' and restore it from 'to'. 2326 * 2327 * MachSwitchFPState(from, to) 2328 * struct proc *from; 2329 * struct user *to; 2330 * 2331 * Results: 2332 * None. 2333 * 2334 * Side effects: 2335 * None. 2336 * 2337 *---------------------------------------------------------------------------- 2338 */ 2339LEAF(MachSwitchFPState) 2340 .set noreorder 2341 mfc0 t1, MACH_COP_0_STATUS_REG # Save old SR 2342 li t0, MACH_SR_COP_1_BIT # enable the coprocessor 2343 mtc0 t0, MACH_COP_0_STATUS_REG 2344 2345 beq a0, zero, 1f # skip save if NULL pointer 2346 nop 2347/* 2348 * First read out the status register to make sure that all FP operations 2349 * have completed. 2350 */ 2351 lw a0, P_ADDR(a0) # get pointer to pcb for proc 2352 cfc1 t0, MACH_FPC_CSR # stall til FP done 2353 cfc1 t0, MACH_FPC_CSR # now get status 2354 li t3, ~MACH_SR_COP_1_BIT 2355 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register 2356 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status 2357 and t2, t2, t3 # clear COP_1 enable bit 2358 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register 2359/* 2360 * Save the floating point registers. 2361 */ 2362 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) 2363 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) 2364 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) 2365 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) 2366 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) 2367 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) 2368 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) 2369 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) 2370 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) 2371 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) 2372 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) 2373 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) 2374 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) 2375 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) 2376 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) 2377 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) 2378 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) 2379 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) 2380 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) 2381 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) 2382 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) 2383 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) 2384 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) 2385 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) 2386 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) 2387 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) 2388 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) 2389 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) 2390 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) 2391 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) 2392 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) 2393 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) 2394 23951: 2396/* 2397 * Restore the floating point registers. 2398 */ 2399 lw t0, U_PCB_FPREGS+(32 * 4)(a1) # get status register 2400 lwc1 $f0, U_PCB_FPREGS+(0 * 4)(a1) 2401 lwc1 $f1, U_PCB_FPREGS+(1 * 4)(a1) 2402 lwc1 $f2, U_PCB_FPREGS+(2 * 4)(a1) 2403 lwc1 $f3, U_PCB_FPREGS+(3 * 4)(a1) 2404 lwc1 $f4, U_PCB_FPREGS+(4 * 4)(a1) 2405 lwc1 $f5, U_PCB_FPREGS+(5 * 4)(a1) 2406 lwc1 $f6, U_PCB_FPREGS+(6 * 4)(a1) 2407 lwc1 $f7, U_PCB_FPREGS+(7 * 4)(a1) 2408 lwc1 $f8, U_PCB_FPREGS+(8 * 4)(a1) 2409 lwc1 $f9, U_PCB_FPREGS+(9 * 4)(a1) 2410 lwc1 $f10, U_PCB_FPREGS+(10 * 4)(a1) 2411 lwc1 $f11, U_PCB_FPREGS+(11 * 4)(a1) 2412 lwc1 $f12, U_PCB_FPREGS+(12 * 4)(a1) 2413 lwc1 $f13, U_PCB_FPREGS+(13 * 4)(a1) 2414 lwc1 $f14, U_PCB_FPREGS+(14 * 4)(a1) 2415 lwc1 $f15, U_PCB_FPREGS+(15 * 4)(a1) 2416 lwc1 $f16, U_PCB_FPREGS+(16 * 4)(a1) 2417 lwc1 $f17, U_PCB_FPREGS+(17 * 4)(a1) 2418 lwc1 $f18, U_PCB_FPREGS+(18 * 4)(a1) 2419 lwc1 $f19, U_PCB_FPREGS+(19 * 4)(a1) 2420 lwc1 $f20, U_PCB_FPREGS+(20 * 4)(a1) 2421 lwc1 $f21, U_PCB_FPREGS+(21 * 4)(a1) 2422 lwc1 $f22, U_PCB_FPREGS+(22 * 4)(a1) 2423 lwc1 $f23, U_PCB_FPREGS+(23 * 4)(a1) 2424 lwc1 $f24, U_PCB_FPREGS+(24 * 4)(a1) 2425 lwc1 $f25, U_PCB_FPREGS+(25 * 4)(a1) 2426 lwc1 $f26, U_PCB_FPREGS+(26 * 4)(a1) 2427 lwc1 $f27, U_PCB_FPREGS+(27 * 4)(a1) 2428 lwc1 $f28, U_PCB_FPREGS+(28 * 4)(a1) 2429 lwc1 $f29, U_PCB_FPREGS+(29 * 4)(a1) 2430 lwc1 $f30, U_PCB_FPREGS+(30 * 4)(a1) 2431 lwc1 $f31, U_PCB_FPREGS+(31 * 4)(a1) 2432 2433 and t0, t0, ~MACH_FPC_EXCEPTION_BITS 2434 ctc1 t0, MACH_FPC_CSR 2435 nop 2436 2437 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register. 2438 j ra 2439 nop 2440 .set reorder 2441END(MachSwitchFPState) 2442 2443/*---------------------------------------------------------------------------- 2444 * 2445 * MachSaveCurFPState -- 2446 * 2447 * Save the current floating point coprocessor state. 2448 * 2449 * MachSaveCurFPState(p) 2450 * struct proc *p; 2451 * 2452 * Results: 2453 * None. 2454 * 2455 * Side effects: 2456 * machFPCurProcPtr is cleared. 2457 * 2458 *---------------------------------------------------------------------------- 2459 */ 2460LEAF(MachSaveCurFPState) 2461 .set noreorder 2462 lw a0, P_ADDR(a0) # get pointer to pcb for proc 2463 mfc0 t1, MACH_COP_0_STATUS_REG # Disable interrupts and 2464 li t0, MACH_SR_COP_1_BIT # enable the coprocessor 2465 mtc0 t0, MACH_COP_0_STATUS_REG 2466 sw zero, machFPCurProcPtr # indicate state has been saved 2467/* 2468 * First read out the status register to make sure that all FP operations 2469 * have completed. 2470 */ 2471 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register 2472 li t3, ~MACH_SR_COP_1_BIT 2473 and t2, t2, t3 # clear COP_1 enable bit 2474 cfc1 t0, MACH_FPC_CSR # stall til FP done 2475 cfc1 t0, MACH_FPC_CSR # now get status 2476 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register 2477 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status 2478/* 2479 * Save the floating point registers. 2480 */ 2481 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) 2482 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) 2483 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) 2484 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) 2485 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) 2486 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) 2487 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) 2488 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) 2489 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) 2490 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) 2491 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) 2492 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) 2493 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) 2494 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) 2495 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) 2496 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) 2497 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) 2498 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) 2499 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) 2500 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) 2501 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) 2502 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) 2503 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) 2504 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) 2505 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) 2506 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) 2507 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) 2508 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) 2509 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) 2510 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) 2511 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) 2512 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) 2513 2514 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register. 2515 j ra 2516 nop 2517 .set reorder 2518END(MachSaveCurFPState) 2519 2520/*---------------------------------------------------------------------------- 2521 * 2522 * MachFPInterrupt -- 2523 * 2524 * Handle a floating point interrupt. 2525 * 2526 * MachFPInterrupt(statusReg, causeReg, pc) 2527 * unsigned statusReg; 2528 * unsigned causeReg; 2529 * unsigned pc; 2530 * 2531 * Results: 2532 * None. 2533 * 2534 * Side effects: 2535 * None. 2536 * 2537 *---------------------------------------------------------------------------- 2538 */ 2539NON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra) 2540 .set noreorder 2541 subu sp, sp, STAND_FRAME_SIZE 2542 mfc0 t0, MACH_COP_0_STATUS_REG 2543 sw ra, STAND_RA_OFFSET(sp) 2544 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2545 2546 or t1, t0, MACH_SR_COP_1_BIT 2547 mtc0 t1, MACH_COP_0_STATUS_REG 2548 nop 2549 nop 2550 cfc1 t1, MACH_FPC_CSR # stall til FP done 2551 cfc1 t1, MACH_FPC_CSR # now get status 2552 nop 2553 .set reorder 2554 sll t2, t1, (31 - 17) # unimplemented operation? 2555 bgez t2, 3f # no, normal trap 2556/* 2557 * We got an unimplemented operation trap so 2558 * fetch the instruction, compute the next PC and emulate the instruction. 2559 */ 2560 bgez a1, 1f # Check the branch delay bit. 2561/* 2562 * The instruction is in the branch delay slot so the branch will have to 2563 * be emulated to get the resulting PC. 2564 */ 2565 sw a2, STAND_FRAME_SIZE + 8(sp) 2566 li a0, UADDR+U_PCB_REGS # first arg is ptr to CPU registers 2567 move a1, a2 # second arg is instruction PC 2568 move a2, t1 # third arg is floating point CSR 2569 move a3, zero # fourth arg is FALSE 2570 jal MachEmulateBranch # compute PC after branch 2571/* 2572 * Now load the floating-point instruction in the branch delay slot 2573 * to be emulated. 2574 */ 2575 lw a2, STAND_FRAME_SIZE + 8(sp) # restore EXC pc 2576 lw a0, 4(a2) # a0 = coproc instruction 2577 b 2f 2578/* 2579 * This is not in the branch delay slot so calculate the resulting 2580 * PC (epc + 4) into v0 and continue to MachEmulateFP(). 2581 */ 25821: 2583 lw a0, 0(a2) # a0 = coproc instruction 2584 addu v0, a2, 4 # v0 = next pc 25852: 2586 sw v0, UADDR+U_PCB_REGS+(PC * 4) # save new pc 2587/* 2588 * Check to see if the instruction to be emulated is a floating-point 2589 * instruction. 2590 */ 2591 srl a3, a0, MACH_OPCODE_SHIFT 2592 beq a3, MACH_OPCODE_C1, 4f # this should never fail 2593/* 2594 * Send a floating point exception signal to the current process. 2595 */ 25963: 2597 lw a0, curproc # get current process 2598 cfc1 a2, MACH_FPC_CSR # code = FP execptions 2599 li a1, SIGFPE 2600 ctc1 zero, MACH_FPC_CSR # Clear exceptions 2601 jal trapsignal 2602 b FPReturn 2603 2604/* 2605 * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate. 2606 */ 26074: 2608 jal MachEmulateFP 2609 2610/* 2611 * Turn off the floating point coprocessor and return. 2612 */ 2613FPReturn: 2614 .set noreorder 2615 mfc0 t0, MACH_COP_0_STATUS_REG 2616 lw ra, STAND_RA_OFFSET(sp) 2617 and t0, t0, ~MACH_SR_COP_1_BIT 2618 mtc0 t0, MACH_COP_0_STATUS_REG 2619 j ra 2620 addu sp, sp, STAND_FRAME_SIZE 2621 .set reorder 2622END(MachFPInterrupt) 2623 2624/*---------------------------------------------------------------------------- 2625 * 2626 * MachConfigCache -- 2627 * 2628 * Size the caches. 2629 * NOTE: should only be called from mach_init(). 2630 * 2631 * Results: 2632 * None. 2633 * 2634 * Side effects: 2635 * The size of the data cache is stored into machDataCacheSize and the 2636 * size of instruction cache is stored into machInstCacheSize. 2637 * 2638 *---------------------------------------------------------------------------- 2639 */ 2640NON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra) 2641 .set noreorder 2642 subu sp, sp, STAND_FRAME_SIZE 2643 sw ra, STAND_RA_OFFSET(sp) # Save return address. 2644 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2645 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2646 la v0, 1f 2647 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2648 j v0 2649 nop 26501: 2651/* 2652 * This works because jal doesn't change pc[31..28] and the 2653 * linker still thinks SizeCache is in the cached region so it computes 2654 * the correct address without complaining. 2655 */ 2656 jal SizeCache # Get the size of the d-cache. 2657 nop 2658 sw v0, machDataCacheSize 2659 nop # Make sure sw out of pipe 2660 nop 2661 nop 2662 nop 2663 li v0, MACH_SR_SWAP_CACHES # Swap caches 2664 mtc0 v0, MACH_COP_0_STATUS_REG 2665 nop # Insure caches stable 2666 nop 2667 nop 2668 nop 2669 jal SizeCache # Get the size of the i-cache. 2670 nop 2671 sw v0, machInstCacheSize 2672 nop # Make sure sw out of pipe 2673 nop 2674 nop 2675 nop 2676 mtc0 zero, MACH_COP_0_STATUS_REG # Swap back caches. 2677 nop 2678 nop 2679 nop 2680 nop 2681 la t0, 1f 2682 j t0 # Back to cached mode 2683 nop 26841: 2685 lw ra, STAND_RA_OFFSET(sp) # Restore return addr 2686 addu sp, sp, STAND_FRAME_SIZE # Restore sp. 2687 j ra 2688 nop 2689 .set reorder 2690END(MachConfigCache) 2691 2692/*---------------------------------------------------------------------------- 2693 * 2694 * SizeCache -- 2695 * 2696 * Get the size of the cache. 2697 * 2698 * Results: 2699 * The size of the cache. 2700 * 2701 * Side effects: 2702 * None. 2703 * 2704 *---------------------------------------------------------------------------- 2705 */ 2706LEAF(SizeCache) 2707 .set noreorder 2708 mfc0 t0, MACH_COP_0_STATUS_REG # Save the current status reg. 2709 nop 2710 or v0, t0, MACH_SR_ISOL_CACHES # Isolate the caches. 2711 nop # Make sure no stores in pipe 2712 mtc0 v0, MACH_COP_0_STATUS_REG 2713 nop # Make sure isolated 2714 nop 2715 nop 2716/* 2717 * Clear cache size boundaries. 2718 */ 2719 li v0, MACH_MIN_CACHE_SIZE 27201: 2721 sw zero, MACH_CACHED_MEMORY_ADDR(v0) # Clear cache memory 2722 sll v0, v0, 1 2723 bleu v0, +MACH_MAX_CACHE_SIZE, 1b 2724 nop 2725 li v0, -1 2726 sw v0, MACH_CACHED_MEMORY_ADDR(zero) # Store marker in cache 2727 li v0, MACH_MIN_CACHE_SIZE 27282: 2729 lw v1, MACH_CACHED_MEMORY_ADDR(v0) # Look for marker 2730 nop 2731 bne v1, zero, 3f # Found marker. 2732 nop 2733 sll v0, v0, 1 # cache size * 2 2734 bleu v0, +MACH_MAX_CACHE_SIZE, 2b # keep looking 2735 nop 2736 move v0, zero # must be no cache 27373: 2738 mtc0 t0, MACH_COP_0_STATUS_REG 2739 nop # Make sure unisolated 2740 nop 2741 nop 2742 nop 2743 j ra 2744 nop 2745 .set reorder 2746END(SizeCache) 2747 2748/*---------------------------------------------------------------------------- 2749 * 2750 * MachFlushCache -- 2751 * 2752 * Flush the caches. 2753 * 2754 * Results: 2755 * None. 2756 * 2757 * Side effects: 2758 * The contents of the caches is flushed. 2759 * 2760 *---------------------------------------------------------------------------- 2761 */ 2762LEAF(MachFlushCache) 2763 .set noreorder 2764 lw t1, machInstCacheSize # Must load before isolating 2765 lw t2, machDataCacheSize # Must load before isolating 2766 mfc0 t3, MACH_COP_0_STATUS_REG # Save the status register. 2767 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2768 la v0, 1f 2769 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2770 j v0 2771 nop 2772/* 2773 * Flush the instruction cache. 2774 */ 27751: 2776 li v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES 2777 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap caches. 2778 li t0, MACH_UNCACHED_MEMORY_ADDR 2779 subu t0, t0, t1 2780 li t1, MACH_UNCACHED_MEMORY_ADDR 2781 la v0, 1f # Run cached 2782 j v0 2783 nop 27841: 2785 addu t0, t0, 4 2786 bne t0, t1, 1b 2787 sb zero, -4(t0) 2788 2789 la v0, 1f 2790 or v0, MACH_UNCACHED_MEMORY_ADDR 2791 j v0 # Run uncached 2792 nop 2793/* 2794 * Flush the data cache. 2795 */ 27961: 2797 li v0, MACH_SR_ISOL_CACHES 2798 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap back caches 2799 li t0, MACH_UNCACHED_MEMORY_ADDR 2800 subu t0, t0, t2 2801 la v0, 1f 2802 j v0 # Back to cached mode 2803 nop 28041: 2805 addu t0, t0, 4 2806 bne t0, t1, 1b 2807 sb zero, -4(t0) 2808 2809 nop # Insure isolated stores 2810 nop # out of pipe. 2811 nop 2812 nop 2813 mtc0 t3, MACH_COP_0_STATUS_REG # Restore status reg. 2814 nop # Insure cache unisolated. 2815 nop 2816 nop 2817 nop 2818 j ra 2819 nop 2820 .set reorder 2821END(MachFlushCache) 2822 2823/*---------------------------------------------------------------------------- 2824 * 2825 * MachFlushICache -- 2826 * 2827 * void MachFlushICache(addr, len) 2828 * vm_offset_t addr, len; 2829 * 2830 * Flush instruction cache for range of addr to addr + len - 1. 2831 * The address can be any valid address so long as no TLB misses occur. 2832 * 2833 * Results: 2834 * None. 2835 * 2836 * Side effects: 2837 * The contents of the cache is flushed. 2838 * 2839 *---------------------------------------------------------------------------- 2840 */ 2841LEAF(MachFlushICache) 2842 .set noreorder 2843 mfc0 t0, MACH_COP_0_STATUS_REG # Save SR 2844 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2845 2846 la v1, 1f 2847 or v1, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2848 j v1 2849 nop 28501: 2851 bc0f 1b # make sure stores are complete 2852 li v1, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES 2853 mtc0 v1, MACH_COP_0_STATUS_REG 2854 nop 2855 addu a1, a1, a0 # compute ending address 28561: 2857 addu a0, a0, 4 2858 bne a0, a1, 1b 2859 sb zero, -4(a0) 2860 2861 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts 2862 j ra # return and run cached 2863 nop 2864 .set reorder 2865END(MachFlushICache) 2866 2867#ifdef KADB 2868/* 2869 * Read a long and return it. 2870 * Note: addresses can be unaligned! 2871 * 2872 * long 2873L* kdbpeek(addr) 2874L* caddt_t addr; 2875L* { 2876L* return (*(long *)addr); 2877L* } 2878 */ 2879LEAF(kdbpeek) 2880 li v0, KADBERR 2881 sw v0, UADDR+U_PCB_ONFAULT 2882 and v0, a0, 3 # unaligned address? 2883 bne v0, zero, 1f 2884 lw v0, (a0) # aligned access 2885 b 2f 28861: 2887 lwr v0, 0(a0) # get next 4 bytes (unaligned) 2888 lwl v0, 3(a0) 28892: 2890 sw zero, UADDR+U_PCB_ONFAULT 2891 j ra # made it w/o errors 2892kadberr: 2893 li v0, 1 # trap sends us here 2894 sw v0, kdbmkfault 2895 j ra 2896END(kdbpeek) 2897 2898/* 2899 * Write a long to 'addr'. 2900 * Note: addresses can be unaligned! 2901 * 2902L* void 2903L* kdbpoke(addr, value) 2904L* caddt_t addr; 2905L* long value; 2906L* { 2907L* *(long *)addr = value; 2908L* } 2909 */ 2910LEAF(kdbpoke) 2911 li v0, KADBERR 2912 sw v0, UADDR+U_PCB_ONFAULT 2913 and v0, a0, 3 # unaligned address? 2914 bne v0, zero, 1f 2915 sw a1, (a0) # aligned access 2916 b 2f 29171: 2918 swr a1, 0(a0) # store next 4 bytes (unaligned) 2919 swl a1, 3(a0) 2920 and a0, a0, ~3 # align address for cache flush 29212: 2922 sw zero, UADDR+U_PCB_ONFAULT 2923 li a1, 8 2924 b MachFlushICache # flush instruction cache 2925END(kdbpoke) 2926 2927/* 2928 * Save registers and state so we can do a 'kdbreset' (like longjmp) later. 2929 * Always returns zero. 2930 * 2931L* int kdb_savearea[11]; 2932L* 2933L* int 2934L* kdbsetexit() 2935L* { 2936L* kdb_savearea[0] = 0; 2937L* return (0); 2938L* } 2939 */ 2940 .comm kdb_savearea, (11 * 4) 2941 2942LEAF(kdbsetexit) 2943 .set noreorder 2944 la a0, kdb_savearea 2945 sw s0, 0(a0) 2946 sw s1, 4(a0) 2947 sw s2, 8(a0) 2948 sw s3, 12(a0) 2949 sw s4, 16(a0) 2950 sw s5, 20(a0) 2951 sw s6, 24(a0) 2952 sw s7, 28(a0) 2953 sw sp, 32(a0) 2954 sw s8, 36(a0) 2955 sw ra, 40(a0) 2956 j ra 2957 move v0, zero 2958 .set reorder 2959END(kdbsetexit) 2960 2961/* 2962 * Restore registers and state (like longjmp) and return x. 2963 * 2964L* int 2965L* kdbreset(x) 2966L* { 2967L* return (x); 2968L* } 2969 */ 2970LEAF(kdbreset) 2971 .set noreorder 2972 la v0, kdb_savearea 2973 lw ra, 40(v0) 2974 lw s0, 0(v0) 2975 lw s1, 4(v0) 2976 lw s2, 8(v0) 2977 lw s3, 12(v0) 2978 lw s4, 16(v0) 2979 lw s5, 20(v0) 2980 lw s6, 24(v0) 2981 lw s7, 28(v0) 2982 lw sp, 32(v0) 2983 lw s8, 36(v0) 2984 j ra 2985 move v0, a0 2986 .set reorder 2987END(kdbreset) 2988 2989/* 2990 * Trap into the debugger. 2991 * 2992L* void 2993L* kdbpanic() 2994L* { 2995L* } 2996 */ 2997LEAF(kdbpanic) 2998 break MACH_BREAK_KDB_VAL 2999 j ra 3000END(kdbpanic) 3001#endif /* KADB */ 3002