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