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