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.6 (Berkeley) 07/03/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#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 v0, MACH_COP_0_CAUSE_REG # read cause register 1831 nop 1832 or v0, v0, MACH_SOFT_INT_MASK_0 # set soft clock interrupt 1833 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1834 j ra 1835 nop 1836END(setsoftclock) 1837 1838LEAF(clearsoftclock) 1839 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1840 nop 1841 and v0, v0, ~MACH_SOFT_INT_MASK_0 # clear soft clock interrupt 1842 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1843 j ra 1844 nop 1845END(clearsoftclock) 1846 1847LEAF(setsoftnet) 1848 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1849 nop 1850 or v0, v0, MACH_SOFT_INT_MASK_1 # set soft net interrupt 1851 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1852 j ra 1853 nop 1854END(setsoftnet) 1855 1856LEAF(clearsoftnet) 1857 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register 1858 nop 1859 and v0, v0, ~MACH_SOFT_INT_MASK_1 # clear soft net interrupt 1860 mtc0 v0, MACH_COP_0_CAUSE_REG # save it 1861 j ra 1862 nop 1863END(clearsoftnet) 1864 1865/* 1866 * Set/change interrupt priority routines. 1867 */ 1868 1869LEAF(MachEnableIntr) 1870 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1871 nop 1872 or v0, v0, MACH_SR_INT_ENA_CUR 1873 mtc0 v0, MACH_COP_0_STATUS_REG # enable all interrupts 1874 j ra 1875 nop 1876END(MachEnableIntr) 1877 1878LEAF(spl0) 1879 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1880 nop 1881 or t0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1882 mtc0 t0, MACH_COP_0_STATUS_REG # enable all interrupts 1883 j ra 1884 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1885END(spl0) 1886 1887LEAF(splsoftclock) 1888 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1889 li t0, ~MACH_SOFT_INT_MASK_0 # disable soft clock 1890 and t0, t0, v0 1891 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1892 j ra 1893 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1894END(splsoftclock) 1895 1896LEAF(Mach_spl0) 1897 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1898 li t0, ~(MACH_INT_MASK_0|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) 1899 and t0, t0, v0 1900 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1901 j ra 1902 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1903END(Mach_spl0) 1904 1905LEAF(Mach_spl1) 1906 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1907 li t0, ~(MACH_INT_MASK_1|MACH_SOFT_INT_MASK_0|MACH_SOFT_INT_MASK_1) 1908 and t0, t0, v0 1909 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1910 j ra 1911 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1912END(Mach_spl1) 1913 1914LEAF(Mach_spl2) 1915 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1916 li t0, ~(MACH_INT_MASK_2|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) 1917 and t0, t0, v0 1918 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1919 j ra 1920 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1921END(Mach_spl2) 1922 1923LEAF(Mach_spl3) 1924 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1925 li t0, ~(MACH_INT_MASK_3|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) 1926 and t0, t0, v0 1927 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1928 j ra 1929 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1930END(Mach_spl3) 1931 1932/* 1933 * We define an alternate entry point after mcount is called so it 1934 * can be used in mcount without causeing a recursive loop. 1935 */ 1936LEAF(splhigh) 1937ALEAF(_splhigh) 1938 mfc0 v0, MACH_COP_0_STATUS_REG # read status register 1939 li t0, ~MACH_SR_INT_ENA_CUR # disable all interrupts 1940 and t0, t0, v0 1941 mtc0 t0, MACH_COP_0_STATUS_REG # save it 1942 j ra 1943 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1944END(splhigh) 1945 1946/* 1947 * Restore saved interrupt mask. 1948 */ 1949LEAF(splx) 1950ALEAF(_splx) 1951 mfc0 v0, MACH_COP_0_STATUS_REG 1952 li t0, ~(MACH_INT_MASK | MACH_SR_INT_ENA_CUR) 1953 and t0, t0, v0 1954 or t0, t0, a0 1955 mtc0 t0, MACH_COP_0_STATUS_REG 1956 j ra 1957 nop 1958END(splx) 1959 1960/*---------------------------------------------------------------------------- 1961 * 1962 * MachEmptyWriteBuffer -- 1963 * 1964 * Return when the write buffer is empty. 1965 * 1966 * MachEmptyWriteBuffer() 1967 * 1968 * Results: 1969 * None. 1970 * 1971 * Side effects: 1972 * None. 1973 * 1974 *---------------------------------------------------------------------------- 1975 */ 1976LEAF(MachEmptyWriteBuffer) 1977 nop 1978 nop 1979 nop 1980 nop 19811: bc0f 1b 1982 nop 1983 j ra 1984 nop 1985END(MachEmptyWriteBuffer) 1986 1987/*-------------------------------------------------------------------------- 1988 * 1989 * MachTLBWriteIndexed -- 1990 * 1991 * Write the given entry into the TLB at the given index. 1992 * 1993 * MachTLBWriteIndexed(index, highEntry, lowEntry) 1994 * int index; 1995 * int highEntry; 1996 * int lowEntry; 1997 * 1998 * Results: 1999 * None. 2000 * 2001 * Side effects: 2002 * TLB entry set. 2003 * 2004 *-------------------------------------------------------------------------- 2005 */ 2006LEAF(MachTLBWriteIndexed) 2007 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2008 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2009 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID. 2010 2011 sll a0, a0, VMMACH_TLB_INDEX_SHIFT 2012 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index. 2013 mtc0 a1, MACH_COP_0_TLB_HI # Set up entry high. 2014 mtc0 a2, MACH_COP_0_TLB_LOW # Set up entry low. 2015 nop 2016 tlbwi # Write the TLB 2017 2018 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID. 2019 j ra 2020 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2021END(MachTLBWriteIndexed) 2022 2023#if 0 2024/*-------------------------------------------------------------------------- 2025 * 2026 * MachTLBWriteRandom -- 2027 * 2028 * Write the given entry into the TLB at a random location. 2029 * 2030 * MachTLBWriteRandom(highEntry, lowEntry) 2031 * unsigned highEntry; 2032 * unsigned lowEntry; 2033 * 2034 * Results: 2035 * None. 2036 * 2037 * Side effects: 2038 * TLB entry set. 2039 * 2040 *-------------------------------------------------------------------------- 2041 */ 2042LEAF(MachTLBWriteRandom) 2043 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2044 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2045 mfc0 v0, MACH_COP_0_TLB_HI # Save the current PID. 2046 nop 2047 2048 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high. 2049 mtc0 a1, MACH_COP_0_TLB_LOW # Set up entry low. 2050 nop 2051 tlbwr # Write the TLB 2052 2053 mtc0 v0, MACH_COP_0_TLB_HI # Restore the PID. 2054 j ra 2055 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2056END(MachTLBWriteRandom) 2057#endif 2058 2059/*-------------------------------------------------------------------------- 2060 * 2061 * MachSetPID -- 2062 * 2063 * Write the given pid into the TLB pid reg. 2064 * 2065 * MachSetPID(pid) 2066 * int pid; 2067 * 2068 * Results: 2069 * None. 2070 * 2071 * Side effects: 2072 * PID set in the entry hi register. 2073 * 2074 *-------------------------------------------------------------------------- 2075 */ 2076LEAF(MachSetPID) 2077 sll a0, a0, VMMACH_TLB_PID_SHIFT # put PID in right spot 2078 mtc0 a0, MACH_COP_0_TLB_HI # Write the hi reg value 2079 j ra 2080 nop 2081END(MachSetPID) 2082 2083/*-------------------------------------------------------------------------- 2084 * 2085 * MachTLBFlush -- 2086 * 2087 * Flush the "random" entries from the TLB. 2088 * 2089 * MachTLBFlush() 2090 * 2091 * Results: 2092 * None. 2093 * 2094 * Side effects: 2095 * The TLB is flushed. 2096 * 2097 *-------------------------------------------------------------------------- 2098 */ 2099LEAF(MachTLBFlush) 2100 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2101 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2102 mfc0 t0, MACH_COP_0_TLB_HI # Save the PID 2103 li t1, MACH_CACHED_MEMORY_ADDR # invalid address 2104 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid 2105 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2106/* 2107 * Align the starting value (t1) and the upper bound (t2). 2108 */ 2109 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT 2110 li t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 21111: 2112 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register. 2113 addu t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT # Increment index. 2114 bne t1, t2, 1b 2115 tlbwi # Write the TLB entry. 2116 2117 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID 2118 j ra 2119 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2120END(MachTLBFlush) 2121 2122#if 0 2123/*-------------------------------------------------------------------------- 2124 * 2125 * MachTLBFlushPID -- 2126 * 2127 * Flush all entries with the given PID from the TLB. 2128 * 2129 * MachTLBFlushPID(pid) 2130 * int pid; 2131 * 2132 * Results: 2133 * None. 2134 * 2135 * Side effects: 2136 * All entries corresponding to this PID are flushed. 2137 * 2138 *-------------------------------------------------------------------------- 2139 */ 2140LEAF(MachTLBFlushPID) 2141 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2142 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2143 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID 2144 sll a0, a0, VMMACH_TLB_PID_SHIFT # Align the pid to flush. 2145/* 2146 * Align the starting value (t1) and the upper bound (t2). 2147 */ 2148 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT 2149 li t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT 2150 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register 21511: 2152 addu t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT # Increment index. 2153 tlbr # Read from the TLB 2154 mfc0 t4, MACH_COP_0_TLB_HI # Fetch the hi register. 2155 nop 2156 and t4, t4, VMMACH_TLB_PID # compare PIDs 2157 bne t4, a0, 2f 2158 li v0, MACH_CACHED_MEMORY_ADDR # invalid address 2159 mtc0 v0, MACH_COP_0_TLB_HI # Mark entry high as invalid 2160 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2161 nop 2162 tlbwi # Write the entry. 21632: 2164 bne t1, t2, 1b 2165 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register 2166 2167 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2168 j ra 2169 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2170END(MachTLBFlushPID) 2171#endif 2172 2173/*-------------------------------------------------------------------------- 2174 * 2175 * MachTLBFlushAddr -- 2176 * 2177 * Flush any TLB entries for the given address and TLB PID. 2178 * 2179 * MachTLBFlushAddr(highreg) 2180 * unsigned highreg; 2181 * 2182 * Results: 2183 * None. 2184 * 2185 * Side effects: 2186 * The process's page is flushed from the TLB. 2187 * 2188 *-------------------------------------------------------------------------- 2189 */ 2190LEAF(MachTLBFlushAddr) 2191 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2192 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2193 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2194 nop 2195 2196 mtc0 a0, MACH_COP_0_TLB_HI # look for addr & PID 2197 nop 2198 tlbp # Probe for the entry. 2199 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2200 li t1, MACH_CACHED_MEMORY_ADDR # Load invalid entry. 2201 bltz v0, 1f # index < 0 => !found 2202 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid 2203 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry. 2204 nop 2205 tlbwi 22061: 2207 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2208 j ra 2209 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2210END(MachTLBFlushAddr) 2211 2212/*-------------------------------------------------------------------------- 2213 * 2214 * MachTLBUpdate -- 2215 * 2216 * Update the TLB if highreg is found; otherwise, enter the data. 2217 * 2218 * MachTLBUpdate(highreg, lowreg) 2219 * unsigned highreg, lowreg; 2220 * 2221 * Results: 2222 * None. 2223 * 2224 * Side effects: 2225 * None. 2226 * 2227 *-------------------------------------------------------------------------- 2228 */ 2229LEAF(MachTLBUpdate) 2230 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2231 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2232 mfc0 t0, MACH_COP_0_TLB_HI # Save current PID 2233 nop # 2 cycles before intr disabled 2234 mtc0 a0, MACH_COP_0_TLB_HI # init high reg. 2235 nop 2236 tlbp # Probe for the entry. 2237 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2238 mtc0 a1, MACH_COP_0_TLB_LOW # init low reg. 2239 bltz v0, 1f # index < 0 => !found 2240 sra v0, v0, VMMACH_TLB_INDEX_SHIFT # convert index to regular num 2241 b 2f 2242 tlbwi # update slot found 22431: 2244 mtc0 a0, MACH_COP_0_TLB_HI # init high reg. 2245 nop 2246 tlbwr # enter into a random slot 22472: 2248 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2249 j ra 2250 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2251END(MachTLBUpdate) 2252 2253#if defined(DEBUG) 2254/*-------------------------------------------------------------------------- 2255 * 2256 * MachTLBFind -- 2257 * 2258 * Search the TLB for the given entry. 2259 * 2260 * MachTLBFind(hi) 2261 * unsigned hi; 2262 * 2263 * Results: 2264 * Returns a value >= 0 if the entry was found (the index). 2265 * Returns a value < 0 if the entry was not found. 2266 * 2267 * Side effects: 2268 * tlbhi and tlblo will contain the TLB entry found. 2269 * 2270 *-------------------------------------------------------------------------- 2271 */ 2272 .comm tlbhi, 4 2273 .comm tlblo, 4 2274LEAF(MachTLBFind) 2275 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2276 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2277 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2278 nop 2279 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high. 2280 nop 2281 tlbp # Probe for the entry. 2282 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got 2283 nop 2284 bltz v0, 1f # not found 2285 nop 2286 tlbr # read TLB 2287 mfc0 t1, MACH_COP_0_TLB_HI # See what we got 2288 mfc0 t2, MACH_COP_0_TLB_LOW # See what we got 2289 sw t1, tlbhi 2290 sw t2, tlblo 2291 srl v0, v0, VMMACH_TLB_INDEX_SHIFT # convert index to regular num 22921: 2293 mtc0 t0, MACH_COP_0_TLB_HI # Restore current PID 2294 j ra 2295 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2296END(MachTLBFind) 2297 2298/*-------------------------------------------------------------------------- 2299 * 2300 * MachTLBRead -- 2301 * 2302 * Read the TLB entry. 2303 * 2304 * MachTLBRead(entry) 2305 * unsigned entry; 2306 * 2307 * Results: 2308 * None. 2309 * 2310 * Side effects: 2311 * tlbhi and tlblo will contain the TLB entry found. 2312 * 2313 *-------------------------------------------------------------------------- 2314 */ 2315LEAF(MachTLBRead) 2316 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register. 2317 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts 2318 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID 2319 2320 sll a0, a0, VMMACH_TLB_INDEX_SHIFT 2321 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index register 2322 nop 2323 tlbr # Read from the TLB 2324 mfc0 t3, MACH_COP_0_TLB_HI # fetch the hi entry 2325 mfc0 t4, MACH_COP_0_TLB_LOW # fetch the low entry 2326 sw t3, tlbhi 2327 sw t4, tlblo 2328 2329 mtc0 t0, MACH_COP_0_TLB_HI # restore PID 2330 j ra 2331 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register 2332END(MachTLBRead) 2333 2334/*-------------------------------------------------------------------------- 2335 * 2336 * MachTLBGetPID -- 2337 * 2338 * MachTLBGetPID() 2339 * 2340 * Results: 2341 * Returns the current TLB pid reg. 2342 * 2343 * Side effects: 2344 * None. 2345 * 2346 *-------------------------------------------------------------------------- 2347 */ 2348LEAF(MachTLBGetPID) 2349 mfc0 v0, MACH_COP_0_TLB_HI # get PID 2350 nop 2351 and v0, v0, VMMACH_TLB_PID # mask off PID 2352 j ra 2353 srl v0, v0, VMMACH_TLB_PID_SHIFT # put PID in right spot 2354END(MachTLBGetPID) 2355 2356/* 2357 * Return the current value of the cause register. 2358 */ 2359LEAF(MachGetCauseReg) 2360 mfc0 v0, MACH_COP_0_CAUSE_REG 2361 j ra 2362 nop 2363END(MachGetCauseReg) 2364#endif /* DEBUG */ 2365 2366/*---------------------------------------------------------------------------- 2367 * 2368 * MachSwitchFPState -- 2369 * 2370 * Save the current state into 'from' and restore it from 'to'. 2371 * 2372 * MachSwitchFPState(from, to) 2373 * struct proc *from; 2374 * struct user *to; 2375 * 2376 * Results: 2377 * None. 2378 * 2379 * Side effects: 2380 * None. 2381 * 2382 *---------------------------------------------------------------------------- 2383 */ 2384LEAF(MachSwitchFPState) 2385 mfc0 t1, MACH_COP_0_STATUS_REG # Save old SR 2386 li t0, MACH_SR_COP_1_BIT # enable the coprocessor 2387 mtc0 t0, MACH_COP_0_STATUS_REG 2388 2389 beq a0, zero, 1f # skip save if NULL pointer 2390 nop 2391/* 2392 * First read out the status register to make sure that all FP operations 2393 * have completed. 2394 */ 2395 lw a0, P_ADDR(a0) # get pointer to pcb for proc 2396 cfc1 t0, MACH_FPC_CSR # stall til FP done 2397 cfc1 t0, MACH_FPC_CSR # now get status 2398 li t3, ~MACH_SR_COP_1_BIT 2399 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register 2400 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status 2401 and t2, t2, t3 # clear COP_1 enable bit 2402 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register 2403/* 2404 * Save the floating point registers. 2405 */ 2406 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) 2407 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) 2408 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) 2409 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) 2410 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) 2411 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) 2412 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) 2413 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) 2414 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) 2415 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) 2416 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) 2417 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) 2418 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) 2419 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) 2420 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) 2421 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) 2422 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) 2423 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) 2424 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) 2425 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) 2426 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) 2427 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) 2428 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) 2429 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) 2430 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) 2431 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) 2432 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) 2433 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) 2434 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) 2435 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) 2436 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) 2437 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) 2438 24391: 2440/* 2441 * Restore the floating point registers. 2442 */ 2443 lw t0, U_PCB_FPREGS+(32 * 4)(a1) # get status register 2444 lwc1 $f0, U_PCB_FPREGS+(0 * 4)(a1) 2445 lwc1 $f1, U_PCB_FPREGS+(1 * 4)(a1) 2446 lwc1 $f2, U_PCB_FPREGS+(2 * 4)(a1) 2447 lwc1 $f3, U_PCB_FPREGS+(3 * 4)(a1) 2448 lwc1 $f4, U_PCB_FPREGS+(4 * 4)(a1) 2449 lwc1 $f5, U_PCB_FPREGS+(5 * 4)(a1) 2450 lwc1 $f6, U_PCB_FPREGS+(6 * 4)(a1) 2451 lwc1 $f7, U_PCB_FPREGS+(7 * 4)(a1) 2452 lwc1 $f8, U_PCB_FPREGS+(8 * 4)(a1) 2453 lwc1 $f9, U_PCB_FPREGS+(9 * 4)(a1) 2454 lwc1 $f10, U_PCB_FPREGS+(10 * 4)(a1) 2455 lwc1 $f11, U_PCB_FPREGS+(11 * 4)(a1) 2456 lwc1 $f12, U_PCB_FPREGS+(12 * 4)(a1) 2457 lwc1 $f13, U_PCB_FPREGS+(13 * 4)(a1) 2458 lwc1 $f14, U_PCB_FPREGS+(14 * 4)(a1) 2459 lwc1 $f15, U_PCB_FPREGS+(15 * 4)(a1) 2460 lwc1 $f16, U_PCB_FPREGS+(16 * 4)(a1) 2461 lwc1 $f17, U_PCB_FPREGS+(17 * 4)(a1) 2462 lwc1 $f18, U_PCB_FPREGS+(18 * 4)(a1) 2463 lwc1 $f19, U_PCB_FPREGS+(19 * 4)(a1) 2464 lwc1 $f20, U_PCB_FPREGS+(20 * 4)(a1) 2465 lwc1 $f21, U_PCB_FPREGS+(21 * 4)(a1) 2466 lwc1 $f22, U_PCB_FPREGS+(22 * 4)(a1) 2467 lwc1 $f23, U_PCB_FPREGS+(23 * 4)(a1) 2468 lwc1 $f24, U_PCB_FPREGS+(24 * 4)(a1) 2469 lwc1 $f25, U_PCB_FPREGS+(25 * 4)(a1) 2470 lwc1 $f26, U_PCB_FPREGS+(26 * 4)(a1) 2471 lwc1 $f27, U_PCB_FPREGS+(27 * 4)(a1) 2472 lwc1 $f28, U_PCB_FPREGS+(28 * 4)(a1) 2473 lwc1 $f29, U_PCB_FPREGS+(29 * 4)(a1) 2474 lwc1 $f30, U_PCB_FPREGS+(30 * 4)(a1) 2475 lwc1 $f31, U_PCB_FPREGS+(31 * 4)(a1) 2476 2477 and t0, t0, ~MACH_FPC_EXCEPTION_BITS 2478 ctc1 t0, MACH_FPC_CSR 2479 nop 2480 2481 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register. 2482 j ra 2483 nop 2484END(MachSwitchFPState) 2485 2486/*---------------------------------------------------------------------------- 2487 * 2488 * MachSaveCurFPState -- 2489 * 2490 * Save the current floating point coprocessor state. 2491 * 2492 * MachSaveCurFPState(p) 2493 * struct proc *p; 2494 * 2495 * Results: 2496 * None. 2497 * 2498 * Side effects: 2499 * machFPCurProcPtr is cleared. 2500 * 2501 *---------------------------------------------------------------------------- 2502 */ 2503LEAF(MachSaveCurFPState) 2504 lw a0, P_ADDR(a0) # get pointer to pcb for proc 2505 mfc0 t1, MACH_COP_0_STATUS_REG # Disable interrupts and 2506 li t0, MACH_SR_COP_1_BIT # enable the coprocessor 2507 mtc0 t0, MACH_COP_0_STATUS_REG 2508 sw zero, machFPCurProcPtr # indicate state has been saved 2509/* 2510 * First read out the status register to make sure that all FP operations 2511 * have completed. 2512 */ 2513 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register 2514 li t3, ~MACH_SR_COP_1_BIT 2515 and t2, t2, t3 # clear COP_1 enable bit 2516 cfc1 t0, MACH_FPC_CSR # stall til FP done 2517 cfc1 t0, MACH_FPC_CSR # now get status 2518 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register 2519 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status 2520/* 2521 * Save the floating point registers. 2522 */ 2523 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0) 2524 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0) 2525 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0) 2526 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0) 2527 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0) 2528 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0) 2529 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0) 2530 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0) 2531 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0) 2532 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0) 2533 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0) 2534 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0) 2535 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0) 2536 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0) 2537 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0) 2538 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0) 2539 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0) 2540 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0) 2541 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0) 2542 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0) 2543 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0) 2544 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0) 2545 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0) 2546 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0) 2547 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0) 2548 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0) 2549 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0) 2550 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0) 2551 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0) 2552 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0) 2553 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0) 2554 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0) 2555 2556 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register. 2557 j ra 2558 nop 2559END(MachSaveCurFPState) 2560 2561/*---------------------------------------------------------------------------- 2562 * 2563 * MachFPInterrupt -- 2564 * 2565 * Handle a floating point interrupt. 2566 * 2567 * MachFPInterrupt(statusReg, causeReg, pc) 2568 * unsigned statusReg; 2569 * unsigned causeReg; 2570 * unsigned pc; 2571 * 2572 * Results: 2573 * None. 2574 * 2575 * Side effects: 2576 * None. 2577 * 2578 *---------------------------------------------------------------------------- 2579 */ 2580NON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra) 2581 subu sp, sp, STAND_FRAME_SIZE 2582 mfc0 t0, MACH_COP_0_STATUS_REG 2583 sw ra, STAND_RA_OFFSET(sp) 2584 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2585 2586 or t1, t0, MACH_SR_COP_1_BIT 2587 mtc0 t1, MACH_COP_0_STATUS_REG 2588 nop 2589 nop 2590 cfc1 t1, MACH_FPC_CSR # stall til FP done 2591 cfc1 t1, MACH_FPC_CSR # now get status 2592 nop 2593 sll t2, t1, (31 - 17) # unimplemented operation? 2594 bgez t2, 3f # no, normal trap 2595 nop 2596/* 2597 * We got an unimplemented operation trap so 2598 * fetch the instruction, compute the next PC and emulate the instruction. 2599 */ 2600 bgez a1, 1f # Check the branch delay bit. 2601 nop 2602/* 2603 * The instruction is in the branch delay slot so the branch will have to 2604 * be emulated to get the resulting PC. 2605 */ 2606 sw a2, STAND_FRAME_SIZE + 8(sp) 2607 li a0, UADDR+U_PCB_REGS # first arg is ptr to CPU registers 2608 move a1, a2 # second arg is instruction PC 2609 move a2, t1 # third arg is floating point CSR 2610 jal MachEmulateBranch # compute PC after branch 2611 move a3, zero # fourth arg is FALSE 2612/* 2613 * Now load the floating-point instruction in the branch delay slot 2614 * to be emulated. 2615 */ 2616 lw a2, STAND_FRAME_SIZE + 8(sp) # restore EXC pc 2617 b 2f 2618 lw a0, 4(a2) # a0 = coproc instruction 2619/* 2620 * This is not in the branch delay slot so calculate the resulting 2621 * PC (epc + 4) into v0 and continue to MachEmulateFP(). 2622 */ 26231: 2624 lw a0, 0(a2) # a0 = coproc instruction 2625 addu v0, a2, 4 # v0 = next pc 26262: 2627 sw v0, UADDR+U_PCB_REGS+(PC * 4) # save new pc 2628/* 2629 * Check to see if the instruction to be emulated is a floating-point 2630 * instruction. 2631 */ 2632 srl a3, a0, MACH_OPCODE_SHIFT 2633 beq a3, MACH_OPCODE_C1, 4f # this should never fail 2634/* 2635 * Send a floating point exception signal to the current process. 2636 */ 26373: 2638 lw a0, curproc # get current process 2639 cfc1 a2, MACH_FPC_CSR # code = FP execptions 2640 ctc1 zero, MACH_FPC_CSR # Clear exceptions 2641 jal trapsignal 2642 li a1, SIGFPE 2643 b FPReturn 2644 nop 2645 2646/* 2647 * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate. 2648 */ 26494: 2650 jal MachEmulateFP 2651 nop 2652 2653/* 2654 * Turn off the floating point coprocessor and return. 2655 */ 2656FPReturn: 2657 mfc0 t0, MACH_COP_0_STATUS_REG 2658 lw ra, STAND_RA_OFFSET(sp) 2659 and t0, t0, ~MACH_SR_COP_1_BIT 2660 mtc0 t0, MACH_COP_0_STATUS_REG 2661 j ra 2662 addu sp, sp, STAND_FRAME_SIZE 2663END(MachFPInterrupt) 2664 2665/*---------------------------------------------------------------------------- 2666 * 2667 * MachConfigCache -- 2668 * 2669 * Size the caches. 2670 * NOTE: should only be called from mach_init(). 2671 * 2672 * Results: 2673 * None. 2674 * 2675 * Side effects: 2676 * The size of the data cache is stored into machDataCacheSize and the 2677 * size of instruction cache is stored into machInstCacheSize. 2678 * 2679 *---------------------------------------------------------------------------- 2680 */ 2681NON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra) 2682 subu sp, sp, STAND_FRAME_SIZE 2683 sw ra, STAND_RA_OFFSET(sp) # Save return address. 2684 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE) 2685 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2686 la v0, 1f 2687 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2688 j v0 2689 nop 26901: 2691/* 2692 * This works because jal doesn't change pc[31..28] and the 2693 * linker still thinks SizeCache is in the cached region so it computes 2694 * the correct address without complaining. 2695 */ 2696 jal SizeCache # Get the size of the d-cache. 2697 nop 2698 sw v0, machDataCacheSize 2699 nop # Make sure sw out of pipe 2700 nop 2701 nop 2702 nop 2703 li v0, MACH_SR_SWAP_CACHES # Swap caches 2704 mtc0 v0, MACH_COP_0_STATUS_REG 2705 nop # Insure caches stable 2706 nop 2707 nop 2708 nop 2709 jal SizeCache # Get the size of the i-cache. 2710 nop 2711 mtc0 zero, MACH_COP_0_STATUS_REG # Swap back caches and enable. 2712 nop 2713 nop 2714 nop 2715 nop 2716 sw v0, machInstCacheSize 2717 la t0, 1f 2718 j t0 # Back to cached mode 2719 nop 27201: 2721 lw ra, STAND_RA_OFFSET(sp) # Restore return addr 2722 addu sp, sp, STAND_FRAME_SIZE # Restore sp. 2723 j ra 2724 nop 2725END(MachConfigCache) 2726 2727/*---------------------------------------------------------------------------- 2728 * 2729 * SizeCache -- 2730 * 2731 * Get the size of the cache. 2732 * 2733 * Results: 2734 * The size of the cache. 2735 * 2736 * Side effects: 2737 * None. 2738 * 2739 *---------------------------------------------------------------------------- 2740 */ 2741LEAF(SizeCache) 2742 mfc0 t0, MACH_COP_0_STATUS_REG # Save the current status reg. 2743 nop 2744 or v0, t0, MACH_SR_ISOL_CACHES # Isolate the caches. 2745 nop # Make sure no stores in pipe 2746 mtc0 v0, MACH_COP_0_STATUS_REG 2747 nop # Make sure isolated 2748 nop 2749 nop 2750/* 2751 * Clear cache size boundaries. 2752 */ 2753 li v0, MACH_MIN_CACHE_SIZE 2754 li v1, MACH_CACHED_MEMORY_ADDR 2755 li t2, MACH_MAX_CACHE_SIZE 27561: 2757 addu t1, v0, v1 # Compute address to clear 2758 sw zero, 0(t1) # Clear cache memory 2759 bne v0, t2, 1b 2760 sll v0, v0, 1 2761 2762 li v0, -1 2763 sw v0, 0(v1) # Store marker in cache 2764 li v0, MACH_MIN_CACHE_SIZE 27652: 2766 addu t1, v0, v1 # Compute address 2767 lw t3, 0(t1) # Look for marker 2768 nop 2769 bne t3, zero, 3f # Found marker. 2770 nop 2771 bne v0, t2, 2b # keep looking 2772 sll v0, v0, 1 # cache size * 2 2773 2774 move v0, zero # must be no cache 27753: 2776 mtc0 t0, MACH_COP_0_STATUS_REG 2777 nop # Make sure unisolated 2778 nop 2779 nop 2780 nop 2781 j ra 2782 nop 2783END(SizeCache) 2784 2785/*---------------------------------------------------------------------------- 2786 * 2787 * MachFlushCache -- 2788 * 2789 * Flush the caches. 2790 * 2791 * Results: 2792 * None. 2793 * 2794 * Side effects: 2795 * The contents of the caches is flushed. 2796 * 2797 *---------------------------------------------------------------------------- 2798 */ 2799LEAF(MachFlushCache) 2800 lw t1, machInstCacheSize # Must load before isolating 2801 lw t2, machDataCacheSize # Must load before isolating 2802 mfc0 t3, MACH_COP_0_STATUS_REG # Save the status register. 2803 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2804 la v0, 1f 2805 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2806 j v0 2807 nop 2808/* 2809 * Flush the instruction cache. 2810 */ 28111: 2812 li v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES 2813 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap caches. 2814 li t0, MACH_UNCACHED_MEMORY_ADDR 2815 subu t0, t0, t1 2816 li t1, MACH_UNCACHED_MEMORY_ADDR 2817 la v0, 1f # Run cached 2818 j v0 2819 nop 28201: 2821 addu t0, t0, 4 2822 bne t0, t1, 1b 2823 sb zero, -4(t0) 2824 2825 la v0, 1f 2826 or v0, MACH_UNCACHED_MEMORY_ADDR 2827 j v0 # Run uncached 2828 nop 2829/* 2830 * Flush the data cache. 2831 */ 28321: 2833 li v0, MACH_SR_ISOL_CACHES 2834 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap back caches 2835 li t0, MACH_UNCACHED_MEMORY_ADDR 2836 subu t0, t0, t2 2837 la v0, 1f 2838 j v0 # Back to cached mode 2839 nop 28401: 2841 addu t0, t0, 4 2842 bne t0, t1, 1b 2843 sb zero, -4(t0) 2844 2845 nop # Insure isolated stores 2846 nop # out of pipe. 2847 nop 2848 nop 2849 mtc0 t3, MACH_COP_0_STATUS_REG # Restore status reg. 2850 nop # Insure cache unisolated. 2851 nop 2852 nop 2853 nop 2854 j ra 2855 nop 2856END(MachFlushCache) 2857 2858/*---------------------------------------------------------------------------- 2859 * 2860 * MachFlushICache -- 2861 * 2862 * void MachFlushICache(addr, len) 2863 * vm_offset_t addr, len; 2864 * 2865 * Flush instruction cache for range of addr to addr + len - 1. 2866 * The address can be any valid address so long as no TLB misses occur. 2867 * 2868 * Results: 2869 * None. 2870 * 2871 * Side effects: 2872 * The contents of the cache is flushed. 2873 * 2874 *---------------------------------------------------------------------------- 2875 */ 2876LEAF(MachFlushICache) 2877 mfc0 t0, MACH_COP_0_STATUS_REG # Save SR 2878 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2879 2880 la v1, 1f 2881 or v1, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2882 j v1 2883 nop 28841: 2885 bc0f 1b # make sure stores are complete 2886 li v1, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES 2887 mtc0 v1, MACH_COP_0_STATUS_REG 2888 nop 2889 addu a1, a1, a0 # compute ending address 28901: 2891 addu a0, a0, 4 2892 bne a0, a1, 1b 2893 sb zero, -4(a0) 2894 2895 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts 2896 j ra # return and run cached 2897 nop 2898END(MachFlushICache) 2899 2900/*---------------------------------------------------------------------------- 2901 * 2902 * MachFlushDCache -- 2903 * 2904 * void MachFlushDCache(addr, len) 2905 * vm_offset_t addr, len; 2906 * 2907 * Flush data cache for range of addr to addr + len - 1. 2908 * The address can be any valid address so long as no TLB misses occur. 2909 * (Be sure to use cached K0SEG kernel addresses) 2910 * Results: 2911 * None. 2912 * 2913 * Side effects: 2914 * The contents of the cache is flushed. 2915 * 2916 *---------------------------------------------------------------------------- 2917 */ 2918LEAF(MachFlushDCache) 2919 mfc0 t0, MACH_COP_0_STATUS_REG # Save SR 2920 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts. 2921 2922 la v1, 1f 2923 or v1, MACH_UNCACHED_MEMORY_ADDR # Run uncached. 2924 j v1 2925 nop 29261: 2927 bc0f 1b # make sure stores are complete 2928 li v1, MACH_SR_ISOL_CACHES 2929 mtc0 v1, MACH_COP_0_STATUS_REG 2930 nop 2931 addu a1, a1, a0 # compute ending address 29321: 2933 addu a0, a0, 4 2934 bne a0, a1, 1b 2935 sb zero, -4(a0) 2936 2937 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts 2938 j ra # return and run cached 2939 nop 2940END(MachFlushDCache) 2941 2942#ifdef KADB 2943/* 2944 * Read a long and return it. 2945 * Note: addresses can be unaligned! 2946 * 2947 * long 2948L* kdbpeek(addr) 2949L* caddt_t addr; 2950L* { 2951L* return (*(long *)addr); 2952L* } 2953 */ 2954LEAF(kdbpeek) 2955 li v0, KADBERR 2956 sw v0, UADDR+U_PCB_ONFAULT 2957 and v0, a0, 3 # unaligned address? 2958 bne v0, zero, 1f 2959 nop 2960 b 2f 2961 lw v0, (a0) # aligned access 29621: 2963 lwr v0, 0(a0) # get next 4 bytes (unaligned) 2964 lwl v0, 3(a0) 29652: 2966 j ra # made it w/o errors 2967 sw zero, UADDR+U_PCB_ONFAULT 2968kadberr: 2969 li v0, 1 # trap sends us here 2970 sw v0, kdbmkfault 2971 j ra 2972 nop 2973END(kdbpeek) 2974 2975/* 2976 * Write a long to 'addr'. 2977 * Note: addresses can be unaligned! 2978 * 2979L* void 2980L* kdbpoke(addr, value) 2981L* caddt_t addr; 2982L* long value; 2983L* { 2984L* *(long *)addr = value; 2985L* } 2986 */ 2987LEAF(kdbpoke) 2988 li v0, KADBERR 2989 sw v0, UADDR+U_PCB_ONFAULT 2990 and v0, a0, 3 # unaligned address? 2991 bne v0, zero, 1f 2992 nop 2993 b 2f 2994 sw a1, (a0) # aligned access 29951: 2996 swr a1, 0(a0) # store next 4 bytes (unaligned) 2997 swl a1, 3(a0) 2998 and a0, a0, ~3 # align address for cache flush 29992: 3000 sw zero, UADDR+U_PCB_ONFAULT 3001 b MachFlushICache # flush instruction cache 3002 li a1, 8 3003END(kdbpoke) 3004 3005/* 3006 * Save registers and state so we can do a 'kdbreset' (like longjmp) later. 3007 * Always returns zero. 3008 * 3009L* int kdb_savearea[11]; 3010L* 3011L* int 3012L* kdbsetexit() 3013L* { 3014L* kdb_savearea[0] = 0; 3015L* return (0); 3016L* } 3017 */ 3018 .comm kdb_savearea, (11 * 4) 3019 3020LEAF(kdbsetexit) 3021 la a0, kdb_savearea 3022 sw s0, 0(a0) 3023 sw s1, 4(a0) 3024 sw s2, 8(a0) 3025 sw s3, 12(a0) 3026 sw s4, 16(a0) 3027 sw s5, 20(a0) 3028 sw s6, 24(a0) 3029 sw s7, 28(a0) 3030 sw sp, 32(a0) 3031 sw s8, 36(a0) 3032 sw ra, 40(a0) 3033 j ra 3034 move v0, zero 3035END(kdbsetexit) 3036 3037/* 3038 * Restore registers and state (like longjmp) and return x. 3039 * 3040L* int 3041L* kdbreset(x) 3042L* { 3043L* return (x); 3044L* } 3045 */ 3046LEAF(kdbreset) 3047 la v0, kdb_savearea 3048 lw ra, 40(v0) 3049 lw s0, 0(v0) 3050 lw s1, 4(v0) 3051 lw s2, 8(v0) 3052 lw s3, 12(v0) 3053 lw s4, 16(v0) 3054 lw s5, 20(v0) 3055 lw s6, 24(v0) 3056 lw s7, 28(v0) 3057 lw sp, 32(v0) 3058 lw s8, 36(v0) 3059 j ra 3060 move v0, a0 3061END(kdbreset) 3062 3063/* 3064 * Trap into the debugger. 3065 * 3066L* void 3067L* kdbpanic() 3068L* { 3069L* } 3070 */ 3071LEAF(kdbpanic) 3072 break MACH_BREAK_KDB_VAL 3073 j ra 3074 nop 3075END(kdbpanic) 3076#endif /* KADB */ 3077 3078#ifdef DEBUG 3079LEAF(cpu_getregs) 3080 sw sp, 0(a0) 3081 sw ra, 4(a0) 3082 j ra 3083 sw s8, 8(a0) 3084END(cpu_getregs) 3085#endif /* DEBUG */ 3086 3087/* 3088 * Interrupt counters for vmstat. 3089 * XXX These aren't used yet. 3090 */ 3091 .data 3092 .globl intrcnt, eintrcnt, intrnames, eintrnames 3093intrnames: 3094 .asciiz "spur" 3095 .asciiz "hil" 3096 .asciiz "lev2" 3097 .asciiz "lev3" 3098 .asciiz "lev4" 3099 .asciiz "lev5" 3100 .asciiz "dma" 3101 .asciiz "clock" 3102 .asciiz "statclock" 3103 .asciiz "nmi" 3104eintrnames: 3105 .align 2 3106intrcnt: 3107 .word 0,0,0,0,0,0,0,0,0,0 3108eintrcnt: 3109