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.7 (Berkeley) 06/02/95 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#ifdef DEBUG 880 lw a1, intr_level 881 sw a0, STAND_FRAME_SIZE(sp) 882 beq a1, zero, 1f 883 nop 884 PANIC("cpu_switch: intr_level %d") # can't sleep in interrupt() 8851: 886#endif 887 lw t2, cnt+V_SWTCH # for statistics 888 lw t1, whichqs # look for non-empty queue 889 sw s0, UADDR+U_PCB_CONTEXT+0 # do a 'savectx()' 890 sw s1, UADDR+U_PCB_CONTEXT+4 891 sw s2, UADDR+U_PCB_CONTEXT+8 892 sw s3, UADDR+U_PCB_CONTEXT+12 893 mfc0 t0, MACH_COP_0_STATUS_REG # t0 = saved status register 894 sw s4, UADDR+U_PCB_CONTEXT+16 895 sw s5, UADDR+U_PCB_CONTEXT+20 896 sw s6, UADDR+U_PCB_CONTEXT+24 897 sw s7, UADDR+U_PCB_CONTEXT+28 898 sw s8, UADDR+U_PCB_CONTEXT+36 899 sw ra, UADDR+U_PCB_CONTEXT+40 # save return address 900 sw t0, UADDR+U_PCB_CONTEXT+44 # save status register 901 addu t2, t2, 1 902 sw t2, cnt+V_SWTCH 903 beq t1, zero, idle # if none, idle 904 mtc0 zero, MACH_COP_0_STATUS_REG # Disable all interrupts 905sw1: 906 nop # wait for intrs disabled 907 nop 908 lw t0, whichqs # look for non-empty queue 909 li t2, -1 # t2 = lowest bit set 910 beq t0, zero, idle # if none, idle 911 move t3, t0 # t3 = saved whichqs 9121: 913 addu t2, t2, 1 914 and t1, t0, 1 # bit set? 915 beq t1, zero, 1b 916 srl t0, t0, 1 # try next bit 917/* 918 * Remove process from queue. 919 */ 920 sll t0, t2, 3 921 la t1, qs 922 addu t0, t0, t1 # t0 = qp = &qs[highbit] 923 lw a0, P_FORW(t0) # a0 = p = highest pri process 924 nop 925 lw v0, P_FORW(a0) # v0 = p->p_forw 926 bne t0, a0, 2f # make sure something in queue 927 sw v0, P_FORW(t0) # qp->ph_link = p->p_forw; 928 PANIC("cpu_switch") # nothing in queue 9292: 930 sw t0, P_BACK(v0) # p->p_forw->p_back = qp 931 bne v0, t0, 3f # queue still not empty 932 sw zero, P_BACK(a0) ## for firewall checking 933 li v1, 1 # compute bit in 'whichqs' 934 sll v1, v1, t2 935 xor t3, t3, v1 # clear bit in 'whichqs' 936 sw t3, whichqs 9373: 938/* 939 * Switch to new context. 940 */ 941 sw zero, want_resched 942 jal pmap_alloc_tlbpid # v0 = TLB PID 943 move s0, a0 # BDSLOT: save p 944 sw s0, curproc # set curproc 945 sll v0, v0, VMMACH_TLB_PID_SHIFT # v0 = aligned PID 946 lw t0, P_UPTE+0(s0) # t0 = first u. pte 947 lw t1, P_UPTE+4(s0) # t1 = 2nd u. pte 948 or v0, v0, UADDR # v0 = first HI entry 949/* 950 * Resume process indicated by the pte's for its u struct 951 * NOTE: This is hard coded to UPAGES == 2. 952 * Also, there should be no TLB faults at this point. 953 */ 954 mtc0 zero, MACH_COP_0_TLB_INDEX # set the index register 955 mtc0 v0, MACH_COP_0_TLB_HI # init high entry 956 mtc0 t0, MACH_COP_0_TLB_LOW # init low entry 957 li t0, 1 << VMMACH_TLB_INDEX_SHIFT 958 tlbwi # Write the TLB entry. 959 addu v0, v0, NBPG # 2nd HI entry 960 mtc0 t0, MACH_COP_0_TLB_INDEX # set the index register 961 mtc0 v0, MACH_COP_0_TLB_HI # init high entry 962 mtc0 t1, MACH_COP_0_TLB_LOW # init low entry 963 nop 964 tlbwi # Write the TLB entry. 965/* 966 * Now running on new u struct. 967 * Restore registers and return. 968 */ 969 lw v0, UADDR+U_PCB_CONTEXT+44 # restore kernel context 970 lw ra, UADDR+U_PCB_CONTEXT+40 971 lw s0, UADDR+U_PCB_CONTEXT+0 972 lw s1, UADDR+U_PCB_CONTEXT+4 973 lw s2, UADDR+U_PCB_CONTEXT+8 974 lw s3, UADDR+U_PCB_CONTEXT+12 975 lw s4, UADDR+U_PCB_CONTEXT+16 976 lw s5, UADDR+U_PCB_CONTEXT+20 977 lw s6, UADDR+U_PCB_CONTEXT+24 978 lw s7, UADDR+U_PCB_CONTEXT+28 979 lw sp, UADDR+U_PCB_CONTEXT+32 980 lw s8, UADDR+U_PCB_CONTEXT+36 981 mtc0 v0, MACH_COP_0_STATUS_REG 982 j ra 983 li v0, 1 # possible return to 'savectx()' 984END(cpu_switch) 985 986/* 987 * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to 988 * user text space. 989 * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to 990 * user data space. 991 */ 992LEAF(fuword) 993ALEAF(fuiword) 994 blt a0, zero, fswberr # make sure address is in user space 995 li v0, FSWBERR 996 sw v0, UADDR+U_PCB_ONFAULT 997 lw v0, 0(a0) # fetch word 998 j ra 999 sw zero, UADDR+U_PCB_ONFAULT 1000END(fuword) 1001 1002LEAF(fusword) 1003ALEAF(fuisword) 1004 blt a0, zero, fswberr # make sure address is in user space 1005 li v0, FSWBERR 1006 sw v0, UADDR+U_PCB_ONFAULT 1007 lhu v0, 0(a0) # fetch short 1008 j ra 1009 sw zero, UADDR+U_PCB_ONFAULT 1010END(fusword) 1011 1012LEAF(fubyte) 1013ALEAF(fuibyte) 1014 blt a0, zero, fswberr # make sure address is in user space 1015 li v0, FSWBERR 1016 sw v0, UADDR+U_PCB_ONFAULT 1017 lbu v0, 0(a0) # fetch byte 1018 j ra 1019 sw zero, UADDR+U_PCB_ONFAULT 1020END(fubyte) 1021 1022LEAF(suword) 1023 blt a0, zero, fswberr # make sure address is in user space 1024 li v0, FSWBERR 1025 sw v0, UADDR+U_PCB_ONFAULT 1026 sw a1, 0(a0) # store word 1027 sw zero, UADDR+U_PCB_ONFAULT 1028 j ra 1029 move v0, zero 1030END(suword) 1031 1032/* 1033 * Have to flush instruction cache afterwards. 1034 */ 1035LEAF(suiword) 1036 blt a0, zero, fswberr # make sure address is in user space 1037 li v0, FSWBERR 1038 sw v0, UADDR+U_PCB_ONFAULT 1039 sw a1, 0(a0) # store word 1040 sw zero, UADDR+U_PCB_ONFAULT 1041 move v0, zero 1042 b MachFlushICache # NOTE: this should not clobber v0! 1043 li a1, 4 # size of word 1044END(suiword) 1045 1046/* 1047 * Will have to flush the instruction cache if byte merging is done in hardware. 1048 */ 1049LEAF(susword) 1050ALEAF(suisword) 1051 blt a0, zero, fswberr # make sure address is in user space 1052 li v0, FSWBERR 1053 sw v0, UADDR+U_PCB_ONFAULT 1054 sh a1, 0(a0) # store short 1055 sw zero, UADDR+U_PCB_ONFAULT 1056 j ra 1057 move v0, zero 1058END(susword) 1059 1060LEAF(subyte) 1061ALEAF(suibyte) 1062 blt a0, zero, fswberr # make sure address is in user space 1063 li v0, FSWBERR 1064 sw v0, UADDR+U_PCB_ONFAULT 1065 sb a1, 0(a0) # store byte 1066 sw zero, UADDR+U_PCB_ONFAULT 1067 j ra 1068 move v0, zero 1069END(subyte) 1070 1071LEAF(fswberr) 1072 j ra 1073 li v0, -1 1074END(fswberr) 1075 1076/* 1077 * fuswintr and suswintr are just like fusword and susword except that if 1078 * the page is not in memory or would cause a trap, then we return an error. 1079 * The important thing is to prevent sleep() and switch(). 1080 */ 1081LEAF(fuswintr) 1082 blt a0, zero, fswintrberr # make sure address is in user space 1083 li v0, FSWINTRBERR 1084 sw v0, UADDR+U_PCB_ONFAULT 1085 lhu v0, 0(a0) # fetch short 1086 j ra 1087 sw zero, UADDR+U_PCB_ONFAULT 1088END(fuswintr) 1089 1090LEAF(suswintr) 1091 blt a0, zero, fswintrberr # make sure address is in user space 1092 li v0, FSWINTRBERR 1093 sw v0, UADDR+U_PCB_ONFAULT 1094 sh a1, 0(a0) # store short 1095 sw zero, UADDR+U_PCB_ONFAULT 1096 j ra 1097 move v0, zero 1098END(suswintr) 1099 1100LEAF(fswintrberr) 1101 j ra 1102 li v0, -1 1103END(fswintrberr) 1104 1105/* 1106 * Insert 'p' after 'q'. 1107 * _insque(p, q) 1108 * caddr_t p, q; 1109 */ 1110LEAF(_insque) 1111 lw v0, 0(a1) # v0 = q->next 1112 sw a1, 4(a0) # p->prev = q 1113 sw v0, 0(a0) # p->next = q->next 1114 sw a0, 4(v0) # q->next->prev = p 1115 j ra 1116 sw a0, 0(a1) # q->next = p 1117END(_insque) 1118 1119/* 1120 * Remove item 'p' from queue. 1121 * _remque(p) 1122 * caddr_t p; 1123 */ 1124LEAF(_remque) 1125 lw v0, 0(a0) # v0 = p->next 1126 lw v1, 4(a0) # v1 = p->prev 1127 nop 1128 sw v0, 0(v1) # p->prev->next = p->next 1129 j ra 1130 sw v1, 4(v0) # p->next->prev = p->prev 1131END(_remque) 1132 1133/* 1134 * This code is copied to the UTLB exception vector address to 1135 * handle user level TLB translation misses. 1136 * NOTE: This code must be relocatable!!! 1137 */ 1138 .globl MachUTLBMiss 1139MachUTLBMiss: 1140 .set noat 1141 mfc0 k0, MACH_COP_0_BAD_VADDR # get the virtual address 1142 lw k1, UADDR+U_PCB_SEGTAB # get the current segment table 1143 bltz k0, 1f # R3000 chip bug 1144 srl k0, k0, SEGSHIFT # compute segment table index 1145 sll k0, k0, 2 1146 addu k1, k1, k0 1147 mfc0 k0, MACH_COP_0_BAD_VADDR # get the virtual address 1148 lw k1, 0(k1) # get pointer to segment map 1149 srl k0, k0, PGSHIFT - 2 # compute segment map index 1150 andi k0, k0, (NPTEPG - 1) << 2 1151 beq k1, zero, 2f # invalid segment map 1152 addu k1, k1, k0 # index into segment map 1153 lw k0, 0(k1) # get page PTE 1154 nop 1155 beq k0, zero, 2f # dont load invalid entries 1156 mtc0 k0, MACH_COP_0_TLB_LOW 1157 mfc0 k1, MACH_COP_0_EXC_PC # get return address 1158 tlbwr # update TLB 1159 j k1 1160 rfe 11611: 1162 mfc0 k1, MACH_COP_0_EXC_PC # get return address 1163 nop 1164 j k1 1165 rfe 11662: 1167 j SlowFault # handle the rest 1168 nop 1169 .set at 1170 .globl MachUTLBMissEnd 1171MachUTLBMissEnd: 1172 1173/* 1174 * This code is copied to the general exception vector address to 1175 * handle all execptions except RESET and UTLBMiss. 1176 * NOTE: This code must be relocatable!!! 1177 */ 1178 .globl MachException 1179MachException: 1180/* 1181 * Find out what mode we came from and jump to the proper handler. 1182 */ 1183 .set noat 1184 mfc0 k0, MACH_COP_0_STATUS_REG # Get the status register 1185 mfc0 k1, MACH_COP_0_CAUSE_REG # Get the cause register value. 1186 and k0, k0, MACH_SR_KU_PREV # test for user mode 1187 sll k0, k0, 3 # shift user bit for cause index 1188 and k1, k1, MACH_CR_EXC_CODE # Mask out the cause bits. 1189 or k1, k1, k0 # change index to user table 11901: 1191 la k0, machExceptionTable # get base of the jump table 1192 addu k0, k0, k1 # Get the address of the 1193 # function entry. Note that 1194 # the cause is already 1195 # shifted left by 2 bits so 1196 # we dont have to shift. 1197 lw k0, 0(k0) # Get the function address 1198 nop 1199 j k0 # Jump to the function. 1200 nop 1201 .set at 1202 .globl MachExceptionEnd 1203MachExceptionEnd: 1204 1205/* 1206 * We couldn't find a TLB entry. 1207 * Find out what mode we came from and call the appropriate handler. 1208 */ 1209SlowFault: 1210 .set noat 1211 mfc0 k0, MACH_COP_0_STATUS_REG 1212 nop 1213 and k0, k0, MACH_SR_KU_PREV 1214 bne k0, zero, MachUserGenException 1215 nop 1216 .set at 1217/* 1218 * Fall though ... 1219 */ 1220 1221/*---------------------------------------------------------------------------- 1222 * 1223 * MachKernGenException -- 1224 * 1225 * Handle an exception from kernel mode. 1226 * 1227 * Results: 1228 * None. 1229 * 1230 * Side effects: 1231 * None. 1232 * 1233 *---------------------------------------------------------------------------- 1234 */ 1235 1236/* 1237 * The kernel exception stack contains 18 saved general registers, 1238 * the status register and the multiply lo and high registers. 1239 * In addition, we set this up for linkage conventions. 1240 */ 1241#define KERN_REG_SIZE (18 * 4) 1242#define KERN_REG_OFFSET (STAND_FRAME_SIZE) 1243#define KERN_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) 1244#define KERN_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) 1245#define KERN_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) 1246#define KERN_EXC_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) 1247 1248NNON_LEAF(MachKernGenException, KERN_EXC_FRAME_SIZE, ra) 1249 .set noat 1250#ifdef KADB 1251 la k0, kdbpcb # save registers for kadb 1252 sw s0, (S0 * 4)(k0) 1253 sw s1, (S1 * 4)(k0) 1254 sw s2, (S2 * 4)(k0) 1255 sw s3, (S3 * 4)(k0) 1256 sw s4, (S4 * 4)(k0) 1257 sw s5, (S5 * 4)(k0) 1258 sw s6, (S6 * 4)(k0) 1259 sw s7, (S7 * 4)(k0) 1260 sw s8, (S8 * 4)(k0) 1261 sw gp, (GP * 4)(k0) 1262 sw sp, (SP * 4)(k0) 1263#endif 1264 subu sp, sp, KERN_EXC_FRAME_SIZE 1265 .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE) 1266/* 1267 * Save the relevant kernel registers onto the stack. 1268 * We don't need to save s0 - s8, sp and gp because 1269 * the compiler does it for us. 1270 */ 1271 sw AT, KERN_REG_OFFSET + 0(sp) 1272 sw v0, KERN_REG_OFFSET + 4(sp) 1273 sw v1, KERN_REG_OFFSET + 8(sp) 1274 sw a0, KERN_REG_OFFSET + 12(sp) 1275 mflo v0 1276 mfhi v1 1277 sw a1, KERN_REG_OFFSET + 16(sp) 1278 sw a2, KERN_REG_OFFSET + 20(sp) 1279 sw a3, KERN_REG_OFFSET + 24(sp) 1280 sw t0, KERN_REG_OFFSET + 28(sp) 1281 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1282 sw t1, KERN_REG_OFFSET + 32(sp) 1283 sw t2, KERN_REG_OFFSET + 36(sp) 1284 sw t3, KERN_REG_OFFSET + 40(sp) 1285 sw t4, KERN_REG_OFFSET + 44(sp) 1286 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1287 sw t5, KERN_REG_OFFSET + 48(sp) 1288 sw t6, KERN_REG_OFFSET + 52(sp) 1289 sw t7, KERN_REG_OFFSET + 56(sp) 1290 sw t8, KERN_REG_OFFSET + 60(sp) 1291 mfc0 a2, MACH_COP_0_BAD_VADDR # Third arg is the fault addr. 1292 sw t9, KERN_REG_OFFSET + 64(sp) 1293 sw ra, KERN_REG_OFFSET + 68(sp) 1294 sw v0, KERN_MULT_LO_OFFSET(sp) 1295 sw v1, KERN_MULT_HI_OFFSET(sp) 1296 mfc0 a3, MACH_COP_0_EXC_PC # Fourth arg is the pc. 1297 sw a0, KERN_SR_OFFSET(sp) 1298/* 1299 * Call the exception handler. 1300 */ 1301 jal trap 1302 sw a3, STAND_RA_OFFSET(sp) # for debugging 1303/* 1304 * Restore registers and return from the exception. 1305 * v0 contains the return address. 1306 */ 1307 lw a0, KERN_SR_OFFSET(sp) 1308 lw t0, KERN_MULT_LO_OFFSET(sp) 1309 lw t1, KERN_MULT_HI_OFFSET(sp) 1310 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1311 mtlo t0 1312 mthi t1 1313 move k0, v0 1314 lw AT, KERN_REG_OFFSET + 0(sp) 1315 lw v0, KERN_REG_OFFSET + 4(sp) 1316 lw v1, KERN_REG_OFFSET + 8(sp) 1317 lw a0, KERN_REG_OFFSET + 12(sp) 1318 lw a1, KERN_REG_OFFSET + 16(sp) 1319 lw a2, KERN_REG_OFFSET + 20(sp) 1320 lw a3, KERN_REG_OFFSET + 24(sp) 1321 lw t0, KERN_REG_OFFSET + 28(sp) 1322 lw t1, KERN_REG_OFFSET + 32(sp) 1323 lw t2, KERN_REG_OFFSET + 36(sp) 1324 lw t3, KERN_REG_OFFSET + 40(sp) 1325 lw t4, KERN_REG_OFFSET + 44(sp) 1326 lw t5, KERN_REG_OFFSET + 48(sp) 1327 lw t6, KERN_REG_OFFSET + 52(sp) 1328 lw t7, KERN_REG_OFFSET + 56(sp) 1329 lw t8, KERN_REG_OFFSET + 60(sp) 1330 lw t9, KERN_REG_OFFSET + 64(sp) 1331 lw ra, KERN_REG_OFFSET + 68(sp) 1332 addu sp, sp, KERN_EXC_FRAME_SIZE 1333 j k0 # Now return from the 1334 rfe # exception. 1335 .set at 1336END(MachKernGenException) 1337 1338/*---------------------------------------------------------------------------- 1339 * 1340 * MachUserGenException -- 1341 * 1342 * Handle an exception from user mode. 1343 * 1344 * Results: 1345 * None. 1346 * 1347 * Side effects: 1348 * None. 1349 * 1350 *---------------------------------------------------------------------------- 1351 */ 1352NNON_LEAF(MachUserGenException, STAND_FRAME_SIZE, ra) 1353 .set noat 1354 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 1355/* 1356 * Save all of the registers except for the kernel temporaries in u.u_pcb. 1357 */ 1358 sw AT, UADDR+U_PCB_REGS+(AST * 4) 1359 sw v0, UADDR+U_PCB_REGS+(V0 * 4) 1360 sw v1, UADDR+U_PCB_REGS+(V1 * 4) 1361 sw a0, UADDR+U_PCB_REGS+(A0 * 4) 1362 mflo v0 1363 sw a1, UADDR+U_PCB_REGS+(A1 * 4) 1364 sw a2, UADDR+U_PCB_REGS+(A2 * 4) 1365 sw a3, UADDR+U_PCB_REGS+(A3 * 4) 1366 sw t0, UADDR+U_PCB_REGS+(T0 * 4) 1367 mfhi v1 1368 sw t1, UADDR+U_PCB_REGS+(T1 * 4) 1369 sw t2, UADDR+U_PCB_REGS+(T2 * 4) 1370 sw t3, UADDR+U_PCB_REGS+(T3 * 4) 1371 sw t4, UADDR+U_PCB_REGS+(T4 * 4) 1372 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1373 sw t5, UADDR+U_PCB_REGS+(T5 * 4) 1374 sw t6, UADDR+U_PCB_REGS+(T6 * 4) 1375 sw t7, UADDR+U_PCB_REGS+(T7 * 4) 1376 sw s0, UADDR+U_PCB_REGS+(S0 * 4) 1377 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1378 sw s1, UADDR+U_PCB_REGS+(S1 * 4) 1379 sw s2, UADDR+U_PCB_REGS+(S2 * 4) 1380 sw s3, UADDR+U_PCB_REGS+(S3 * 4) 1381 sw s4, UADDR+U_PCB_REGS+(S4 * 4) 1382 mfc0 a2, MACH_COP_0_BAD_VADDR # Third arg is the fault addr 1383 sw s5, UADDR+U_PCB_REGS+(S5 * 4) 1384 sw s6, UADDR+U_PCB_REGS+(S6 * 4) 1385 sw s7, UADDR+U_PCB_REGS+(S7 * 4) 1386 sw t8, UADDR+U_PCB_REGS+(T8 * 4) 1387 mfc0 a3, MACH_COP_0_EXC_PC # Fourth arg is the pc. 1388 sw t9, UADDR+U_PCB_REGS+(T9 * 4) 1389 sw gp, UADDR+U_PCB_REGS+(GP * 4) 1390 sw sp, UADDR+U_PCB_REGS+(SP * 4) 1391 sw s8, UADDR+U_PCB_REGS+(S8 * 4) 1392 li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP 1393 sw ra, UADDR+U_PCB_REGS+(RA * 4) 1394 sw v0, UADDR+U_PCB_REGS+(MULLO * 4) 1395 sw v1, UADDR+U_PCB_REGS+(MULHI * 4) 1396 sw a0, UADDR+U_PCB_REGS+(SR * 4) 1397 # la gp, _gp # switch to kernel GP 1398 sw a3, UADDR+U_PCB_REGS+(PC * 4) 1399 sw a3, STAND_RA_OFFSET(sp) # for debugging 1400 .set at 1401 and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU. 1402 .set noat 1403/* 1404 * Call the exception handler. 1405 */ 1406 jal trap 1407 mtc0 t0, MACH_COP_0_STATUS_REG 1408/* 1409 * Restore user registers and return. NOTE: interrupts are enabled. 1410 */ 1411 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1412 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1413 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1414 mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts 1415 mtlo t0 1416 mthi t1 1417 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1418 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1419 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1420 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1421 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1422 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1423 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1424 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1425 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1426 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1427 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1428 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1429 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1430 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1431 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1432 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1433 lw s0, UADDR+U_PCB_REGS+(S0 * 4) 1434 lw s1, UADDR+U_PCB_REGS+(S1 * 4) 1435 lw s2, UADDR+U_PCB_REGS+(S2 * 4) 1436 lw s3, UADDR+U_PCB_REGS+(S3 * 4) 1437 lw s4, UADDR+U_PCB_REGS+(S4 * 4) 1438 lw s5, UADDR+U_PCB_REGS+(S5 * 4) 1439 lw s6, UADDR+U_PCB_REGS+(S6 * 4) 1440 lw s7, UADDR+U_PCB_REGS+(S7 * 4) 1441 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1442 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1443 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1444 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1445 lw s8, UADDR+U_PCB_REGS+(S8 * 4) 1446 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1447 j k0 1448 rfe 1449 .set at 1450END(MachUserGenException) 1451 1452/*---------------------------------------------------------------------------- 1453 * 1454 * MachKernIntr -- 1455 * 1456 * Handle an interrupt from kernel mode. 1457 * Interrupts use the standard kernel stack. 1458 * switch_exit sets up a kernel stack after exit so interrupts won't fail. 1459 * 1460 * Results: 1461 * None. 1462 * 1463 * Side effects: 1464 * None. 1465 * 1466 *---------------------------------------------------------------------------- 1467 */ 1468#define KINTR_REG_OFFSET (STAND_FRAME_SIZE) 1469#define KINTR_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE) 1470#define KINTR_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4) 1471#define KINTR_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8) 1472#define KINTR_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12) 1473 1474NNON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra) 1475 .set noat 1476 subu sp, sp, KINTR_FRAME_SIZE # allocate stack frame 1477 .mask 0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE) 1478/* 1479 * Save the relevant kernel registers onto the stack. 1480 * We don't need to save s0 - s8, sp and gp because 1481 * the compiler does it for us. 1482 */ 1483 sw AT, KINTR_REG_OFFSET + 0(sp) 1484 sw v0, KINTR_REG_OFFSET + 4(sp) 1485 sw v1, KINTR_REG_OFFSET + 8(sp) 1486 sw a0, KINTR_REG_OFFSET + 12(sp) 1487 mflo v0 1488 mfhi v1 1489 sw a1, KINTR_REG_OFFSET + 16(sp) 1490 sw a2, KINTR_REG_OFFSET + 20(sp) 1491 sw a3, KINTR_REG_OFFSET + 24(sp) 1492 sw t0, KINTR_REG_OFFSET + 28(sp) 1493 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1494 sw t1, KINTR_REG_OFFSET + 32(sp) 1495 sw t2, KINTR_REG_OFFSET + 36(sp) 1496 sw t3, KINTR_REG_OFFSET + 40(sp) 1497 sw t4, KINTR_REG_OFFSET + 44(sp) 1498 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1499 sw t5, KINTR_REG_OFFSET + 48(sp) 1500 sw t6, KINTR_REG_OFFSET + 52(sp) 1501 sw t7, KINTR_REG_OFFSET + 56(sp) 1502 sw t8, KINTR_REG_OFFSET + 60(sp) 1503 mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc. 1504 sw t9, KINTR_REG_OFFSET + 64(sp) 1505 sw ra, KINTR_REG_OFFSET + 68(sp) 1506 sw v0, KINTR_MULT_LO_OFFSET(sp) 1507 sw v1, KINTR_MULT_HI_OFFSET(sp) 1508 sw a0, KINTR_SR_OFFSET(sp) 1509/* 1510 * Call the interrupt handler. 1511 */ 1512 jal interrupt 1513 sw a2, STAND_RA_OFFSET(sp) # for debugging 1514/* 1515 * Restore registers and return from the interrupt. 1516 */ 1517 lw a0, KINTR_SR_OFFSET(sp) 1518 lw t0, KINTR_MULT_LO_OFFSET(sp) 1519 lw t1, KINTR_MULT_HI_OFFSET(sp) 1520 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1521 mtlo t0 1522 mthi t1 1523 lw k0, STAND_RA_OFFSET(sp) 1524 lw AT, KINTR_REG_OFFSET + 0(sp) 1525 lw v0, KINTR_REG_OFFSET + 4(sp) 1526 lw v1, KINTR_REG_OFFSET + 8(sp) 1527 lw a0, KINTR_REG_OFFSET + 12(sp) 1528 lw a1, KINTR_REG_OFFSET + 16(sp) 1529 lw a2, KINTR_REG_OFFSET + 20(sp) 1530 lw a3, KINTR_REG_OFFSET + 24(sp) 1531 lw t0, KINTR_REG_OFFSET + 28(sp) 1532 lw t1, KINTR_REG_OFFSET + 32(sp) 1533 lw t2, KINTR_REG_OFFSET + 36(sp) 1534 lw t3, KINTR_REG_OFFSET + 40(sp) 1535 lw t4, KINTR_REG_OFFSET + 44(sp) 1536 lw t5, KINTR_REG_OFFSET + 48(sp) 1537 lw t6, KINTR_REG_OFFSET + 52(sp) 1538 lw t7, KINTR_REG_OFFSET + 56(sp) 1539 lw t8, KINTR_REG_OFFSET + 60(sp) 1540 lw t9, KINTR_REG_OFFSET + 64(sp) 1541 lw ra, KINTR_REG_OFFSET + 68(sp) 1542 addu sp, sp, KINTR_FRAME_SIZE 1543 j k0 # Now return from the 1544 rfe # interrupt. 1545 .set at 1546END(MachKernIntr) 1547 1548/*---------------------------------------------------------------------------- 1549 * 1550 * MachUserIntr -- 1551 * 1552 * Handle an interrupt from user mode. 1553 * Note: we save minimal state in the u.u_pcb struct and use the standard 1554 * kernel stack since there has to be a u page if we came from user mode. 1555 * If there is a pending software interrupt, then save the remaining state 1556 * and call softintr(). This is all because if we call switch() inside 1557 * interrupt(), not all the user registers have been saved in u.u_pcb. 1558 * 1559 * Results: 1560 * None. 1561 * 1562 * Side effects: 1563 * None. 1564 * 1565 *---------------------------------------------------------------------------- 1566 */ 1567NNON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra) 1568 .set noat 1569 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 1570/* 1571 * Save the relevant user registers into the u.u_pcb struct. 1572 * We don't need to save s0 - s8 because 1573 * the compiler does it for us. 1574 */ 1575 sw AT, UADDR+U_PCB_REGS+(AST * 4) 1576 sw v0, UADDR+U_PCB_REGS+(V0 * 4) 1577 sw v1, UADDR+U_PCB_REGS+(V1 * 4) 1578 sw a0, UADDR+U_PCB_REGS+(A0 * 4) 1579 mflo v0 1580 mfhi v1 1581 sw a1, UADDR+U_PCB_REGS+(A1 * 4) 1582 sw a2, UADDR+U_PCB_REGS+(A2 * 4) 1583 sw a3, UADDR+U_PCB_REGS+(A3 * 4) 1584 sw t0, UADDR+U_PCB_REGS+(T0 * 4) 1585 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. 1586 sw t1, UADDR+U_PCB_REGS+(T1 * 4) 1587 sw t2, UADDR+U_PCB_REGS+(T2 * 4) 1588 sw t3, UADDR+U_PCB_REGS+(T3 * 4) 1589 sw t4, UADDR+U_PCB_REGS+(T4 * 4) 1590 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. 1591 sw t5, UADDR+U_PCB_REGS+(T5 * 4) 1592 sw t6, UADDR+U_PCB_REGS+(T6 * 4) 1593 sw t7, UADDR+U_PCB_REGS+(T7 * 4) 1594 sw t8, UADDR+U_PCB_REGS+(T8 * 4) 1595 mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc. 1596 sw t9, UADDR+U_PCB_REGS+(T9 * 4) 1597 sw gp, UADDR+U_PCB_REGS+(GP * 4) 1598 sw sp, UADDR+U_PCB_REGS+(SP * 4) 1599 sw ra, UADDR+U_PCB_REGS+(RA * 4) 1600 li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP 1601 sw v0, UADDR+U_PCB_REGS+(MULLO * 4) 1602 sw v1, UADDR+U_PCB_REGS+(MULHI * 4) 1603 sw a0, UADDR+U_PCB_REGS+(SR * 4) 1604 sw a2, UADDR+U_PCB_REGS+(PC * 4) 1605 # la gp, _gp # switch to kernel GP 1606 .set at 1607 and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU. 1608 .set noat 1609 mtc0 t0, MACH_COP_0_STATUS_REG 1610/* 1611 * Call the interrupt handler. 1612 */ 1613 jal interrupt 1614 sw a2, STAND_RA_OFFSET(sp) # for debugging 1615/* 1616 * Restore registers and return from the interrupt. 1617 */ 1618 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1619 lw v0, astpending # any pending interrupts? 1620 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs 1621 bne v0, zero, 1f # dont restore, call softintr 1622 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1623 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1624 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1625 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1626 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1627 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1628 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1629 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1630 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1631 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1632 mtlo t0 1633 mthi t1 1634 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1635 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1636 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1637 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1638 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1639 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1640 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1641 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1642 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1643 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1644 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1645 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1646 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1647 j k0 # Now return from the 1648 rfe # interrupt. 1649 16501: 1651/* 1652 * We have pending software interrupts; save remaining user state in u.u_pcb. 1653 */ 1654 sw s0, UADDR+U_PCB_REGS+(S0 * 4) 1655 sw s1, UADDR+U_PCB_REGS+(S1 * 4) 1656 sw s2, UADDR+U_PCB_REGS+(S2 * 4) 1657 sw s3, UADDR+U_PCB_REGS+(S3 * 4) 1658 sw s4, UADDR+U_PCB_REGS+(S4 * 4) 1659 sw s5, UADDR+U_PCB_REGS+(S5 * 4) 1660 sw s6, UADDR+U_PCB_REGS+(S6 * 4) 1661 sw s7, UADDR+U_PCB_REGS+(S7 * 4) 1662 sw s8, UADDR+U_PCB_REGS+(S8 * 4) 1663 li t0, MACH_HARD_INT_MASK | MACH_SR_INT_ENA_CUR 1664/* 1665 * Call the software interrupt handler. 1666 */ 1667 jal softintr 1668 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts (spl0) 1669/* 1670 * Restore user registers and return. NOTE: interrupts are enabled. 1671 */ 1672 lw a0, UADDR+U_PCB_REGS+(SR * 4) 1673 lw t0, UADDR+U_PCB_REGS+(MULLO * 4) 1674 lw t1, UADDR+U_PCB_REGS+(MULHI * 4) 1675 mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts 1676 mtlo t0 1677 mthi t1 1678 lw k0, UADDR+U_PCB_REGS+(PC * 4) 1679 lw AT, UADDR+U_PCB_REGS+(AST * 4) 1680 lw v0, UADDR+U_PCB_REGS+(V0 * 4) 1681 lw v1, UADDR+U_PCB_REGS+(V1 * 4) 1682 lw a0, UADDR+U_PCB_REGS+(A0 * 4) 1683 lw a1, UADDR+U_PCB_REGS+(A1 * 4) 1684 lw a2, UADDR+U_PCB_REGS+(A2 * 4) 1685 lw a3, UADDR+U_PCB_REGS+(A3 * 4) 1686 lw t0, UADDR+U_PCB_REGS+(T0 * 4) 1687 lw t1, UADDR+U_PCB_REGS+(T1 * 4) 1688 lw t2, UADDR+U_PCB_REGS+(T2 * 4) 1689 lw t3, UADDR+U_PCB_REGS+(T3 * 4) 1690 lw t4, UADDR+U_PCB_REGS+(T4 * 4) 1691 lw t5, UADDR+U_PCB_REGS+(T5 * 4) 1692 lw t6, UADDR+U_PCB_REGS+(T6 * 4) 1693 lw t7, UADDR+U_PCB_REGS+(T7 * 4) 1694 lw s0, UADDR+U_PCB_REGS+(S0 * 4) 1695 lw s1, UADDR+U_PCB_REGS+(S1 * 4) 1696 lw s2, UADDR+U_PCB_REGS+(S2 * 4) 1697 lw s3, UADDR+U_PCB_REGS+(S3 * 4) 1698 lw s4, UADDR+U_PCB_REGS+(S4 * 4) 1699 lw s5, UADDR+U_PCB_REGS+(S5 * 4) 1700 lw s6, UADDR+U_PCB_REGS+(S6 * 4) 1701 lw s7, UADDR+U_PCB_REGS+(S7 * 4) 1702 lw t8, UADDR+U_PCB_REGS+(T8 * 4) 1703 lw t9, UADDR+U_PCB_REGS+(T9 * 4) 1704 lw gp, UADDR+U_PCB_REGS+(GP * 4) 1705 lw sp, UADDR+U_PCB_REGS+(SP * 4) 1706 lw s8, UADDR+U_PCB_REGS+(S8 * 4) 1707 lw ra, UADDR+U_PCB_REGS+(RA * 4) 1708 j k0 1709 rfe 1710 .set at 1711END(MachUserIntr) 1712 1713#if 0 1714/*---------------------------------------------------------------------------- 1715 * 1716 * MachTLBModException -- 1717 * 1718 * Handle a TLB modified exception. 1719 * The BaddVAddr, Context, and EntryHi registers contain the failed 1720 * virtual address. 1721 * 1722 * Results: 1723 * None. 1724 * 1725 * Side effects: 1726 * None. 1727 * 1728 *---------------------------------------------------------------------------- 1729 */ 1730NLEAF(MachTLBModException) 1731 .set noat 1732 tlbp # find the TLB entry 1733 mfc0 k0, MACH_COP_0_TLB_LOW # get the physical address 1734 mfc0 k1, MACH_COP_0_TLB_INDEX # check to be sure its valid 1735 or k0, k0, VMMACH_TLB_MOD_BIT # update TLB 1736 blt k1, zero, 4f # not found!!! 1737 mtc0 k0, MACH_COP_0_TLB_LOW 1738 li k1, MACH_CACHED_MEMORY_ADDR 1739 subu k0, k0, k1 1740 srl k0, k0, VMMACH_TLB_PHYS_PAGE_SHIFT 1741 la k1, pmap_attributes 1742 addu k0, k0, k1 1743 lbu k1, 0(k0) # fetch old value 1744 nop 1745 or k1, k1, 1 # set modified bit 1746 sb k1, 0(k0) # save new value 1747 mfc0 k0, MACH_COP_0_EXC_PC # get return address 1748 nop 1749 j k0 1750 rfe 17514: 1752 break 0 # panic 1753 .set at 1754END(MachTLBModException) 1755#endif 1756 1757/*---------------------------------------------------------------------------- 1758 * 1759 * MachTLBMissException -- 1760 * 1761 * Handle a TLB miss exception from kernel mode. 1762 * The BaddVAddr, Context, and EntryHi registers contain the failed 1763 * virtual address. 1764 * 1765 * Results: 1766 * None. 1767 * 1768 * Side effects: 1769 * None. 1770 * 1771 *---------------------------------------------------------------------------- 1772 */ 1773NLEAF(MachTLBMissException) 1774 .set noat 1775 mfc0 k0, MACH_COP_0_BAD_VADDR # get the fault address 1776 li k1, VM_MIN_KERNEL_ADDRESS # compute index 1777 subu k0, k0, k1 1778 lw k1, Sysmapsize # index within range? 1779 srl k0, k0, PGSHIFT 1780 sltu k1, k0, k1 1781 beq k1, zero, 1f # No. check for valid stack 1782 nop 1783 lw k1, Sysmap 1784 sll k0, k0, 2 # compute offset from index 1785 addu k1, k1, k0 1786 lw k0, 0(k1) # get PTE entry 1787 mfc0 k1, MACH_COP_0_EXC_PC # get return address 1788 mtc0 k0, MACH_COP_0_TLB_LOW # save PTE entry 1789 and k0, k0, PG_V # check for valid entry 1790 beq k0, zero, MachKernGenException # PTE invalid 1791 nop 1792 tlbwr # update TLB 1793 j k1 1794 rfe 1795 17961: 1797 subu k0, sp, UADDR + 0x200 # check to see if we have a 1798 sltiu k0, UPAGES*NBPG - 0x200 # valid kernel stack 1799 bne k0, zero, MachKernGenException # Go panic 1800 nop 1801 1802 la a0, start - START_FRAME - 8 # set sp to a valid place 1803 sw sp, 24(a0) 1804 move sp, a0 1805 la a0, 1f 1806 mfc0 a2, MACH_COP_0_STATUS_REG 1807 mfc0 a3, MACH_COP_0_CAUSE_REG 1808 mfc0 a1, MACH_COP_0_EXC_PC 1809 sw a2, 16(sp) 1810 sw a3, 20(sp) 1811 sw sp, 24(sp) 1812 move a2, ra 1813 jal printf 1814 mfc0 a3, MACH_COP_0_BAD_VADDR 1815 .data 18161: 1817 .asciiz "ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n" 1818 .text 1819 1820 la sp, start - START_FRAME # set sp to a valid place 1821 PANIC("kernel stack overflow") 1822 .set at 1823END(MachTLBMissException) 1824 1825/* 1826 * Set/clear software interrupt routines. 1827 */ 1828 1829LEAF(setsoftclock) 1830 mfc0 v1, MACH_COP_0_STATUS_REG # save status register 1831 mtc0 zero, MACH_COP_0_STATUS_REG # disable interrupts (2 cycles) 1832 nop 1833 nop 1834 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1835 nop 1836 or v0, v0, MACH_SOFT_INT_MASK_0 # set soft clock interrupt 1837 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1838 mtc0 v1, MACH_COP_0_STATUS_REG 1839 j ra 1840 nop 1841END(setsoftclock) 1842 1843LEAF(clearsoftclock) 1844 mfc0 v1, MACH_COP_0_STATUS_REG # save status register 1845 mtc0 zero, MACH_COP_0_STATUS_REG # disable interrupts (2 cycles) 1846 nop 1847 nop 1848 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1849 nop 1850 and v0, v0, ~MACH_SOFT_INT_MASK_0 # clear soft clock interrupt 1851 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1852 mtc0 v1, MACH_COP_0_STATUS_REG 1853 j ra 1854 nop 1855END(clearsoftclock) 1856 1857LEAF(setsoftnet) 1858 mfc0 v1, MACH_COP_0_STATUS_REG # save status register 1859 mtc0 zero, MACH_COP_0_STATUS_REG # disable interrupts (2 cycles) 1860 nop 1861 nop 1862 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1863 nop 1864 or v0, v0, MACH_SOFT_INT_MASK_1 # set soft net interrupt 1865 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1866 mtc0 v1, MACH_COP_0_STATUS_REG 1867 j ra 1868 nop 1869END(setsoftnet) 1870 1871LEAF(clearsoftnet) 1872 mfc0 v1, MACH_COP_0_STATUS_REG # save status register 1873 mtc0 zero, MACH_COP_0_STATUS_REG # disable interrupts (2 cycles) 1874 nop 1875 nop 1876 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1877 nop 1878 and v0, v0, ~MACH_SOFT_INT_MASK_1 # clear soft net interrupt 1879 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1880 mtc0 v1, MACH_COP_0_STATUS_REG 1881 j ra 1882 nop 1883END(clearsoftnet) 1884 1885/* 1886 * Set/change interrupt priority routines. 1887 */ 1888 1889LEAF(MachEnableIntr) 1890 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1891 nop 1892 or v0, v0, MACH_SR_INT_ENA_CUR 1893 mtc0 v0, MACH_COP_0_STATUS_REG # enable all interrupts 1894 j ra 1895 nop 1896END(MachEnableIntr) 1897 1898LEAF(spl0) 1899 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1900 nop 1901 or t0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1902 mtc0 t0, MACH_COP_0_STATUS_REG # enable all interrupts 1903 j ra 1904 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1905END(spl0) 1906 1907LEAF(splsoftclock) 1908 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1909 li t0, ~MACH_SOFT_INT_MASK_0 # disable soft clock 1910 and t0, t0, v0 1911 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1912 j ra 1913 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1914END(splsoftclock) 1915 1916LEAF(Mach_spl0) 1917 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1918 li t0, ~(MACH_INT_MASK_0|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) 1919 and t0, t0, v0 1920 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1921 j ra 1922 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1923END(Mach_spl0) 1924 1925LEAF(Mach_spl1) 1926 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1927 li t0, ~(MACH_INT_MASK_1|MACH_SOFT_INT_MASK_0|MACH_SOFT_INT_MASK_1) 1928 and t0, t0, v0 1929 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1930 j ra 1931 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1932END(Mach_spl1) 1933 1934LEAF(Mach_spl2) 1935 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1936 li t0, ~(MACH_INT_MASK_2|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) 1937 and t0, t0, v0 1938 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1939 j ra 1940 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1941END(Mach_spl2) 1942 1943LEAF(Mach_spl3) 1944 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1945 li t0, ~(MACH_INT_MASK_3|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) 1946 and t0, t0, v0 1947 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1948 j ra 1949 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1950END(Mach_spl3) 1951 1952/* 1953 * We define an alternate entry point after mcount is called so it 1954 * can be used in mcount without causeing a recursive loop. 1955 */ 1956LEAF(splhigh) 1957ALEAF(_splhigh) 1958 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1959 li t0, ~MACH_SR_INT_ENA_CUR # disable all interrupts 1960 and t0, t0, v0 1961 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1962 j ra 1963 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1964END(splhigh) 1965 1966/* 1967 * Restore saved interrupt mask. 1968 */ 1969LEAF(splx) 1970ALEAF(_splx) 1971 mfc0 v0, MACH_COP_0_STATUS_REG 1972 li t0, ~(MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1973 and t0, t0, v0 1974 or t0, t0, a0 1975 mtc0 t0, MACH_COP_0_STATUS_REG 1976 j ra 1977 nop 1978END(splx) 1979 1980/*---------------------------------------------------------------------------- 1981 * 1982 * MachEmptyWriteBuffer -- 1983 * 1984 * Return when the write buffer is empty. 1985 * 1986 * MachEmptyWriteBuffer() 1987 * 1988 * Results: 1989 * None. 1990 * 1991 * Side effects: 1992 * None. 1993 * 1994 *---------------------------------------------------------------------------- 1995 */ 1996LEAF(MachEmptyWriteBuffer) 1997 nop 1998 nop 1999 nop 2000 nop 20011: bc0f 1b 2002 nop 2003 j ra 2004 nop 2005END(MachEmptyWriteBuffer) 2006 2007/*-------------------------------------------------------------------------- 2008 * 2009 * MachTLBWriteIndexed -- 2010 * 2011 * Write the given entry into the TLB at the given index. 2012 * 2013 * MachTLBWriteIndexed(index, highEntry, lowEntry) 2014 * int index; 2015 * int highEntry; 2016 * int lowEntry; 2017 * 2018 * Results: 2019 * None. 2020 * 2021 * Side effects: 2022 * TLB entry set. 2023 * 2024 *-------------------------------------------------------------------------- 2025 */ 2026LEAF(MachTLBWriteIndexed) 2027 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2028 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2029 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID. 2030 2031 sll a0, a0, VMMACH_TLB_INDEX_SHIFT 2032 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index. 2033 mtc0 a1, MACH_COP_0_TLB_HI # Set up entry high. 2034 mtc0 a2, MACH_COP_0_TLB_LOW # Set up entry low. 2035 nop 2036 tlbwi # Write the TLB 2037 2038 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID. 2039 j ra 2040 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2041END(MachTLBWriteIndexed) 2042 2043#if 0 2044/*-------------------------------------------------------------------------- 2045 * 2046 * MachTLBWriteRandom -- 2047 * 2048 * Write the given entry into the TLB at a random location. 2049 * 2050 * MachTLBWriteRandom(highEntry, lowEntry) 2051 * unsigned highEntry; 2052 * unsigned lowEntry; 2053 * 2054 * Results: 2055 * None. 2056 * 2057 * Side effects: 2058 * TLB entry set. 2059 * 2060 *-------------------------------------------------------------------------- 2061 */ 2062LEAF(MachTLBWriteRandom) 2063 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2064 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2065 mfc0 v0, MACH_COP_0_TLB_HI # Save the current PID. 2066 nop 2067 2068 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high. 2069 mtc0 a1, MACH_COP_0_TLB_LOW # Set up entry low. 2070 nop 2071 tlbwr # Write the TLB 2072 2073 mtc0 v0, MACH_COP_0_TLB_HI # Restore the PID. 2074 j ra 2075 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2076END(MachTLBWriteRandom) 2077#endif 2078 2079/*-------------------------------------------------------------------------- 2080 * 2081 * MachSetPID -- 2082 * 2083 * Write the given pid into the TLB pid reg. 2084 * 2085 * MachSetPID(pid) 2086 * int pid; 2087 * 2088 * Results: 2089 * None. 2090 * 2091 * Side effects: 2092 * PID set in the entry hi register. 2093 * 2094 *-------------------------------------------------------------------------- 2095 */ 2096LEAF(MachSetPID) 2097 sll a0, a0, VMMACH_TLB_PID_SHIFT # put PID in right spot 2098 mtc0 a0, MACH_COP_0_TLB_HI # Write the hi reg value 2099 j ra 2100 nop 2101END(MachSetPID) 2102 2103/*-------------------------------------------------------------------------- 2104 * 2105 * MachTLBFlush -- 2106 * 2107 * Flush the "random" entries from the TLB. 2108 * 2109 * MachTLBFlush() 2110 * 2111 * Results: 2112 * None. 2113 * 2114 * Side effects: 2115 * The TLB is flushed. 2116 * 2117 *-------------------------------------------------------------------------- 2118 */ 2119LEAF(MachTLBFlush) 2120 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2121 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2122 mfc0 t0, MACH_COP_0_TLB_HI # Save the PID 2123 li t1, MACH_CACHED_MEMORY_ADDR # invalid address 2124 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid 2125 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2126/* 2127 * Align the starting value (t1) and the upper bound (t2). 2128 */ 2129 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT 2130 li t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 21311: 2132 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register. 2133 addu t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT # Increment index. 2134 bne t1, t2, 1b 2135 tlbwi # Write the TLB entry. 2136 2137 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID 2138 j ra 2139 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2140END(MachTLBFlush) 2141 2142#if 0 2143/*-------------------------------------------------------------------------- 2144 * 2145 * MachTLBFlushPID -- 2146 * 2147 * Flush all entries with the given PID from the TLB. 2148 * 2149 * MachTLBFlushPID(pid) 2150 * int pid; 2151 * 2152 * Results: 2153 * None. 2154 * 2155 * Side effects: 2156 * All entries corresponding to this PID are flushed. 2157 * 2158 *-------------------------------------------------------------------------- 2159 */ 2160LEAF(MachTLBFlushPID) 2161 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2162 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2163 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID 2164 sll a0, a0, VMMACH_TLB_PID_SHIFT # Align the pid to flush. 2165/* 2166 * Align the starting value (t1) and the upper bound (t2). 2167 */ 2168 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT 2169 li t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 2170 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register 21711: 2172 addu t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT # Increment index. 2173 tlbr # Read from the TLB 2174 mfc0 t4, MACH_COP_0_TLB_HI # Fetch the hi register. 2175 nop 2176 and t4, t4, VMMACH_TLB_PID # compare PIDs 2177 bne t4, a0, 2f 2178 li v0, MACH_CACHED_MEMORY_ADDR # invalid address 2179 mtc0 v0, MACH_COP_0_TLB_HI # Mark entry high as invalid 2180 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2181 nop 2182 tlbwi # Write the entry. 21832: 2184 bne t1, t2, 1b 2185 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register 2186 2187 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2188 j ra 2189 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2190END(MachTLBFlushPID) 2191#endif 2192 2193/*-------------------------------------------------------------------------- 2194 * 2195 * MachTLBFlushAddr -- 2196 * 2197 * Flush any TLB entries for the given address and TLB PID. 2198 * 2199 * MachTLBFlushAddr(highreg) 2200 * unsigned highreg; 2201 * 2202 * Results: 2203 * None. 2204 * 2205 * Side effects: 2206 * The process's page is flushed from the TLB. 2207 * 2208 *-------------------------------------------------------------------------- 2209 */ 2210LEAF(MachTLBFlushAddr) 2211 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2212 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2213 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2214 nop 2215 2216 mtc0 a0, MACH_COP_0_TLB_HI # look for addr & PID 2217 nop 2218 tlbp # Probe for the entry. 2219 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2220 li t1, MACH_CACHED_MEMORY_ADDR # Load invalid entry. 2221 bltz v0, 1f # index < 0 => !found 2222 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid 2223 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2224 nop 2225 tlbwi 22261: 2227 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2228 j ra 2229 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2230END(MachTLBFlushAddr) 2231 2232/*-------------------------------------------------------------------------- 2233 * 2234 * MachTLBUpdate -- 2235 * 2236 * Update the TLB if highreg is found; otherwise, enter the data. 2237 * 2238 * MachTLBUpdate(highreg, lowreg) 2239 * unsigned highreg, lowreg; 2240 * 2241 * Results: 2242 * None. 2243 * 2244 * Side effects: 2245 * None. 2246 * 2247 *-------------------------------------------------------------------------- 2248 */ 2249LEAF(MachTLBUpdate) 2250 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2251 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2252 mfc0 t0, MACH_COP_0_TLB_HI # Save current PID 2253 nop # 2 cycles before intr disabled 2254 mtc0 a0, MACH_COP_0_TLB_HI # init high reg. 2255 nop 2256 tlbp # Probe for the entry. 2257 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2258 mtc0 a1, MACH_COP_0_TLB_LOW # init low reg. 2259 bltz v0, 1f # index < 0 => !found 2260 sra v0, v0, VMMACH_TLB_INDEX_SHIFT # convert index to regular num 2261 b 2f 2262 tlbwi # update slot found 22631: 2264 mtc0 a0, MACH_COP_0_TLB_HI # init high reg. 2265 nop 2266 tlbwr # enter into a random slot 22672: 2268 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2269 j ra 2270 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2271END(MachTLBUpdate) 2272 2273#if defined(DEBUG) 2274/*-------------------------------------------------------------------------- 2275 * 2276 * MachTLBFind -- 2277 * 2278 * Search the TLB for the given entry. 2279 * 2280 * MachTLBFind(hi) 2281 * unsigned hi; 2282 * 2283 * Results: 2284 * Returns a value >= 0 if the entry was found (the index). 2285 * Returns a value < 0 if the entry was not found. 2286 * 2287 * Side effects: 2288 * tlbhi and tlblo will contain the TLB entry found. 2289 * 2290 *-------------------------------------------------------------------------- 2291 */ 2292 .comm tlbhi, 4 2293 .comm tlblo, 4 2294LEAF(MachTLBFind) 2295 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2296 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2297 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2298 nop 2299 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high. 2300 nop 2301 tlbp # Probe for the entry. 2302 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2303 nop 2304 bltz v0, 1f # not found 2305 nop 2306 tlbr # read TLB 2307 mfc0 t1, MACH_COP_0_TLB_HI # See what we got 2308 mfc0 t2, MACH_COP_0_TLB_LOW # See what we got 2309 sw t1, tlbhi 2310 sw t2, tlblo 2311 srl v0, v0, VMMACH_TLB_INDEX_SHIFT # convert index to regular num 23121: 2313 mtc0 t0, MACH_COP_0_TLB_HI # Restore current PID 2314 j ra 2315 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2316END(MachTLBFind) 2317 2318/*-------------------------------------------------------------------------- 2319 * 2320 * MachTLBRead -- 2321 * 2322 * Read the TLB entry. 2323 * 2324 * MachTLBRead(entry) 2325 * unsigned entry; 2326 * 2327 * Results: 2328 * None. 2329 * 2330 * Side effects: 2331 * tlbhi and tlblo will contain the TLB entry found. 2332 * 2333 *-------------------------------------------------------------------------- 2334 */ 2335LEAF(MachTLBRead) 2336 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2337 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2338 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2339 2340 sll a0, a0, VMMACH_TLB_INDEX_SHIFT 2341 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index register 2342 nop 2343 tlbr # Read from the TLB 2344 mfc0 t3, MACH_COP_0_TLB_HI # fetch the hi entry 2345 mfc0 t4, MACH_COP_0_TLB_LOW # fetch the low entry 2346 sw t3, tlbhi 2347 sw t4, tlblo 2348 2349 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2350 j ra 2351 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2352END(MachTLBRead) 2353 2354/*-------------------------------------------------------------------------- 2355 * 2356 * MachTLBGetPID -- 2357 * 2358 * MachTLBGetPID() 2359 * 2360 * Results: 2361 * Returns the current TLB pid reg. 2362 * 2363 * Side effects: 2364 * None. 2365 * 2366 *-------------------------------------------------------------------------- 2367 */ 2368LEAF(MachTLBGetPID) 2369 mfc0 v0, MACH_COP_0_TLB_HI # get PID 2370 nop 2371 and v0, v0, VMMACH_TLB_PID # mask off PID 2372 j ra 2373 srl v0, v0, VMMACH_TLB_PID_SHIFT # put PID in right spot 2374END(MachTLBGetPID) 2375 2376/* 2377 * Return the current value of the cause register. 2378 */ 2379LEAF(MachGetCauseReg) 2380 mfc0 v0, MACH_COP_0_CAUSE_REG 2381 j ra 2382 nop 2383END(MachGetCauseReg) 2384#endif /* DEBUG */ 2385 2386/*---------------------------------------------------------------------------- 2387 * 2388 * MachSwitchFPState -- 2389 * 2390 * Save the current state into 'from' and restore it from 'to'. 2391 * 2392 * MachSwitchFPState(from, to) 2393 * struct proc *from; 2394 * struct user *to; 2395 * 2396 * Results: 2397 * None. 2398 * 2399 * Side effects: 2400 * None. 2401 * 2402 *---------------------------------------------------------------------------- 2403 */ 2404LEAF(MachSwitchFPState) 2405 mfc0 t1, MACH_COP_0_STATUS_REG # Save old SR 2406 li t0, MACH_SR_COP_1_BIT # enable the coprocessor 2407 mtc0 t0, MACH_COP_0_STATUS_REG 2408 2409 beq a0, zero, 1f # skip save if NULL pointer 2410 nop 2411/* 2412 * First read out the status register to make sure that all FP operations 2413 * have completed. 2414 */ 2415 lw a0, P_ADDR(a0) # get pointer to pcb for proc 2416 cfc1 t0, MACH_FPC_CSR # stall til FP done 2417 cfc1 t0, MACH_FPC_CSR # now get status 2418 li t3, ~MACH_SR_COP_1_BIT 2419 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register 2420 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status 2421 and t2, t2, t3 # clear COP_1 enable bit 2422 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register 2423/* 2424 * Save the floating point registers. 2425 */ 2426 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) 2427 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) 2428 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) 2429 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) 2430 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) 2431 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) 2432 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) 2433 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) 2434 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) 2435 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) 2436 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) 2437 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) 2438 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) 2439 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) 2440 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) 2441 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) 2442 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) 2443 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) 2444 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) 2445 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) 2446 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) 2447 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) 2448 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) 2449 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) 2450 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) 2451 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) 2452 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) 2453 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) 2454 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) 2455 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) 2456 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) 2457 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) 2458 24591: 2460/* 2461 * Restore the floating point registers. 2462 */ 2463 lw t0, U_PCB_FPREGS+(32 * 4)(a1) # get status register 2464 lwc1 $f0, U_PCB_FPREGS+(0 * 4)(a1) 2465 lwc1 $f1, U_PCB_FPREGS+(1 * 4)(a1) 2466 lwc1 $f2, U_PCB_FPREGS+(2 * 4)(a1) 2467 lwc1 $f3, U_PCB_FPREGS+(3 * 4)(a1) 2468 lwc1 $f4, U_PCB_FPREGS+(4 * 4)(a1) 2469 lwc1 $f5, U_PCB_FPREGS+(5 * 4)(a1) 2470 lwc1 $f6, U_PCB_FPREGS+(6 * 4)(a1) 2471 lwc1 $f7, U_PCB_FPREGS+(7 * 4)(a1) 2472 lwc1 $f8, U_PCB_FPREGS+(8 * 4)(a1) 2473 lwc1 $f9, U_PCB_FPREGS+(9 * 4)(a1) 2474 lwc1 $f10, U_PCB_FPREGS+(10 * 4)(a1) 2475 lwc1 $f11, U_PCB_FPREGS+(11 * 4)(a1) 2476 lwc1 $f12, U_PCB_FPREGS+(12 * 4)(a1) 2477 lwc1 $f13, U_PCB_FPREGS+(13 * 4)(a1) 2478 lwc1 $f14, U_PCB_FPREGS+(14 * 4)(a1) 2479 lwc1 $f15, U_PCB_FPREGS+(15 * 4)(a1) 2480 lwc1 $f16, U_PCB_FPREGS+(16 * 4)(a1) 2481 lwc1 $f17, U_PCB_FPREGS+(17 * 4)(a1) 2482 lwc1 $f18, U_PCB_FPREGS+(18 * 4)(a1) 2483 lwc1 $f19, U_PCB_FPREGS+(19 * 4)(a1) 2484 lwc1 $f20, U_PCB_FPREGS+(20 * 4)(a1) 2485 lwc1 $f21, U_PCB_FPREGS+(21 * 4)(a1) 2486 lwc1 $f22, U_PCB_FPREGS+(22 * 4)(a1) 2487 lwc1 $f23, U_PCB_FPREGS+(23 * 4)(a1) 2488 lwc1 $f24, U_PCB_FPREGS+(24 * 4)(a1) 2489 lwc1 $f25, U_PCB_FPREGS+(25 * 4)(a1) 2490 lwc1 $f26, U_PCB_FPREGS+(26 * 4)(a1) 2491 lwc1 $f27, U_PCB_FPREGS+(27 * 4)(a1) 2492 lwc1 $f28, U_PCB_FPREGS+(28 * 4)(a1) 2493 lwc1 $f29, U_PCB_FPREGS+(29 * 4)(a1) 2494 lwc1 $f30, U_PCB_FPREGS+(30 * 4)(a1) 2495 lwc1 $f31, U_PCB_FPREGS+(31 * 4)(a1) 2496 2497 and t0, t0, ~MACH_FPC_EXCEPTION_BITS 2498 ctc1 t0, MACH_FPC_CSR 2499 nop 2500 2501 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register. 2502 j ra 2503 nop 2504END(MachSwitchFPState) 2505 2506/*---------------------------------------------------------------------------- 2507 * 2508 * MachSaveCurFPState -- 2509 * 2510 * Save the current floating point coprocessor state. 2511 * 2512 * MachSaveCurFPState(p) 2513 * struct proc *p; 2514 * 2515 * Results: 2516 * None. 2517 * 2518 * Side effects: 2519 * machFPCurProcPtr is cleared. 2520 * 2521 *---------------------------------------------------------------------------- 2522 */ 2523LEAF(MachSaveCurFPState) 2524 lw a0, P_ADDR(a0) # get pointer to pcb for proc 2525 mfc0 t1, MACH_COP_0_STATUS_REG # Disable interrupts and 2526 li t0, MACH_SR_COP_1_BIT # enable the coprocessor 2527 mtc0 t0, MACH_COP_0_STATUS_REG 2528 sw zero, machFPCurProcPtr # indicate state has been saved 2529/* 2530 * First read out the status register to make sure that all FP operations 2531 * have completed. 2532 */ 2533 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register 2534 li t3, ~MACH_SR_COP_1_BIT 2535 and t2, t2, t3 # clear COP_1 enable bit 2536 cfc1 t0, MACH_FPC_CSR # stall til FP done 2537 cfc1 t0, MACH_FPC_CSR # now get status 2538 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register 2539 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status 2540/* 2541 * Save the floating point registers. 2542 */ 2543 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) 2544 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) 2545 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) 2546 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) 2547 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) 2548 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) 2549 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) 2550 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) 2551 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) 2552 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) 2553 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) 2554 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) 2555 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) 2556 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) 2557 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) 2558 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) 2559 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) 2560 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) 2561 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) 2562 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) 2563 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) 2564 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) 2565 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) 2566 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) 2567 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) 2568 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) 2569 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) 2570 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) 2571 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) 2572 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) 2573 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) 2574 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) 2575 2576 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register. 2577 j ra 2578 nop 2579END(MachSaveCurFPState) 2580 2581/*---------------------------------------------------------------------------- 2582 * 2583 * MachFPInterrupt -- 2584 * 2585 * Handle a floating point interrupt. 2586 * 2587 * MachFPInterrupt(statusReg, causeReg, pc) 2588 * unsigned statusReg; 2589 * unsigned causeReg; 2590 * unsigned pc; 2591 * 2592 * Results: 2593 * None. 2594 * 2595 * Side effects: 2596 * None. 2597 * 2598 *---------------------------------------------------------------------------- 2599 */ 2600NON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra) 2601 subu sp, sp, STAND_FRAME_SIZE 2602 mfc0 t0, MACH_COP_0_STATUS_REG 2603 sw ra, STAND_RA_OFFSET(sp) 2604 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2605 2606 or t1, t0, MACH_SR_COP_1_BIT 2607 mtc0 t1, MACH_COP_0_STATUS_REG 2608 nop 2609 nop 2610 cfc1 t1, MACH_FPC_CSR # stall til FP done 2611 cfc1 t1, MACH_FPC_CSR # now get status 2612 nop 2613 sll t2, t1, (31 - 17) # unimplemented operation? 2614 bgez t2, 3f # no, normal trap 2615 nop 2616/* 2617 * We got an unimplemented operation trap so 2618 * fetch the instruction, compute the next PC and emulate the instruction. 2619 */ 2620 bgez a1, 1f # Check the branch delay bit. 2621 nop 2622/* 2623 * The instruction is in the branch delay slot so the branch will have to 2624 * be emulated to get the resulting PC. 2625 */ 2626 sw a2, STAND_FRAME_SIZE + 8(sp) 2627 li a0, UADDR+U_PCB_REGS # first arg is ptr to CPU registers 2628 move a1, a2 # second arg is instruction PC 2629 move a2, t1 # third arg is floating point CSR 2630 jal MachEmulateBranch # compute PC after branch 2631 move a3, zero # fourth arg is FALSE 2632/* 2633 * Now load the floating-point instruction in the branch delay slot 2634 * to be emulated. 2635 */ 2636 lw a2, STAND_FRAME_SIZE + 8(sp) # restore EXC pc 2637 b 2f 2638 lw a0, 4(a2) # a0 = coproc instruction 2639/* 2640 * This is not in the branch delay slot so calculate the resulting 2641 * PC (epc + 4) into v0 and continue to MachEmulateFP(). 2642 */ 26431: 2644 lw a0, 0(a2) # a0 = coproc instruction 2645 addu v0, a2, 4 # v0 = next pc 26462: 2647 sw v0, UADDR+U_PCB_REGS+(PC * 4) # save new pc 2648/* 2649 * Check to see if the instruction to be emulated is a floating-point 2650 * instruction. 2651 */ 2652 srl a3, a0, MACH_OPCODE_SHIFT 2653 beq a3, MACH_OPCODE_C1, 4f # this should never fail 2654/* 2655 * Send a floating point exception signal to the current process. 2656 */ 26573: 2658 lw a0, curproc # get current process 2659 cfc1 a2, MACH_FPC_CSR # code = FP execptions 2660 ctc1 zero, MACH_FPC_CSR # Clear exceptions 2661 jal trapsignal 2662 li a1, SIGFPE 2663 b FPReturn 2664 nop 2665 2666/* 2667 * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate. 2668 */ 26694: 2670 jal MachEmulateFP 2671 nop 2672 2673/* 2674 * Turn off the floating point coprocessor and return. 2675 */ 2676FPReturn: 2677 mfc0 t0, MACH_COP_0_STATUS_REG 2678 lw ra, STAND_RA_OFFSET(sp) 2679 and t0, t0, ~MACH_SR_COP_1_BIT 2680 mtc0 t0, MACH_COP_0_STATUS_REG 2681 j ra 2682 addu sp, sp, STAND_FRAME_SIZE 2683END(MachFPInterrupt) 2684 2685/*---------------------------------------------------------------------------- 2686 * 2687 * MachConfigCache -- 2688 * 2689 * Size the caches. 2690 * NOTE: should only be called from mach_init(). 2691 * 2692 * Results: 2693 * None. 2694 * 2695 * Side effects: 2696 * The size of the data cache is stored into machDataCacheSize and the 2697 * size of instruction cache is stored into machInstCacheSize. 2698 * 2699 *---------------------------------------------------------------------------- 2700 */ 2701NON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra) 2702 subu sp, sp, STAND_FRAME_SIZE 2703 sw ra, STAND_RA_OFFSET(sp) # Save return address. 2704 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2705 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2706 la v0, 1f 2707 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2708 j v0 2709 nop 27101: 2711/* 2712 * This works because jal doesn't change pc[31..28] and the 2713 * linker still thinks SizeCache is in the cached region so it computes 2714 * the correct address without complaining. 2715 */ 2716 jal SizeCache # Get the size of the d-cache. 2717 nop 2718 sw v0, machDataCacheSize 2719 nop # Make sure sw out of pipe 2720 nop 2721 nop 2722 nop 2723 li v0, MACH_SR_SWAP_CACHES # Swap caches 2724 mtc0 v0, MACH_COP_0_STATUS_REG 2725 nop # Insure caches stable 2726 nop 2727 nop 2728 nop 2729 jal SizeCache # Get the size of the i-cache. 2730 nop 2731 mtc0 zero, MACH_COP_0_STATUS_REG # Swap back caches and enable. 2732 nop 2733 nop 2734 nop 2735 nop 2736 sw v0, machInstCacheSize 2737 la t0, 1f 2738 j t0 # Back to cached mode 2739 nop 27401: 2741 lw ra, STAND_RA_OFFSET(sp) # Restore return addr 2742 addu sp, sp, STAND_FRAME_SIZE # Restore sp. 2743 j ra 2744 nop 2745END(MachConfigCache) 2746 2747/*---------------------------------------------------------------------------- 2748 * 2749 * SizeCache -- 2750 * 2751 * Get the size of the cache. 2752 * 2753 * Results: 2754 * The size of the cache. 2755 * 2756 * Side effects: 2757 * None. 2758 * 2759 *---------------------------------------------------------------------------- 2760 */ 2761LEAF(SizeCache) 2762 mfc0 t0, MACH_COP_0_STATUS_REG # Save the current status reg. 2763 nop 2764 or v0, t0, MACH_SR_ISOL_CACHES # Isolate the caches. 2765 nop # Make sure no stores in pipe 2766 mtc0 v0, MACH_COP_0_STATUS_REG 2767 nop # Make sure isolated 2768 nop 2769 nop 2770/* 2771 * Clear cache size boundaries. 2772 */ 2773 li v0, MACH_MIN_CACHE_SIZE 2774 li v1, MACH_CACHED_MEMORY_ADDR 2775 li t2, MACH_MAX_CACHE_SIZE 27761: 2777 addu t1, v0, v1 # Compute address to clear 2778 sw zero, 0(t1) # Clear cache memory 2779 bne v0, t2, 1b 2780 sll v0, v0, 1 2781 2782 li v0, -1 2783 sw v0, 0(v1) # Store marker in cache 2784 li v0, MACH_MIN_CACHE_SIZE 27852: 2786 addu t1, v0, v1 # Compute address 2787 lw t3, 0(t1) # Look for marker 2788 nop 2789 bne t3, zero, 3f # Found marker. 2790 nop 2791 bne v0, t2, 2b # keep looking 2792 sll v0, v0, 1 # cache size * 2 2793 2794 move v0, zero # must be no cache 27953: 2796 mtc0 t0, MACH_COP_0_STATUS_REG 2797 nop # Make sure unisolated 2798 nop 2799 nop 2800 nop 2801 j ra 2802 nop 2803END(SizeCache) 2804 2805/*---------------------------------------------------------------------------- 2806 * 2807 * MachFlushCache -- 2808 * 2809 * Flush the caches. 2810 * 2811 * Results: 2812 * None. 2813 * 2814 * Side effects: 2815 * The contents of the caches is flushed. 2816 * 2817 *---------------------------------------------------------------------------- 2818 */ 2819LEAF(MachFlushCache) 2820 lw t1, machInstCacheSize # Must load before isolating 2821 lw t2, machDataCacheSize # Must load before isolating 2822 mfc0 t3, MACH_COP_0_STATUS_REG # Save the status register. 2823 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2824 la v0, 1f 2825 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2826 j v0 2827 nop 2828/* 2829 * Flush the instruction cache. 2830 */ 28311: 2832 li v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES 2833 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap caches. 2834 li t0, MACH_UNCACHED_MEMORY_ADDR 2835 subu t0, t0, t1 2836 li t1, MACH_UNCACHED_MEMORY_ADDR 2837 la v0, 1f # Run cached 2838 j v0 2839 nop 28401: 2841 addu t0, t0, 4 2842 bne t0, t1, 1b 2843 sb zero, -4(t0) 2844 2845 la v0, 1f 2846 or v0, MACH_UNCACHED_MEMORY_ADDR 2847 j v0 # Run uncached 2848 nop 2849/* 2850 * Flush the data cache. 2851 */ 28521: 2853 li v0, MACH_SR_ISOL_CACHES 2854 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap back caches 2855 li t0, MACH_UNCACHED_MEMORY_ADDR 2856 subu t0, t0, t2 2857 la v0, 1f 2858 j v0 # Back to cached mode 2859 nop 28601: 2861 addu t0, t0, 4 2862 bne t0, t1, 1b 2863 sb zero, -4(t0) 2864 2865 nop # Insure isolated stores 2866 nop # out of pipe. 2867 nop 2868 nop 2869 mtc0 t3, MACH_COP_0_STATUS_REG # Restore status reg. 2870 nop # Insure cache unisolated. 2871 nop 2872 nop 2873 nop 2874 j ra 2875 nop 2876END(MachFlushCache) 2877 2878/*---------------------------------------------------------------------------- 2879 * 2880 * MachFlushICache -- 2881 * 2882 * void MachFlushICache(addr, len) 2883 * vm_offset_t addr, len; 2884 * 2885 * Flush instruction cache for range of addr to addr + len - 1. 2886 * The address can be any valid address so long as no TLB misses occur. 2887 * 2888 * Results: 2889 * None. 2890 * 2891 * Side effects: 2892 * The contents of the cache is flushed. 2893 * 2894 *---------------------------------------------------------------------------- 2895 */ 2896LEAF(MachFlushICache) 2897 mfc0 t0, MACH_COP_0_STATUS_REG # Save SR 2898 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2899 2900 la v1, 1f 2901 or v1, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2902 j v1 2903 nop 29041: 2905 bc0f 1b # make sure stores are complete 2906 li v1, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES 2907 mtc0 v1, MACH_COP_0_STATUS_REG 2908 nop 2909 addu a1, a1, a0 # compute ending address 29101: 2911 addu a0, a0, 4 2912 bne a0, a1, 1b 2913 sb zero, -4(a0) 2914 2915 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts 2916 j ra # return and run cached 2917 nop 2918END(MachFlushICache) 2919 2920/*---------------------------------------------------------------------------- 2921 * 2922 * MachFlushDCache -- 2923 * 2924 * void MachFlushDCache(addr, len) 2925 * vm_offset_t addr, len; 2926 * 2927 * Flush data cache for range of addr to addr + len - 1. 2928 * The address can be any valid address so long as no TLB misses occur. 2929 * (Be sure to use cached K0SEG kernel addresses) 2930 * Results: 2931 * None. 2932 * 2933 * Side effects: 2934 * The contents of the cache is flushed. 2935 * 2936 *---------------------------------------------------------------------------- 2937 */ 2938LEAF(MachFlushDCache) 2939 mfc0 t0, MACH_COP_0_STATUS_REG # Save SR 2940 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2941 2942 la v1, 1f 2943 or v1, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2944 j v1 2945 nop 29461: 2947 bc0f 1b # make sure stores are complete 2948 li v1, MACH_SR_ISOL_CACHES 2949 mtc0 v1, MACH_COP_0_STATUS_REG 2950 nop 2951 addu a1, a1, a0 # compute ending address 29521: 2953 addu a0, a0, 4 2954 bne a0, a1, 1b 2955 sb zero, -4(a0) 2956 2957 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts 2958 j ra # return and run cached 2959 nop 2960END(MachFlushDCache) 2961 2962#ifdef KADB 2963/* 2964 * Read a long and return it. 2965 * Note: addresses can be unaligned! 2966 * 2967 * long 2968L* kdbpeek(addr) 2969L* caddt_t addr; 2970L* { 2971L* return (*(long *)addr); 2972L* } 2973 */ 2974LEAF(kdbpeek) 2975 li v0, KADBERR 2976 sw v0, UADDR+U_PCB_ONFAULT 2977 and v0, a0, 3 # unaligned address? 2978 bne v0, zero, 1f 2979 nop 2980 b 2f 2981 lw v0, (a0) # aligned access 29821: 2983 lwr v0, 0(a0) # get next 4 bytes (unaligned) 2984 lwl v0, 3(a0) 29852: 2986 j ra # made it w/o errors 2987 sw zero, UADDR+U_PCB_ONFAULT 2988kadberr: 2989 li v0, 1 # trap sends us here 2990 sw v0, kdbmkfault 2991 j ra 2992 nop 2993END(kdbpeek) 2994 2995/* 2996 * Write a long to 'addr'. 2997 * Note: addresses can be unaligned! 2998 * 2999L* void 3000L* kdbpoke(addr, value) 3001L* caddt_t addr; 3002L* long value; 3003L* { 3004L* *(long *)addr = value; 3005L* } 3006 */ 3007LEAF(kdbpoke) 3008 li v0, KADBERR 3009 sw v0, UADDR+U_PCB_ONFAULT 3010 and v0, a0, 3 # unaligned address? 3011 bne v0, zero, 1f 3012 nop 3013 b 2f 3014 sw a1, (a0) # aligned access 30151: 3016 swr a1, 0(a0) # store next 4 bytes (unaligned) 3017 swl a1, 3(a0) 3018 and a0, a0, ~3 # align address for cache flush 30192: 3020 sw zero, UADDR+U_PCB_ONFAULT 3021 b MachFlushICache # flush instruction cache 3022 li a1, 8 3023END(kdbpoke) 3024 3025/* 3026 * Save registers and state so we can do a 'kdbreset' (like longjmp) later. 3027 * Always returns zero. 3028 * 3029L* int kdb_savearea[11]; 3030L* 3031L* int 3032L* kdbsetexit() 3033L* { 3034L* kdb_savearea[0] = 0; 3035L* return (0); 3036L* } 3037 */ 3038 .comm kdb_savearea, (11 * 4) 3039 3040LEAF(kdbsetexit) 3041 la a0, kdb_savearea 3042 sw s0, 0(a0) 3043 sw s1, 4(a0) 3044 sw s2, 8(a0) 3045 sw s3, 12(a0) 3046 sw s4, 16(a0) 3047 sw s5, 20(a0) 3048 sw s6, 24(a0) 3049 sw s7, 28(a0) 3050 sw sp, 32(a0) 3051 sw s8, 36(a0) 3052 sw ra, 40(a0) 3053 j ra 3054 move v0, zero 3055END(kdbsetexit) 3056 3057/* 3058 * Restore registers and state (like longjmp) and return x. 3059 * 3060L* int 3061L* kdbreset(x) 3062L* { 3063L* return (x); 3064L* } 3065 */ 3066LEAF(kdbreset) 3067 la v0, kdb_savearea 3068 lw ra, 40(v0) 3069 lw s0, 0(v0) 3070 lw s1, 4(v0) 3071 lw s2, 8(v0) 3072 lw s3, 12(v0) 3073 lw s4, 16(v0) 3074 lw s5, 20(v0) 3075 lw s6, 24(v0) 3076 lw s7, 28(v0) 3077 lw sp, 32(v0) 3078 lw s8, 36(v0) 3079 j ra 3080 move v0, a0 3081END(kdbreset) 3082 3083/* 3084 * Trap into the debugger. 3085 * 3086L* void 3087L* kdbpanic() 3088L* { 3089L* } 3090 */ 3091LEAF(kdbpanic) 3092 break MACH_BREAK_KDB_VAL 3093 j ra 3094 nop 3095END(kdbpanic) 3096#endif /* KADB */ 3097 3098#ifdef DEBUG 3099LEAF(cpu_getregs) 3100 sw sp, 0(a0) 3101 sw ra, 4(a0) 3102 j ra 3103 sw s8, 8(a0) 3104END(cpu_getregs) 3105#endif /* DEBUG */ 3106 3107/* 3108 * Interrupt counters for vmstat. 3109 * XXX These aren't used yet. 3110 */ 3111 .data 3112 .globl intrcnt, eintrcnt, intrnames, eintrnames 3113intrnames: 3114 .asciiz "softclock" 3115 .asciiz "softnet" 3116 .asciiz "dc" 3117 .asciiz "ether" 3118 .asciiz "disk" 3119 .asciiz "memory" 3120 .asciiz "clock" 3121 .asciiz "fp" 3122eintrnames: 3123 .align 2 3124intrcnt: 3125 .word 0,0,0,0,0,0,0,0 3126eintrcnt: 3127 .word 0 # This shouldn't be needed but the eintrcnt label 3128 # ends up in a different section otherwise. 3129