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