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