1/* 2 * mips 24k machine assist for routerboard rb450g 3 */ 4#include "mem.h" 5#include "mips.s" 6 7#define SANITY 0x12345678 8 9 NOSCHED 10 11/* 12 * Boot only processor 13 */ 14TEXT start(SB), $-4 15 /* save parameters passed from routerboot */ 16 MOVW R4, R19 /* argc */ 17 MOVW R5, R20 /* argv */ 18 MOVW R6, R21 /* envp */ 19 MOVW R7, R23 /* memory size */ 20 21 MOVW $setR30(SB), R30 22 23PUTC('9', R1, R2) 24 DI(0) 25 26 MOVW sanity(SB), R1 27 CONST(SANITY, R2) 28 SUBU R1, R2, R2 29 BNE R2, insane 30 NOP 31 32 MOVW R0, M(COMPARE) 33 EHB 34 35 /* don't enable any interrupts nor FP, but leave BEV on. */ 36 MOVW $BEV,R1 37 MOVW R1, M(STATUS) 38 UBARRIERS(7, R7, stshb) /* returns to kseg1 space */ 39 MOVW R0, M(CAUSE) 40 EHB 41 42 /* silence the atheros watchdog */ 43 MOVW $(KSEG1|0x18060008), R1 44 MOVW R0, (R1) /* set no action */ 45 SYNC 46 47 MOVW $PE, R1 48 MOVW R1, M(CACHEECC) /* aka ErrCtl */ 49 EHB 50 JAL cleancache(SB) 51 NOP 52 53 MOVW $TLBROFF, R1 54 MOVW R1, M(WIRED) 55 56 MOVW R0, M(CONTEXT) 57 EHB 58 59 /* set KSEG0 cachability before trying LL/SC in lock code */ 60 MOVW M(CONFIG), R1 61 AND $~CFG_K0, R1 62 /* make kseg0 cachable, enable write-through merging */ 63 OR $((PTECACHABILITY>>3)|CFG_MM), R1 64 MOVW R1, M(CONFIG) 65 BARRIERS(7, R7, cfghb) /* back to kseg0 space */ 66 67 MOVW $setR30(SB), R30 /* again */ 68 69 /* initialize Mach, including stack */ 70 MOVW $MACHADDR, R(MACH) 71 ADDU $(MACHSIZE-BY2V), R(MACH), SP 72 MOVW R(MACH), R1 73clrmach: 74 MOVW R0, (R1) 75 ADDU $BY2WD, R1 76 BNE R1, SP, clrmach 77 NOP 78 MOVW R0, 0(R(MACH)) /* m->machno = 0 */ 79 MOVW R0, R(USER) /* up = nil */ 80 81 /* zero bss */ 82 MOVW $edata(SB), R1 83 MOVW $end(SB), R2 84clrbss: 85 MOVW R0, (R1) 86 ADDU $BY2WD, R1 87 BNE R1, R2, clrbss 88 NOP 89 90 MOVW R0, HI 91 MOVW R0, LO 92 93PUTC('\r', R1, R2) 94PUTC('\n', R1, R2) 95 96 /* 97 * restore parameters passed from routerboot and 98 * pass them as arguments to main(). 99 */ 100 SUB $(5*4), SP /* reserve space for args to main() + link */ 101 MOVW R19, R1 /* argc */ 102 MOVW R20, 8(SP) /* argv */ 103 MOVW R21, 12(SP) /* envp */ 104 MOVW R23, 16(SP) /* memory size */ 105 106 MOVW $0x16, R16 107 MOVW $0x17, R17 108 MOVW $0x18, R18 109 MOVW $0x19, R19 110 MOVW $0x20, R20 111 MOVW $0x21, R21 112 MOVW $0x22, R22 113 MOVW $0x23, R23 114 115 JAL main(SB) 116 NOP 117 118 /* shouldn't get here */ 119 CONST(ROM, R1) 120 JMP (R1) /* back to the rom */ 121 NOP 122 123#define PUT(c) PUTC(c, R1, R2) 124#define DELAY(lab) \ 125 CONST(34000000, R3); \ 126lab: SUBU $1, R3; \ 127 BNE R3, lab; \ 128 NOP 129 130insane: 131 /* 132 * data segment is misaligned; kernel needs vl -R4096 or -R16384, 133 * as appropriate, for reboot. 134 */ 135 PUT('?'); PUT('d'); PUT('a'); PUT('t'); PUT('a'); PUT(' '); DELAY(dl1) 136 PUT('s'); PUT('e'); PUT('g'); PUT('m'); PUT('e'); PUT('n'); DELAY(dl2) 137 PUT('t'); PUT(' '); PUT('m'); PUT('i'); PUT('s'); PUT('a'); DELAY(dl3) 138 PUT('l'); PUT('i'); PUT('g'); PUT('n'); PUT('e'); PUT('d'); DELAY(dl4) 139 PUT('\r'); PUT('\n'); DELAY(dl5) 140 CONST(ROM, R1) 141 JMP (R1) /* back to the rom */ 142 NOP 143 144/* target for JALRHB in BARRIERS */ 145TEXT ret(SB), $-4 146 JMP (R22) 147 NOP 148 149/* print R1 in hex; clobbers R3—8 */ 150TEXT printhex(SB), $-4 151 MOVW $32, R5 152 MOVW $9, R7 153prtop: 154 SUB $4, R5 155 MOVW R1, R6 156 SRL R5, R6 157 AND $0xf, R6 158 SGTU R6, R7, R8 159 BEQ R8, prdec /* branch if R6 <= 9 */ 160 NOP 161 ADD $('a'-10), R6 162 JMP prchar 163 NOP 164prdec: 165 ADD $'0', R6 166prchar: 167 PUTC(R6, R3, R4) 168 BNE R5, prtop 169 NOP 170 RETURN 171 172/* 173 * Take first processor into user mode 174 * - argument is stack pointer to user 175 */ 176TEXT touser(SB), $-4 177 DI(0) /* ensure intrs see consistent M(STATUS) */ 178 MOVW R1, SP 179 MOVW $(UTZERO+32), R2 /* header appears in text */ 180 MOVW R2, M(EPC) 181 EHB 182 MOVW M(STATUS), R4 183 AND $(~KMODEMASK), R4 184 OR $(KUSER|IE|EXL), R4 /* switch to user mode, intrs on, exc */ 185 MOVW R4, M(STATUS) /* " */ 186 ERET /* clears EXL */ 187 188/* 189 * manipulate interrupts 190 */ 191 192/* enable an interrupt; bit is in R1 */ 193TEXT intron(SB), $0 194 MOVW M(STATUS), R2 195 OR R1, R2 196 MOVW R2, M(STATUS) 197 EHB 198 RETURN 199 200/* disable an interrupt; bit is in R1 */ 201TEXT introff(SB), $0 202 MOVW M(STATUS), R2 203 XOR $-1, R1 204 AND R1, R2 205 MOVW R2, M(STATUS) 206 EHB 207 RETURN 208 209/* on our 24k, wait instructions are not interruptible, alas. */ 210TEXT idle(SB), $-4 211 EI(1) /* old M(STATUS) into R1 */ 212 EHB 213 /* fall through */ 214 215TEXT wait(SB), $-4 216 WAIT 217 NOP 218 219 MOVW R1, M(STATUS) /* interrupts restored */ 220 EHB 221 RETURN 222 223TEXT splhi(SB), $0 224 EHB 225 MOVW R31, 12(R(MACH)) /* save PC in m->splpc */ 226 DI(1) /* old M(STATUS) into R1 */ 227 EHB 228 RETURN 229 230TEXT splx(SB), $0 231 EHB 232 MOVW R31, 12(R(MACH)) /* save PC in m->splpc */ 233 MOVW M(STATUS), R2 234 AND $IE, R1 235 AND $~IE, R2 236 OR R2, R1 237 MOVW R1, M(STATUS) 238 EHB 239 RETURN 240 241TEXT spllo(SB), $0 242 EHB 243 EI(1) /* old M(STATUS) into R1 */ 244 EHB 245 RETURN 246 247TEXT spldone(SB), $0 248 RETURN 249 250TEXT islo(SB), $0 251 MOVW M(STATUS), R1 252 AND $IE, R1 253 RETURN 254 255TEXT coherence(SB), $-4 256 BARRIERS(7, R7, cohhb) 257 SYNC 258 EHB 259 RETURN 260 261/* 262 * bit twiddling 263 */ 264 265TEXT clz(SB), $-4 /* dest = clz(src): count leading zeroes */ 266 CLZ(1, 1) 267 RETURN 268 269/* 270 * process switching 271 */ 272 273TEXT setlabel(SB), $-4 274 MOVW R29, 0(R1) 275 MOVW R31, 4(R1) 276 MOVW R0, R1 277 RETURN 278 279TEXT gotolabel(SB), $-4 280 MOVW 0(R1), R29 281 MOVW 4(R1), R31 282 MOVW $1, R1 283 RETURN 284 285/* 286 * the tlb routines need to be called at splhi. 287 */ 288 289TEXT puttlb(SB), $0 /* puttlb(virt, phys0, phys1) */ 290 EHB 291 MOVW R1, M(TLBVIRT) 292 EHB 293 MOVW 4(FP), R2 /* phys0 */ 294 MOVW 8(FP), R3 /* phys1 */ 295 MOVW R2, M(TLBPHYS0) 296 EHB 297 MOVW $PGSZ, R1 298 MOVW R3, M(TLBPHYS1) 299 EHB 300 MOVW R1, M(PAGEMASK) 301 OR R2, R3, R4 /* MTC0 delay slot */ 302 AND $PTEVALID, R4 /* MTC0 delay slot */ 303 EHB 304 TLBP /* tlb probe */ 305 EHB 306 MOVW M(INDEX), R1 307 BGEZ R1, index /* if tlb entry found, use it */ 308 NOP 309 BEQ R4, dont /* not valid? cf. kunmap */ 310 NOP 311 MOVW M(RANDOM), R1 /* write random tlb entry */ 312 MOVW R1, M(INDEX) 313index: 314 EHB 315 TLBWI /* write indexed tlb entry */ 316 JRHB(31) /* return and clear all hazards */ 317dont: 318 RETURN 319 320TEXT getwired(SB),$0 321 MOVW M(WIRED), R1 322 RETURN 323 324TEXT setwired(SB),$0 325 MOVW R1, M(WIRED) 326 EHB 327 RETURN 328 329TEXT getrandom(SB),$0 330 MOVW M(RANDOM), R1 331 RETURN 332 333TEXT getpagemask(SB),$0 334 MOVW M(PAGEMASK), R1 335 RETURN 336 337TEXT setpagemask(SB),$0 338 EHB 339 MOVW R1, M(PAGEMASK) 340 EHB 341 MOVW R0, R1 /* prevent accidents */ 342 RETURN 343 344TEXT puttlbx(SB), $0 /* puttlbx(index, virt, phys0, phys1, pagemask) */ 345 MOVW 4(FP), R2 346 MOVW 8(FP), R3 347 MOVW 12(FP), R4 348 MOVW 16(FP), R5 349 EHB 350 MOVW R2, M(TLBVIRT) 351 EHB 352 MOVW R3, M(TLBPHYS0) 353 MOVW R4, M(TLBPHYS1) 354 MOVW R5, M(PAGEMASK) 355 EHB 356 MOVW R1, M(INDEX) 357 EHB 358 TLBWI /* write indexed tlb entry */ 359 JRHB(31) /* return and clear all hazards */ 360 361TEXT tlbvirt(SB), $0 362 EHB 363 MOVW M(TLBVIRT), R1 364 EHB 365 RETURN 366 367TEXT gettlbx(SB), $0 /* gettlbx(index, &entry) */ 368 MOVW 4(FP), R5 369 MOVW M(TLBVIRT), R10 /* save our asid */ 370 EHB 371 MOVW R1, M(INDEX) 372 EHB 373 TLBR /* read indexed tlb entry */ 374 EHB 375 MOVW M(TLBVIRT), R2 376 MOVW M(TLBPHYS0), R3 377 MOVW M(TLBPHYS1), R4 378 MOVW R2, 0(R5) 379 MOVW R3, 4(R5) 380 MIPS24KNOP 381 MOVW R4, 8(R5) 382 EHB 383 MOVW R10, M(TLBVIRT) /* restore our asid */ 384 EHB 385 RETURN 386 387TEXT gettlbp(SB), $0 /* gettlbp(tlbvirt, &entry) */ 388 MOVW 4(FP), R5 389 MOVW M(TLBVIRT), R10 /* save our asid */ 390 EHB 391 MOVW R1, M(TLBVIRT) 392 EHB 393 TLBP /* probe tlb */ 394 EHB 395 MOVW M(INDEX), R1 396 BLTZ R1, gettlbp1 /* if no tlb entry found, return */ 397 NOP 398 EHB 399 TLBR /* read indexed tlb entry */ 400 EHB 401 MOVW M(TLBVIRT), R2 402 MOVW M(TLBPHYS0), R3 403 MOVW M(TLBPHYS1), R4 404 MOVW M(PAGEMASK), R6 405 MOVW R2, 0(R5) 406 MOVW R3, 4(R5) 407 MIPS24KNOP 408 MOVW R4, 8(R5) 409 MOVW R6, 12(R5) 410gettlbp1: 411 EHB 412 MOVW R10, M(TLBVIRT) /* restore our asid */ 413 EHB 414 RETURN 415 416TEXT gettlbvirt(SB), $0 /* gettlbvirt(index) */ 417 MOVW M(TLBVIRT), R10 /* save our asid */ 418 EHB 419 MOVW R1, M(INDEX) 420 EHB 421 TLBR /* read indexed tlb entry */ 422 EHB 423 MOVW M(TLBVIRT), R1 424 EHB 425 MOVW R10, M(TLBVIRT) /* restore our asid */ 426 EHB 427 RETURN 428 429/* 430 * exceptions. 431 * 432 * mips promises that there will be no current hazards upon entry 433 * to exception handlers. 434 */ 435 436 /* will be copied into low memory vectors; must fit in 32 words */ 437TEXT vector0(SB), $-4 438 MOVW $utlbmiss(SB), R26 439 JMP (R26) 440 NOP 441 442/* 443 * compute stlb hash index. 444 * must match index calculation in mmu.c/putstlb() 445 * 446 * M(TLBVIRT) [page & asid] in arg, result in arg. 447 * stir in swizzled asid; we get best results with asid in both high & low bits. 448 * 449 * page = tlbvirt >> (PGSHIFT+1); // ignoring even/odd bit 450 * arg = (tlbvirt<<(STLBLOG-8) ^ (uchar)tlbvirt ^ page ^ 451 * ((page & (MASK(HIPFNBITS) << STLBLOG)) >> HIPFNBITS)) & (STLBSIZE-1); 452 */ 453#define STLBHASH(arg, tmp, tmp2) \ 454 MOVW arg, tmp2; \ 455 SRL $(PGSHIFT+1), arg; /* move low page # bits to low bits */ \ 456 CONST ((MASK(HIPFNBITS) << STLBLOG), tmp); \ 457 AND arg, tmp; /* extract high page # bits */ \ 458 SRL $HIPFNBITS, tmp; /* position them */ \ 459 XOR tmp, arg; /* include them */ \ 460 MOVW tmp2, tmp; /* asid in low byte */ \ 461 SLL $(STLBLOG-8), tmp; /* move asid to high bits */ \ 462 XOR tmp, arg; /* include asid in high bits too */ \ 463 MOVBU tmp2, tmp; /* asid in low byte of tlbvirt */ \ 464 XOR tmp, arg; /* include asid in low bits */ \ 465 CONST (STLBSIZE-1, tmp); \ 466 AND tmp, arg /* chop to fit */ 467/* 468 * vc -S generated essentially this, which uses 4 registers and 469 * R28 for big constants: 470 MOVW R1, R4 471 SRL $(PGSHIFT+1), R1, R3 // page = tlbvirt>>(PGSHIFT+1) 472 SLL $(STLBLOG-8), R1, R1 // tlbvirt<<(STLBLOG-8) 473 MOVBU R4, R5 // (uchar)tlbvirt 474 XOR R5, R1 475 XOR R3, R1 476 AND $(MASK(HIPFNBITS) << STLBLOG), R3 477 SRL $HIPFNBITS, R3 478 XOR R3, R1 479 AND $(STLBSIZE-1), R1 // chop to fit 480 */ 481 482TEXT utlbmiss(SB), $-4 483 /* 484 * don't use R28 by using constants that span both word halves, 485 * it's unsaved so far. avoid R24 (up in kernel) and R25 (m in kernel). 486 */ 487 /* update statistics */ 488 CONST (MACHADDR+16, R26) /* R26 = &m->tlbfault */ 489 MOVW (R26), R27 490 ADDU $1, R27 491 MOVW R27, (R26) /* m->tlbfault++ */ 492 493 MOVW R23, M(DESAVE) /* save R23 */ 494 495#ifdef KUTLBSTATS 496 ADDU $4, R26 /* &m->ktlbfault */ 497 498 MOVW M(STATUS), R23 499 AND $KUSER, R23 500 BEQ R23, kmiss 501 NOP 502 ADDU $4, R26 /* m->utlbfault */ 503kmiss: 504 MOVW (R26), R27 505 ADDU $1, R27 506 MOVW R27, (R26) /* m->[ku]tlbfault++ */ 507#endif 508 509 /* compute stlb index */ 510 EHB 511 MOVW M(TLBVIRT), R27 /* asid in low byte */ 512 STLBHASH(R27, R26, R23) 513 MOVW M(DESAVE), R23 /* restore R23 */ 514 515 /* scale to a byte index (multiply by 12 [3 ulongs]) */ 516 SLL $1, R27, R26 /* × 2 */ 517 ADDU R26, R27 /* × 3 */ 518 SLL $2, R27 /* × 12 */ 519 520 CONST (MACHADDR, R26) /* R26 = m-> */ 521 MOVW 4(R26), R26 /* R26 = m->stb */ 522 ADDU R26, R27 /* R27 = &m->stb[hash] */ 523 524 MOVW M(BADVADDR), R26 525 AND $BY2PG, R26 526 BNE R26, utlbodd /* odd page? */ 527 NOP 528 529utlbeven: 530 MOVW 4(R27), R26 /* R26 = m->stb[hash].phys0 */ 531 BEQ R26, stlbm /* nothing cached? do it the hard way */ 532 NOP 533 MOVW R26, M(TLBPHYS0) 534 EHB 535 MOVW 8(R27), R26 /* R26 = m->stb[hash].phys1 */ 536 JMP utlbcom 537 MOVW R26, M(TLBPHYS1) /* branch delay slot */ 538 539utlbodd: 540 MOVW 8(R27), R26 /* R26 = m->stb[hash].phys1 */ 541 BEQ R26, stlbm /* nothing cached? do it the hard way */ 542 NOP 543 MOVW R26, M(TLBPHYS1) 544 EHB 545 MOVW 4(R27), R26 /* R26 = m->stb[hash].phys0 */ 546 MOVW R26, M(TLBPHYS0) 547 548utlbcom: 549 EHB /* MTC0/MFC0 hazard */ 550 MOVW M(TLBVIRT), R26 551 MOVW (R27), R27 /* R27 = m->stb[hash].virt */ 552 BEQ R27, stlbm /* nothing cached? do it the hard way */ 553 NOP 554 /* is the stlb entry for the right virtual address? */ 555 BNE R26, R27, stlbm /* M(TLBVIRT) != m->stb[hash].virt? */ 556 NOP 557 558 /* if an entry exists, overwrite it, else write a random one */ 559 CONST (PGSZ, R27) 560 MOVW R27, M(PAGEMASK) /* select page size */ 561 EHB 562 TLBP /* probe tlb */ 563 EHB 564 MOVW M(INDEX), R26 565 BGEZ R26, utlindex /* if tlb entry found, rewrite it */ 566 EHB /* delay slot */ 567 TLBWR /* else write random tlb entry */ 568 ERET 569utlindex: 570 TLBWI /* write indexed tlb entry */ 571 ERET 572 573/* 574 * will be copied into low memory vectors; must fit in 32 words 575 * and avoid relative branches. 576 */ 577TEXT vector100(SB), $-4 /* cache trap */ 578TEXT vector180(SB), $-4 /* most exceptions */ 579stlbm: /* not in the stlb either; make trap.c figure it out */ 580 MOVW $exception(SB), R26 581 JMP (R26) 582 NOP 583 584TEXT stlbhash(SB), $-4 585 STLBHASH(R1, R2, R3) 586 RETURN 587 588/* 589 * exceptions other than tlb miss come here directly. 590 */ 591TEXT exception(SB), $-4 592 MOVW M(STATUS), R26 593 AND $KUSER, R26, R27 594 BEQ R27, waskernel 595 MOVW SP, R27 /* delay slot */ 596 597wasuser: 598 CONST (MACHADDR, SP) /* m-> */ 599 MOVW 8(SP), SP /* m->proc */ 600 MOVW 8(SP), SP /* m->proc->kstack */ 601 MOVW M(STATUS), R26 /* redundant load */ 602 ADDU $(KSTACK-UREGSIZE), SP 603 MOVW R31, Ureg_r31(SP) 604 605 JAL savereg1(SB) 606 NOP 607 608 MOVW R30, Ureg_r30(SP) 609 MOVW R(MACH), Ureg_r25(SP) 610 MIPS24KNOP 611 MOVW R(USER), Ureg_r24(SP) 612 613 MOVW $setR30(SB), R30 614 CONST (MACHADDR, R(MACH)) /* R(MACH) = m-> */ 615 MOVW 8(R(MACH)), R(USER) /* up = m->proc */ 616 617 AND $(EXCMASK<<2), R26, R1 618 SUBU $(CSYS<<2), R1 619 BNE R1, notsys 620 NOP 621 622 /* the carrera does this: */ 623// ADDU $8, SP, R1 /* first arg for syscall */ 624 625 MOVW SP, R1 /* first arg for syscall */ 626 JAL syscall(SB) /* to C */ 627 SUBU $Notuoffset, SP /* delay slot */ 628sysrestore: 629 JAL restreg1(SB) 630 ADDU $Notuoffset, SP /* delay slot */ 631 632 MOVW Ureg_r31(SP), R31 633 MOVW Ureg_status(SP), R26 634 MOVW Ureg_r30(SP), R30 635 MOVW R26, M(STATUS) 636 EHB 637 MOVW Ureg_pc(SP), R26 /* old pc */ 638erettor26: 639 MOVW Ureg_sp(SP), SP 640 MOVW R26, M(EPC) 641 ERET 642 643notsys: 644 JAL savereg2(SB) 645 NOP 646 647 /* the carrera does this: */ 648// ADDU $8, SP, R1 /* first arg for trap */ 649 650 MOVW SP, R1 /* first arg for trap */ 651 JAL trap(SB) /* to C for user trap */ 652 SUBU $Notuoffset, SP /* delay slot */ 653 654 ADDU $Notuoffset, SP 655 656restore: 657 JAL restreg1(SB) 658 NOP 659 JAL restreg2(SB) /* restores R28, among others */ 660 NOP 661 662 MOVW Ureg_r30(SP), R30 663 MOVW Ureg_r31(SP), R31 664 MOVW Ureg_r25(SP), R(MACH) 665 MOVW Ureg_r24(SP), R(USER) 666 JMP erettor26 667 NOP 668 669waskernel: 670 SUBU $UREGSIZE, SP 671 OR $7, SP /* conservative rounding */ 672 XOR $7, SP 673 MOVW R31, Ureg_r31(SP) 674 675 JAL savereg1(SB) 676 NOP 677 JAL savereg2(SB) 678 NOP 679 680 /* the carrera does this: */ 681// ADDU $8, SP, R1 /* first arg for trap */ 682 683 MOVW SP, R1 /* first arg for trap */ 684 JAL trap(SB) /* to C for kernel trap */ 685 SUBU $Notuoffset, SP /* delay slot */ 686 687 ADDU $Notuoffset, SP 688 689 JAL restreg1(SB) 690 NOP 691 692 /* 693 * if about to return to `wait', interrupt arrived just before 694 * executing wait, so move saved pc past it. 695 */ 696 MOVW Ureg_pc(SP), R26 697 MOVW R26, R31 698 MOVW $wait(SB), R1 699 SUBU R1, R31 700 BNE R31, notwait 701 NOP 702 ADD $BY2WD, R26 /* advance saved pc */ 703 MOVW R26, Ureg_pc(SP) 704notwait: 705 JAL restreg2(SB) /* restores R28, among others */ 706 NOP 707 708 MOVW Ureg_r31(SP), R31 709 JMP erettor26 710 NOP 711 712TEXT forkret(SB), $0 713 JMP sysrestore 714 MOVW R0, R1 /* delay slot; child returns 0 */ 715 716/* 717 * save mandatory registers. 718 * called with old M(STATUS) in R26. 719 * called with old SP in R27 720 * returns with M(CAUSE) in R26 721 */ 722TEXT savereg1(SB), $-4 723 MOVW R1, Ureg_r1(SP) 724 725 MOVW $(~KMODEMASK),R1 /* don't use R28, it's unsaved so far */ 726 AND R26, R1 727 MOVW R1, M(STATUS) 728 EHB 729 730 MOVW R26, Ureg_status(SP) /* status */ 731 MOVW R27, Ureg_sp(SP) /* user SP */ 732 733 MOVW M(EPC), R1 734 MOVW M(CAUSE), R26 735 736 MOVW R23, Ureg_r23(SP) 737 MOVW R22, Ureg_r22(SP) 738 MIPS24KNOP 739 MOVW R21, Ureg_r21(SP) 740 MOVW R20, Ureg_r20(SP) 741 MIPS24KNOP 742 MOVW R19, Ureg_r19(SP) 743 MOVW R1, Ureg_pc(SP) 744 RETURN 745 746/* 747 * all other registers. 748 * called with M(CAUSE) in R26 749 */ 750TEXT savereg2(SB), $-4 751 MOVW R2, Ureg_r2(SP) 752 753 MOVW M(BADVADDR), R2 754 MOVW R26, Ureg_cause(SP) 755 MOVW M(TLBVIRT), R1 756 MOVW R2, Ureg_badvaddr(SP) 757 MOVW R1, Ureg_tlbvirt(SP) 758 MOVW HI, R1 759 MOVW LO, R2 760 MOVW R1, Ureg_hi(SP) 761 MOVW R2, Ureg_lo(SP) 762 MIPS24KNOP 763 /* LINK,SB,SP missing */ 764 MOVW R28, Ureg_r28(SP) 765 /* R27, R26 not saved */ 766 /* R25, R24 missing */ 767 /* R23- R19 saved in save1 */ 768 MOVW R18, Ureg_r18(SP) 769 MIPS24KNOP 770 MOVW R17, Ureg_r17(SP) 771 MOVW R16, Ureg_r16(SP) 772 MIPS24KNOP 773 MOVW R15, Ureg_r15(SP) 774 MOVW R14, Ureg_r14(SP) 775 MIPS24KNOP 776 MOVW R13, Ureg_r13(SP) 777 MOVW R12, Ureg_r12(SP) 778 MIPS24KNOP 779 MOVW R11, Ureg_r11(SP) 780 MOVW R10, Ureg_r10(SP) 781 MIPS24KNOP 782 MOVW R9, Ureg_r9(SP) 783 MOVW R8, Ureg_r8(SP) 784 MIPS24KNOP 785 MOVW R7, Ureg_r7(SP) 786 MOVW R6, Ureg_r6(SP) 787 MIPS24KNOP 788 MOVW R5, Ureg_r5(SP) 789 MOVW R4, Ureg_r4(SP) 790 MIPS24KNOP 791 MOVW R3, Ureg_r3(SP) 792 RETURN 793 794TEXT restreg1(SB), $-4 795 MOVW Ureg_r23(SP), R23 796 MOVW Ureg_r22(SP), R22 797 MOVW Ureg_r21(SP), R21 798 MOVW Ureg_r20(SP), R20 799 MOVW Ureg_r19(SP), R19 800 RETURN 801 802TEXT restreg2(SB), $-4 803 /* LINK,SB,SP missing */ 804 MOVW Ureg_r28(SP), R28 805 /* R27, R26 not saved */ 806 /* R25, R24 missing */ 807 /* R19- R23 restored in rest1 */ 808 MOVW Ureg_r18(SP), R18 809 MOVW Ureg_r17(SP), R17 810 MOVW Ureg_r16(SP), R16 811 MOVW Ureg_r15(SP), R15 812 MOVW Ureg_r14(SP), R14 813 MOVW Ureg_r13(SP), R13 814 MOVW Ureg_r12(SP), R12 815 MOVW Ureg_r11(SP), R11 816 MOVW Ureg_r10(SP), R10 817 MOVW Ureg_r9(SP), R9 818 MOVW Ureg_r8(SP), R8 819 MOVW Ureg_r7(SP), R7 820 MOVW Ureg_r6(SP), R6 821 MOVW Ureg_r5(SP), R5 822 MOVW Ureg_r4(SP), R4 823 MOVW Ureg_r3(SP), R3 824 MOVW Ureg_lo(SP), R2 825 MOVW Ureg_hi(SP), R1 826 MOVW R2, LO 827 MOVW R1, HI 828 829 MOVW Ureg_status(SP), R1 830 MOVW Ureg_r2(SP), R2 831 MOVW R1, M(STATUS) /* could change interruptibility */ 832 EHB 833 MOVW Ureg_r1(SP), R1 /* BOTCH */ 834 MOVW Ureg_pc(SP), R26 835 RETURN 836 837/* 838 * degenerate floating-point stuff 839 */ 840 841TEXT clrfpintr(SB), $0 842 RETURN 843 844TEXT savefpregs(SB), $0 845 RETURN 846 847TEXT restfpregs(SB), $0 848 RETURN 849 850TEXT fcr31(SB), $0 /* fp csr */ 851 MOVW R0, R1 852 RETURN 853 854/* 855 * Emulate 68020 test and set: load linked / store conditional 856 */ 857 858TEXT tas(SB), $0 859 MOVW R1, R2 /* address of key */ 860tas1: 861 MOVW $1, R3 862 LL(2, 1) 863 NOP 864 SC(2, 3) 865 NOP 866 BEQ R3, tas1 867 NOP 868 RETURN 869 870/* used by the semaphore implementation */ 871TEXT cmpswap(SB), $0 872 MOVW R1, R2 /* address of key */ 873 MOVW old+4(FP), R3 /* old value */ 874 MOVW new+8(FP), R4 /* new value */ 875 LL(2, 1) /* R1 = (R2) */ 876 NOP 877 BNE R1, R3, fail 878 NOP 879 MOVW R4, R1 880 SC(2, 1) /* (R2) = R1 if (R2) hasn't changed; R1 = success */ 881 NOP 882 RETURN 883fail: 884 MOVW R0, R1 885 RETURN 886 887/* 888 * cache manipulation 889 */ 890 891/* 892 * we avoided using R4, R5, R6, and R7 so gotopc can call us without saving 893 * them, but gotopc is now gone. 894 */ 895TEXT icflush(SB), $-4 /* icflush(virtaddr, count) */ 896 MOVW 4(FP), R9 897 DI(10) /* intrs off, old status -> R10 */ 898 UBARRIERS(7, R7, ichb); /* return to kseg1 (uncached) */ 899 ADDU R1, R9 /* R9 = last address */ 900 MOVW $(~(CACHELINESZ-1)), R8 901 AND R1, R8 /* R8 = first address, rounded down */ 902 ADDU $(CACHELINESZ-1), R9 903 AND $(~(CACHELINESZ-1)), R9 /* round last address up */ 904 SUBU R8, R9 /* R9 = revised count */ 905icflush1: 906// CACHE PD+HWB, (R8) /* flush D to ram */ 907 CACHE PI+HINV, (R8) /* invalidate in I */ 908 SUBU $CACHELINESZ, R9 909 BGTZ R9, icflush1 910 ADDU $CACHELINESZ, R8 /* delay slot */ 911 912 BARRIERS(7, R7, ic2hb); /* return to kseg0 (cached) */ 913 MOVW R10, M(STATUS) 914 JRHB(31) /* return and clear all hazards */ 915 916TEXT dcflush(SB), $-4 /* dcflush(virtaddr, count) */ 917 MOVW 4(FP), R9 918 DI(10) /* intrs off, old status -> R10 */ 919 SYNC 920 EHB 921 ADDU R1, R9 /* R9 = last address */ 922 MOVW $(~(CACHELINESZ-1)), R8 923 AND R1, R8 /* R8 = first address, rounded down */ 924 ADDU $(CACHELINESZ-1), R9 925 AND $(~(CACHELINESZ-1)), R9 /* round last address up */ 926 SUBU R8, R9 /* R9 = revised count */ 927dcflush1: 928// CACHE PI+HINV, (R8) /* invalidate in I */ 929 CACHE PD+HWBI, (R8) /* flush & invalidate in D */ 930 SUBU $CACHELINESZ, R9 931 BGTZ R9, dcflush1 932 ADDU $CACHELINESZ, R8 /* delay slot */ 933 SYNC 934 EHB 935 MOVW R10, M(STATUS) 936 JRHB(31) /* return and clear all hazards */ 937 938/* the i and d caches may be different sizes, so clean them separately */ 939TEXT cleancache(SB), $-4 940 DI(10) /* intrs off, old status -> R10 */ 941 942 UBARRIERS(7, R7, cchb); /* return to kseg1 (uncached) */ 943 MOVW R0, R1 /* index, not address */ 944 MOVW $ICACHESIZE, R9 945iccache: 946 CACHE PI+IWBI, (R1) /* flush & invalidate I by index */ 947 SUBU $CACHELINESZ, R9 948 BGTZ R9, iccache 949 ADDU $CACHELINESZ, R1 /* delay slot */ 950 951 BARRIERS(7, R7, cc2hb); /* return to kseg0 (cached) */ 952 953 MOVW R0, R1 /* index, not address */ 954 MOVW $DCACHESIZE, R9 955dccache: 956 CACHE PD+IWBI, (R1) /* flush & invalidate D by index */ 957 SUBU $CACHELINESZ, R9 958 BGTZ R9, dccache 959 ADDU $CACHELINESZ, R1 /* delay slot */ 960 961 SYNC 962 MOVW R10, M(STATUS) 963 JRHB(31) /* return and clear all hazards */ 964 965/* 966 * access to CP0 registers 967 */ 968 969TEXT prid(SB), $0 970 MOVW M(PRID), R1 971 RETURN 972 973TEXT rdcount(SB), $0 974 MOVW M(COUNT), R1 975 RETURN 976 977TEXT wrcount(SB), $0 978 MOVW R1, M(COUNT) 979 EHB 980 RETURN 981 982TEXT wrcompare(SB), $0 983 MOVW R1, M(COMPARE) 984 EHB 985 RETURN 986 987TEXT rdcompare(SB), $0 988 MOVW M(COMPARE), R1 989 RETURN 990 991TEXT getconfig(SB), $-4 992 MOVW M(CONFIG), R1 993 RETURN 994 995TEXT getconfig1(SB), $-4 996 MFC0(CONFIG, 1, 1) 997 RETURN 998 999TEXT getconfig2(SB), $-4 1000 MFC0(CONFIG, 2, 1) 1001 RETURN 1002 1003TEXT getconfig3(SB), $-4 1004 MFC0(CONFIG, 3, 1) 1005 RETURN 1006 1007TEXT getconfig4(SB), $-4 1008 MFC0(CONFIG, 4, 1) 1009 RETURN 1010 1011TEXT getconfig7(SB), $-4 1012 MFC0(CONFIG, 7, 1) 1013 RETURN 1014 1015TEXT gethwreg3(SB), $-4 1016 RDHWR(3, 1) 1017 RETURN 1018 1019TEXT getcause(SB), $-4 1020 MOVW M(CAUSE), R1 1021 RETURN 1022 1023TEXT C_fcr0(SB), $-4 /* fp implementation */ 1024 MOVW $0x500, R1 /* claim to be an r4k, thus have ll/sc */ 1025 RETURN 1026 1027TEXT getstatus(SB), $0 1028 MOVW M(STATUS), R1 1029 RETURN 1030 1031TEXT setstatus(SB), $0 1032 MOVW R1, M(STATUS) 1033 EHB 1034 RETURN 1035 1036TEXT setwatchhi0(SB), $0 1037 MOVW R1, M(WATCHHI) 1038 EHB 1039 RETURN 1040 1041/* 1042 * beware that the register takes a double-word address, so it's not 1043 * precise to the individual instruction. 1044 */ 1045TEXT setwatchlo0(SB), $0 1046 MOVW R1, M(WATCHLO) 1047 EHB 1048 RETURN 1049 1050TEXT setsp(SB), $-4 1051 MOVW R1, SP 1052 RETURN 1053 1054TEXT getintctl(SB), $-4 1055 MFC0(STATUS, 1, 1) 1056 RETURN 1057 1058TEXT getsrsctl(SB), $-4 1059 MFC0(STATUS, 2, 1) 1060 RETURN 1061 1062TEXT getsrsmap(SB), $-4 1063 MFC0(STATUS, 3, 1) 1064 RETURN 1065 1066TEXT getperfctl0(SB), $-4 1067 MFC0(PERFCOUNT, 0, 1) 1068 RETURN 1069 1070TEXT getperfctl1(SB), $-4 1071 MFC0(PERFCOUNT, 2, 1) 1072 RETURN 1073 1074 GLOBL sanity(SB), $4 1075 DATA sanity(SB)/4, $SANITY 1076 1077 SCHED 1078