/* * mips 24k machine assist for routerboard rb450g */ #include "mem.h" #include "mips.s" #define SANITY 0x12345678 NOSCHED /* * Boot only processor */ TEXT start(SB), $-4 MOVW $setR30(SB), R30 PUTC('9', R1, R2) DI(0) MOVW sanity(SB), R1 CONST(SANITY, R2) SUBU R1, R2, R2 BNE R2, insane NOP MOVW R0, M(COMPARE) EHB /* don't enable any interrupts nor FP, but leave BEV on. */ MOVW $BEV,R1 MOVW R1, M(STATUS) UBARRIERS(7, R7, stshb) /* returns to kseg1 space */ MOVW R0, M(CAUSE) EHB /* silence the atheros watchdog */ MOVW $(KSEG1|0x18060008), R1 MOVW R0, (R1) /* set no action */ SYNC MOVW $PE, R1 MOVW R1, M(CACHEECC) /* aka ErrCtl */ EHB JAL cleancache(SB) NOP MOVW $TLBROFF, R1 MOVW R1, M(WIRED) MOVW R0, M(CONTEXT) EHB /* set KSEG0 cachability before trying LL/SC in lock code */ MOVW M(CONFIG), R1 AND $~CFG_K0, R1 /* make kseg0 cachable, enable write-through merging */ OR $((PTECACHABILITY>>3)|CFG_MM), R1 MOVW R1, M(CONFIG) BARRIERS(7, R7, cfghb) /* back to kseg0 space */ MOVW $setR30(SB), R30 /* again */ /* initialize Mach, including stack */ MOVW $MACHADDR, R(MACH) ADDU $(MACHSIZE-BY2V), R(MACH), SP MOVW R(MACH), R1 clrmach: MOVW R0, (R1) ADDU $BY2WD, R1 BNE R1, SP, clrmach NOP MOVW R0, 0(R(MACH)) /* m->machno = 0 */ MOVW R0, R(USER) /* up = nil */ /* zero bss, byte-by-byte */ MOVW $edata(SB), R1 MOVW $end(SB), R2 clrbss: MOVB R0, (R1) ADDU $1, R1 BNE R1, R2, clrbss NOP MOVW $0x16, R16 MOVW $0x17, R17 MOVW $0x18, R18 MOVW $0x19, R19 MOVW $0x20, R20 MOVW $0x21, R21 MOVW $0x22, R22 MOVW $0x23, R23 MOVW R0, HI MOVW R0, LO PUTC('\r', R1, R2) PUTC('\n', R1, R2) JAL main(SB) NOP CONST(ROM, R1) JMP (R1) /* back to the rom */ #define PUT(c) PUTC(c, R1, R2) #define DELAY(lab) \ CONST(34000000, R3); \ lab: SUBU $1, R3; \ BNE R3, lab; \ NOP insane: /* * data segment is misaligned; kernel needs vl -R4096 or -R16384, * as appropriate, for reboot. */ PUT('?'); PUT('d'); PUT('a'); PUT('t'); PUT('a'); PUT(' '); DELAY(dl1) PUT('s'); PUT('e'); PUT('g'); PUT('m'); PUT('e'); PUT('n'); DELAY(dl2) PUT('t'); PUT(' '); PUT('m'); PUT('i'); PUT('s'); PUT('a'); DELAY(dl3) PUT('l'); PUT('i'); PUT('g'); PUT('n'); PUT('e'); PUT('d'); DELAY(dl4) PUT('\r'); PUT('\n'); DELAY(dl5) CONST(ROM, R1) JMP (R1) /* back to the rom */ NOP /* target for JALRHB in BARRIERS */ TEXT ret(SB), $-4 JMP (R22) NOP /* print R1 in hex; clobbers R3—8 */ TEXT printhex(SB), $-4 MOVW $32, R5 MOVW $9, R7 prtop: SUB $4, R5 MOVW R1, R6 SRL R5, R6 AND $0xf, R6 SGTU R6, R7, R8 BEQ R8, prdec /* branch if R6 <= 9 */ NOP ADD $('a'-10), R6 JMP prchar NOP prdec: ADD $'0', R6 prchar: PUTC(R6, R3, R4) BNE R5, prtop NOP RETURN /* * Take first processor into user mode * - argument is stack pointer to user */ TEXT touser(SB), $-4 MOVW R1, SP MOVW $(UTZERO+32), R2 /* header appears in text */ MOVW R2, M(EPC) EHB MOVW M(STATUS), R4 AND $(~KMODEMASK), R4 OR $(KUSER|IE|EXL), R4 /* switch to user mode, intrs on, exc */ MOVW R4, M(STATUS) /* " */ ERET /* clears EXL */ /* * manipulate interrupts */ /* enable an interrupt; bit is in R1 */ TEXT intron(SB), $0 MOVW M(STATUS), R2 OR R1, R2 MOVW R2, M(STATUS) EHB RETURN /* disable an interrupt; bit is in R1 */ TEXT introff(SB), $0 MOVW M(STATUS), R2 XOR $-1, R1 AND R1, R2 MOVW R2, M(STATUS) EHB RETURN /* on our 24k, wait instructions are not interruptible, alas. */ TEXT idle(SB), $-4 EI(1) /* old M(STATUS) into R1 */ EHB /* fall through */ TEXT wait(SB), $-4 WAIT NOP MOVW R1, M(STATUS) /* interrupts restored */ EHB RETURN TEXT splhi(SB), $0 EHB MOVW R31, 12(R(MACH)) /* save PC in m->splpc */ DI(1) /* old M(STATUS) into R1 */ EHB RETURN TEXT splx(SB), $0 EHB MOVW R31, 12(R(MACH)) /* save PC in m->splpc */ MOVW M(STATUS), R2 AND $IE, R1 AND $~IE, R2 OR R2, R1 MOVW R1, M(STATUS) EHB RETURN TEXT spllo(SB), $0 EHB EI(1) /* old M(STATUS) into R1 */ EHB RETURN TEXT spldone(SB), $0 RETURN TEXT islo(SB), $0 MOVW M(STATUS), R1 AND $IE, R1 RETURN TEXT coherence(SB), $-4 BARRIERS(7, R7, cohhb) SYNC EHB RETURN /* * process switching */ TEXT setlabel(SB), $-4 MOVW R29, 0(R1) MOVW R31, 4(R1) MOVW R0, R1 RETURN TEXT gotolabel(SB), $-4 MOVW 0(R1), R29 MOVW 4(R1), R31 MOVW $1, R1 RETURN /* * the tlb routines need to be called at splhi. */ TEXT puttlb(SB), $0 /* puttlb(virt, phys0, phys1) */ EHB MOVW R1, M(TLBVIRT) EHB MOVW 4(FP), R2 /* phys0 */ MOVW 8(FP), R3 /* phys1 */ MOVW R2, M(TLBPHYS0) EHB MOVW $PGSZ, R1 MOVW R3, M(TLBPHYS1) EHB MOVW R1, M(PAGEMASK) OR R2, R3, R4 /* MTC0 delay slot */ AND $PTEVALID, R4 /* MTC0 delay slot */ EHB TLBP /* tlb probe */ EHB MOVW M(INDEX), R1 BGEZ R1, index /* if tlb entry found, use it */ NOP BEQ R4, dont /* not valid? cf. kunmap */ NOP MOVW M(RANDOM), R1 /* write random tlb entry */ MOVW R1, M(INDEX) index: EHB TLBWI /* write indexed tlb entry */ JRHB(31) /* return and clear all hazards */ dont: RETURN TEXT getwired(SB),$0 MOVW M(WIRED), R1 RETURN TEXT setwired(SB),$0 MOVW R1, M(WIRED) EHB RETURN TEXT getrandom(SB),$0 MOVW M(RANDOM), R1 RETURN TEXT getpagemask(SB),$0 MOVW M(PAGEMASK), R1 RETURN TEXT setpagemask(SB),$0 EHB MOVW R1, M(PAGEMASK) EHB MOVW R0, R1 /* prevent accidents */ RETURN TEXT puttlbx(SB), $0 /* puttlbx(index, virt, phys0, phys1, pagemask) */ MOVW 4(FP), R2 MOVW 8(FP), R3 MOVW 12(FP), R4 MOVW 16(FP), R5 EHB MOVW R2, M(TLBVIRT) EHB MOVW R3, M(TLBPHYS0) MOVW R4, M(TLBPHYS1) MOVW R5, M(PAGEMASK) EHB MOVW R1, M(INDEX) EHB TLBWI /* write indexed tlb entry */ JRHB(31) /* return and clear all hazards */ TEXT tlbvirt(SB), $0 EHB MOVW M(TLBVIRT), R1 EHB RETURN TEXT gettlbx(SB), $0 /* gettlbx(index, &entry) */ MOVW 4(FP), R5 MOVW M(TLBVIRT), R10 /* save our asid */ EHB MOVW R1, M(INDEX) EHB TLBR /* read indexed tlb entry */ EHB MOVW M(TLBVIRT), R2 MOVW M(TLBPHYS0), R3 MOVW M(TLBPHYS1), R4 MOVW R2, 0(R5) MOVW R3, 4(R5) MIPS24KNOP MOVW R4, 8(R5) EHB MOVW R10, M(TLBVIRT) /* restore our asid */ EHB RETURN TEXT gettlbp(SB), $0 /* gettlbp(tlbvirt, &entry) */ MOVW 4(FP), R5 MOVW M(TLBVIRT), R10 /* save our asid */ EHB MOVW R1, M(TLBVIRT) EHB TLBP /* probe tlb */ EHB MOVW M(INDEX), R1 BLTZ R1, gettlbp1 /* if no tlb entry found, return */ NOP EHB TLBR /* read indexed tlb entry */ EHB MOVW M(TLBVIRT), R2 MOVW M(TLBPHYS0), R3 MOVW M(TLBPHYS1), R4 MOVW M(PAGEMASK), R6 MOVW R2, 0(R5) MOVW R3, 4(R5) MIPS24KNOP MOVW R4, 8(R5) MOVW R6, 12(R5) gettlbp1: EHB MOVW R10, M(TLBVIRT) /* restore our asid */ EHB RETURN TEXT gettlbvirt(SB), $0 /* gettlbvirt(index) */ MOVW M(TLBVIRT), R10 /* save our asid */ EHB MOVW R1, M(INDEX) EHB TLBR /* read indexed tlb entry */ EHB MOVW M(TLBVIRT), R1 EHB MOVW R10, M(TLBVIRT) /* restore our asid */ EHB RETURN /* * exceptions. * mips promises that there will be no current hazards upon entry * to exception handlers. */ TEXT vector0(SB), $-4 MOVW $utlbmiss(SB), R26 JMP (R26) NOP /* * compute stlb hash index. * must match index calculation in mmu.c/putstlb() * * M(TLBVIRT) [page & asid] in arg, result in arg. * stir in swizzled asid; we get best results with asid in both high & low bits. * * page = tlbvirt >> (PGSHIFT+1); // ignoring even/odd bit * R27 = ((tlbvirt<<(STLBLOG-8) ^ (uchar)tlbvirt ^ page ^ * ((page & (MASK(HIPFNBITS) << STLBLOG)) >> HIPFNBITS)) & * (STLBSIZE-1)) * 12; */ #define STLBHASH(arg, tmp, tmp2) \ MOVW arg, tmp2; \ SRL $(PGSHIFT+1), arg; /* move low page # bits to low bits */ \ CONST ((MASK(HIPFNBITS) << STLBLOG), tmp); \ AND arg, tmp; /* extract high page # bits */ \ SRL $HIPFNBITS, tmp; /* position them */ \ XOR tmp, arg; /* include them */ \ MOVW tmp2, tmp; /* asid in low byte */ \ SLL $(STLBLOG-8), tmp; /* move asid to high bits */ \ XOR tmp, arg; /* include asid in high bits too */ \ AND $0xff, tmp2, tmp; /* asid in low byte */ \ XOR tmp, arg; /* include asid in low bits */ \ CONST (STLBSIZE-1, tmp); \ AND tmp, arg /* chop to fit */ TEXT utlbmiss(SB), $-4 /* * don't use R28 by using constants that span both word halves, * it's unsaved so far. avoid R24 (up in kernel) and R25 (m in kernel). */ /* update statistics */ CONST (MACHADDR, R26) /* R26 = m-> */ MOVW 16(R26), R27 ADDU $1, R27 MOVW R27, 16(R26) /* m->tlbfault++ */ MOVW R23, M(DESAVE) /* save R23 */ #ifdef KUTLBSTATS MOVW M(STATUS), R23 AND $KUSER, R23 BEQ R23, kmiss MOVW 24(R26), R27 ADDU $1, R27 MOVW R27, 24(R26) /* m->utlbfault++ */ JMP either kmiss: MOVW 20(R26), R27 ADDU $1, R27 MOVW R27, 20(R26) /* m->ktlbfault++ */ either: #endif /* compute stlb index */ EHB MOVW M(TLBVIRT), R27 /* asid in low byte */ STLBHASH(R27, R26, R23) MOVW M(DESAVE), R23 /* restore R23 */ /* scale to a byte index (multiply by 12) */ SLL $1, R27, R26 /* × 2 */ ADDU R26, R27 /* × 3 */ SLL $2, R27 /* × 12 */ CONST (MACHADDR, R26) /* R26 = m-> */ MOVW 4(R26), R26 /* R26 = m->stb */ ADDU R26, R27 /* R27 = &m->stb[hash] */ MOVW M(BADVADDR), R26 AND $BY2PG, R26 BNE R26, utlbodd /* odd page? */ NOP utlbeven: MOVW 4(R27), R26 /* R26 = m->stb[hash].phys0 */ BEQ R26, stlbm /* nothing cached? do it the hard way */ NOP MOVW R26, M(TLBPHYS0) EHB MOVW 8(R27), R26 /* R26 = m->stb[hash].phys1 */ JMP utlbcom MOVW R26, M(TLBPHYS1) /* branch delay slot */ utlbodd: MOVW 8(R27), R26 /* R26 = m->stb[hash].phys1 */ BEQ R26, stlbm /* nothing cached? do it the hard way */ NOP MOVW R26, M(TLBPHYS1) EHB MOVW 4(R27), R26 /* R26 = m->stb[hash].phys0 */ MOVW R26, M(TLBPHYS0) utlbcom: EHB /* MTC0/MFC0 hazard */ MOVW M(TLBVIRT), R26 MOVW (R27), R27 /* R27 = m->stb[hash].virt */ BEQ R27, stlbm /* nothing cached? do it the hard way */ NOP /* is the stlb entry for the right virtual address? */ BNE R26, R27, stlbm /* M(TLBVIRT) != m->stb[hash].virt? */ NOP /* if an entry exists, overwrite it, else write a random one */ CONST (PGSZ, R27) MOVW R27, M(PAGEMASK) /* select page size */ EHB TLBP /* probe tlb */ EHB MOVW M(INDEX), R26 BGEZ R26, utlindex /* if tlb entry found, rewrite it */ EHB /* delay slot */ TLBWR /* else write random tlb entry */ ERET utlindex: TLBWI /* write indexed tlb entry */ ERET /* not in the stlb either; make trap.c figure it out */ stlbm: MOVW $exception(SB), R26 JMP (R26) NOP TEXT stlbhash(SB), $-4 STLBHASH(R1, R2, R3) RETURN TEXT vector100(SB), $-4 MOVW $exception(SB), R26 JMP (R26) NOP TEXT vector180(SB), $-4 MOVW $exception(SB), R26 JMP (R26) NOP TEXT exception(SB), $-4 MOVW M(STATUS), R26 AND $KUSER, R26, R27 BEQ R27, waskernel MOVW SP, R27 /* delay slot */ wasuser: CONST (MACHADDR, SP) /* m-> */ MOVW 8(SP), SP /* m->proc */ MOVW 8(SP), SP /* m->proc->kstack */ MOVW M(STATUS), R26 /* redundant load */ ADDU $(KSTACK-UREGSIZE), SP MOVW R31, Ureg_r31(SP) JAL savereg1(SB) NOP MOVW R30, Ureg_r30(SP) MOVW R(MACH), Ureg_r25(SP) MIPS24KNOP MOVW R(USER), Ureg_r24(SP) MOVW $setR30(SB), R30 CONST (MACHADDR, R(MACH)) /* R(MACH) = m-> */ MOVW 8(R(MACH)), R(USER) /* up = m->proc */ AND $(EXCMASK<<2), R26, R1 SUBU $(CSYS<<2), R1 BNE R1, notsys NOP /* the carrera does this: */ // ADDU $8, SP, R1 /* first arg for syscall */ MOVW SP, R1 /* first arg for syscall */ JAL syscall(SB) SUBU $Notuoffset, SP /* delay slot */ sysrestore: JAL restreg1(SB) ADDU $Notuoffset, SP /* delay slot */ MOVW Ureg_r31(SP), R31 MOVW Ureg_status(SP), R26 MOVW Ureg_r30(SP), R30 MOVW R26, M(STATUS) EHB MOVW Ureg_pc(SP), R26 /* old pc */ MOVW Ureg_sp(SP), SP MOVW R26, M(EPC) ERET notsys: JAL savereg2(SB) NOP /* the carrera does this: */ // ADDU $8, SP, R1 /* first arg for trap */ MOVW SP, R1 /* first arg for trap */ JAL trap(SB) SUBU $Notuoffset, SP /* delay slot */ ADDU $Notuoffset, SP restore: JAL restreg1(SB) NOP JAL restreg2(SB) /* restores R28, among others */ NOP MOVW Ureg_r30(SP), R30 MOVW Ureg_r31(SP), R31 MOVW Ureg_r25(SP), R(MACH) MOVW Ureg_r24(SP), R(USER) MOVW Ureg_sp(SP), SP MOVW R26, M(EPC) ERET waskernel: SUBU $UREGSIZE, SP OR $7, SP /* conservative rounding */ XOR $7, SP MOVW R31, Ureg_r31(SP) JAL savereg1(SB) NOP JAL savereg2(SB) NOP /* the carrera does this: */ // ADDU $8, SP, R1 /* first arg for trap */ MOVW SP, R1 /* first arg for trap */ JAL trap(SB) SUBU $Notuoffset, SP /* delay slot */ ADDU $Notuoffset, SP JAL restreg1(SB) NOP /* * if about to return to `wait', interrupt arrived just before * executing wait, so move saved pc past it. */ MOVW Ureg_pc(SP), R26 MOVW R26, R31 MOVW $wait(SB), R1 SUBU R1, R31 BNE R31, notwait NOP ADD $BY2WD, R26 /* advance saved pc */ MOVW R26, Ureg_pc(SP) notwait: JAL restreg2(SB) /* restores R28, among others */ NOP MOVW Ureg_r31(SP), R31 MOVW Ureg_sp(SP), SP MOVW R26, M(EPC) ERET TEXT forkret(SB), $0 JMP sysrestore MOVW R0, R1 /* delay slot; child returns 0 */ /* * save mandatory registers. * called with old M(STATUS) in R26. * called with old SP in R27 * returns with M(CAUSE) in R26 */ TEXT savereg1(SB), $-4 MOVW R1, Ureg_r1(SP) MOVW $(~KMODEMASK),R1 /* don't use R28, it's unsaved so far */ AND R26, R1 MOVW R1, M(STATUS) EHB MOVW R26, Ureg_status(SP) /* status */ MOVW R27, Ureg_sp(SP) /* user SP */ MOVW M(EPC), R1 MOVW M(CAUSE), R26 MOVW R23, Ureg_r23(SP) MOVW R22, Ureg_r22(SP) MIPS24KNOP MOVW R21, Ureg_r21(SP) MOVW R20, Ureg_r20(SP) MIPS24KNOP MOVW R19, Ureg_r19(SP) MOVW R1, Ureg_pc(SP) RETURN /* * all other registers. * called with M(CAUSE) in R26 */ TEXT savereg2(SB), $-4 MOVW R2, Ureg_r2(SP) MOVW M(BADVADDR), R2 MOVW R26, Ureg_cause(SP) MOVW M(TLBVIRT), R1 MOVW R2, Ureg_badvaddr(SP) MOVW R1, Ureg_tlbvirt(SP) MOVW HI, R1 MOVW LO, R2 MOVW R1, Ureg_hi(SP) MOVW R2, Ureg_lo(SP) MIPS24KNOP /* LINK,SB,SP missing */ MOVW R28, Ureg_r28(SP) /* R27, R26 not saved */ /* R25, R24 missing */ /* R23- R19 saved in save1 */ MOVW R18, Ureg_r18(SP) MIPS24KNOP MOVW R17, Ureg_r17(SP) MOVW R16, Ureg_r16(SP) MIPS24KNOP MOVW R15, Ureg_r15(SP) MOVW R14, Ureg_r14(SP) MIPS24KNOP MOVW R13, Ureg_r13(SP) MOVW R12, Ureg_r12(SP) MIPS24KNOP MOVW R11, Ureg_r11(SP) MOVW R10, Ureg_r10(SP) MIPS24KNOP MOVW R9, Ureg_r9(SP) MOVW R8, Ureg_r8(SP) MIPS24KNOP MOVW R7, Ureg_r7(SP) MOVW R6, Ureg_r6(SP) MIPS24KNOP MOVW R5, Ureg_r5(SP) MOVW R4, Ureg_r4(SP) MIPS24KNOP MOVW R3, Ureg_r3(SP) RETURN TEXT restreg1(SB), $-4 MOVW Ureg_r23(SP), R23 MOVW Ureg_r22(SP), R22 MOVW Ureg_r21(SP), R21 MOVW Ureg_r20(SP), R20 MOVW Ureg_r19(SP), R19 RETURN TEXT restreg2(SB), $-4 /* LINK,SB,SP missing */ MOVW Ureg_r28(SP), R28 /* R27, R26 not saved */ /* R25, R24 missing */ /* R19- R23 restored in rest1 */ MOVW Ureg_r18(SP), R18 MOVW Ureg_r17(SP), R17 MOVW Ureg_r16(SP), R16 MOVW Ureg_r15(SP), R15 MOVW Ureg_r14(SP), R14 MOVW Ureg_r13(SP), R13 MOVW Ureg_r12(SP), R12 MOVW Ureg_r11(SP), R11 MOVW Ureg_r10(SP), R10 MOVW Ureg_r9(SP), R9 MOVW Ureg_r8(SP), R8 MOVW Ureg_r7(SP), R7 MOVW Ureg_r6(SP), R6 MOVW Ureg_r5(SP), R5 MOVW Ureg_r4(SP), R4 MOVW Ureg_r3(SP), R3 MOVW Ureg_lo(SP), R2 MOVW Ureg_hi(SP), R1 MOVW R2, LO MOVW R1, HI MOVW Ureg_status(SP), R1 MOVW Ureg_r2(SP), R2 MOVW R1, M(STATUS) /* could change interruptibility */ EHB MOVW Ureg_r1(SP), R1 /* BOTCH */ MOVW Ureg_pc(SP), R26 RETURN #ifdef OLD_MIPS_EXAMPLE /* this appears to be a dreg from the distant past */ TEXT rfnote(SB), $0 MOVW R1, R26 /* 1st arg is &uregpointer */ JMP restore SUBU $(BY2WD), R26, SP /* delay slot: pc hole */ #endif /* * degenerate floating-point stuff */ TEXT clrfpintr(SB), $0 RETURN TEXT savefpregs(SB), $0 RETURN TEXT restfpregs(SB), $0 RETURN TEXT fcr31(SB), $0 /* fp csr */ MOVW R0, R1 RETURN /* * Emulate 68020 test and set: load linked / store conditional */ TEXT tas(SB), $0 MOVW R1, R2 /* address of key */ tas1: MOVW $1, R3 LL(2, 1) NOP SC(2, 3) NOP BEQ R3, tas1 NOP RETURN TEXT _xinc(SB), $0 MOVW R1, R2 /* address of counter */ loop: MOVW $1, R3 LL(2, 1) NOP ADDU R1, R3 MOVW R3, R1 /* return new value */ SC(2, 3) NOP BEQ R3, loop NOP RETURN TEXT _xdec(SB), $0 SYNC MOVW R1, R2 /* address of counter */ loop1: MOVW $-1, R3 LL(2, 1) NOP ADDU R1, R3 MOVW R3, R1 /* return new value */ SC(2, 3) NOP BEQ R3, loop1 NOP RETURN /* used by the semaphore implementation */ TEXT cmpswap(SB), $0 MOVW R1, R2 /* address of key */ MOVW old+4(FP), R3 /* old value */ MOVW new+8(FP), R4 /* new value */ LL(2, 1) /* R1 = (R2) */ NOP BNE R1, R3, fail NOP MOVW R4, R1 SC(2, 1) /* (R2) = R1 if (R2) hasn't changed; R1 = success */ NOP RETURN fail: MOVW R0, R1 RETURN /* * cache manipulation */ /* * we avoided using R4, R5, R6, and R7 so gotopc can call us without saving * them, but gotopc is now gone. */ TEXT icflush(SB), $-4 /* icflush(virtaddr, count) */ MOVW 4(FP), R9 DI(10) /* intrs off, old status -> R10 */ UBARRIERS(7, R7, ichb); /* return to kseg1 (uncached) */ ADDU R1, R9 /* R9 = last address */ MOVW $(~(CACHELINESZ-1)), R8 AND R1, R8 /* R8 = first address, rounded down */ ADDU $(CACHELINESZ-1), R9 AND $(~(CACHELINESZ-1)), R9 /* round last address up */ SUBU R8, R9 /* R9 = revised count */ icflush1: // CACHE PD+HWB, (R8) /* flush D to ram */ CACHE PI+HINV, (R8) /* invalidate in I */ SUBU $CACHELINESZ, R9 BGTZ R9, icflush1 ADDU $CACHELINESZ, R8 /* delay slot */ BARRIERS(7, R7, ic2hb); /* return to kseg0 (cached) */ MOVW R10, M(STATUS) JRHB(31) /* return and clear all hazards */ TEXT dcflush(SB), $-4 /* dcflush(virtaddr, count) */ MOVW 4(FP), R9 DI(10) /* intrs off, old status -> R10 */ SYNC EHB ADDU R1, R9 /* R9 = last address */ MOVW $(~(CACHELINESZ-1)), R8 AND R1, R8 /* R8 = first address, rounded down */ ADDU $(CACHELINESZ-1), R9 AND $(~(CACHELINESZ-1)), R9 /* round last address up */ SUBU R8, R9 /* R9 = revised count */ dcflush1: // CACHE PI+HINV, (R8) /* invalidate in I */ CACHE PD+HWBI, (R8) /* flush & invalidate in D */ SUBU $CACHELINESZ, R9 BGTZ R9, dcflush1 ADDU $CACHELINESZ, R8 /* delay slot */ SYNC EHB MOVW R10, M(STATUS) JRHB(31) /* return and clear all hazards */ /* the i and d caches may be different sizes, so clean them separately */ TEXT cleancache(SB), $-4 DI(10) /* intrs off, old status -> R10 */ UBARRIERS(7, R7, cchb); /* return to kseg1 (uncached) */ MOVW R0, R1 /* index, not address */ MOVW $ICACHESIZE, R9 iccache: CACHE PI+IWBI, (R1) /* flush & invalidate I by index */ SUBU $CACHELINESZ, R9 BGTZ R9, iccache ADDU $CACHELINESZ, R1 /* delay slot */ BARRIERS(7, R7, cc2hb); /* return to kseg0 (cached) */ MOVW R0, R1 /* index, not address */ MOVW $DCACHESIZE, R9 dccache: CACHE PD+IWBI, (R1) /* flush & invalidate D by index */ SUBU $CACHELINESZ, R9 BGTZ R9, dccache ADDU $CACHELINESZ, R1 /* delay slot */ SYNC MOVW R10, M(STATUS) JRHB(31) /* return and clear all hazards */ /* * access to CP0 registers */ TEXT prid(SB), $0 MOVW M(PRID), R1 RETURN TEXT rdcount(SB), $0 MOVW M(COUNT), R1 RETURN TEXT wrcount(SB), $0 MOVW R1, M(COUNT) EHB RETURN TEXT wrcompare(SB), $0 MOVW R1, M(COMPARE) EHB RETURN TEXT rdcompare(SB), $0 MOVW M(COMPARE), R1 RETURN TEXT getconfig(SB), $-4 MOVW M(CONFIG), R1 RETURN TEXT getconfig1(SB), $-4 MFC0(CONFIG, 1, 1) RETURN TEXT getconfig2(SB), $-4 MFC0(CONFIG, 2, 1) RETURN TEXT getconfig3(SB), $-4 MFC0(CONFIG, 3, 1) RETURN TEXT getconfig4(SB), $-4 MFC0(CONFIG, 4, 1) RETURN TEXT getconfig7(SB), $-4 MFC0(CONFIG, 7, 1) RETURN TEXT gethwreg3(SB), $-4 RDHWR(3, 1) RETURN TEXT getcause(SB), $-4 MOVW M(CAUSE), R1 RETURN TEXT C_fcr0(SB), $-4 /* fp implementation */ MOVW $0x500, R1 /* claim to be an r4k, thus have ll/sc */ RETURN TEXT getstatus(SB), $0 MOVW M(STATUS), R1 RETURN TEXT setstatus(SB), $0 MOVW R1, M(STATUS) EHB RETURN TEXT setwatchhi0(SB), $0 MOVW R1, M(WATCHHI) EHB RETURN /* * beware that the register takes a double-word address, so it's not * precise to the individual instruction. */ TEXT setwatchlo0(SB), $0 MOVW R1, M(WATCHLO) EHB RETURN TEXT setsp(SB), $-4 MOVW R1, SP RETURN TEXT getintctl(SB), $-4 MFC0(STATUS, 1, 1) RETURN TEXT getsrsctl(SB), $-4 MFC0(STATUS, 2, 1) RETURN TEXT getsrsmap(SB), $-4 MFC0(STATUS, 3, 1) RETURN TEXT getperfctl0(SB), $-4 MFC0(PERFCOUNT, 0, 1) RETURN TEXT getperfctl1(SB), $-4 MFC0(PERFCOUNT, 2, 1) RETURN GLOBL sanity(SB), $4 DATA sanity(SB)/4, $SANITY SCHED