plan9fox/sys/src/9/kw/l.s
2011-03-30 19:35:09 +03:00

775 lines
17 KiB
ArmAsm

/*
* sheevaplug machine assist
* arm926ej-s processor at 1.2GHz
*
* loader uses R11 as scratch.
* R9 and R10 are used for `extern register' variables.
*
* ARM v7 arch. ref. man. (I know, this is v5) §B1.3.3 that
* we don't need barriers around moves to CPSR. The ARM v6 manual
* seems to be silent on the subject.
*/
#include "arm.s"
/*
* MCR and MRC are counter-intuitively named.
* MCR coproc, opcode1, Rd, CRn, CRm[, opcode2] # arm -> coproc
* MRC coproc, opcode1, Rd, CRn, CRm[, opcode2] # coproc -> arm
*/
/*
* Entered here from Das U-Boot with MMU disabled.
* Until the MMU is enabled it is OK to call functions provided
* they are within ±32MiB relative and do not require any
* local variables or more than one argument (i.e. there is
* no stack).
*/
TEXT _start(SB), 1, $-4
MOVW $setR12(SB), R12 /* load the SB */
_main:
/* SVC mode, interrupts disabled */
MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1
MOVW R1, CPSR
BARRIERS
/*
* disable the MMU & caches,
* switch to system permission & 32-bit addresses.
*/
MOVW $(CpCsystem|CpCd32|CpCi32), R1
MCR CpSC, 0, R1, C(CpCONTROL), C(0)
ISB
/*
* disable the Sheevaplug's L2 cache, invalidate all caches
*/
/* flush caches. 926ejs manual says we have to do it iteratively. */
_dwbinv0:
MRC CpSC, 0, PC, C(CpCACHE), C(CpCACHEwbi), CpCACHEtest
BNE _dwbinv0
/* drain L1 write buffer, also drains L2 eviction buffer on sheeva */
BARRIERS
/* make the l2 cache pay attention */
MOVW $(PHYSIO+0x20100), R1 /* CPUCSREG */
MOVW (4*10)(R1), R2
ORR $(1<<3), R2 /* cpu->l2cfg |= L2exists */
MOVW R2, (4*10)(R1)
ISB
/* invalidate l2 cache */
MCR CpSC, CpL2, R0, C(CpTESTCFG), C(CpTCl2inv), CpTCl2all
ISB
/* disable l2 cache. do this while l1 caches are off */
MRC CpSC, CpL2, R1, C(CpTESTCFG), C(CpTCl2cfg), CpTCl2conf
/* disabling write allocation is probably for cortex-a8 errata 460075 */
/* l2 off, no wr alloc, no streaming */
BIC $(CpTCl2ena | CpTCl2wralloc | CpTCldcstream), R1
MCR CpSC, CpL2, R1, C(CpTESTCFG), C(CpTCl2cfg), CpTCl2conf
BARRIERS
/* flush caches. 926ejs manual says we have to do it iteratively. */
_dwbinv1:
MRC CpSC, 0, PC, C(CpCACHE), C(CpCACHEwbi), CpCACHEtest
BNE _dwbinv1
BARRIERS
WAVE('\r')
/* clear Mach */
MOVW $PADDR(MACHADDR), R4 /* address of Mach */
_machZ:
MOVW R0, (R4)
ADD $4, R4 /* bump PTE address */
CMP.S $PADDR(L1+L1X(0)), R4
BNE _machZ
/*
* set up the MMU page table
*/
/* clear all PTEs first, to provide a default */
WAVE('\n')
MOVW $PADDR(L1+L1X(0)), R4 /* address of PTE for 0 */
_ptenv0:
ZEROPTE()
CMP.S $PADDR(L1+16*KiB), R4
BNE _ptenv0
/* double map of PHYSDRAM, KZERO to PHYSDRAM for first few MBs */
MOVW $PTEDRAM, R2 /* PTE bits */
MOVW $PHYSDRAM, R3 /* pa */
MOVW $PADDR(L1+L1X(PHYSDRAM)), R4 /* address of PTE for PHYSDRAM */
MOVW $16, R5
_ptdbl:
FILLPTE()
SUB.S $1, R5
BNE _ptdbl
/*
* back up and fill in PTEs for memory at KZERO
* there is 1 bank of 512MB of SDRAM at PHYSDRAM
*/
MOVW $PTEDRAM, R2 /* PTE bits */
MOVW $PHYSDRAM, R3
MOVW $PADDR(L1+L1X(KZERO)), R4 /* start with PTE for KZERO */
MOVW $512, R5 /* inner loop count */
_ptekrw: /* set PTEs for 512MiB */
FILLPTE()
SUB.S $1, R5
BNE _ptekrw
/*
* back up and fill in PTE for MMIO
*/
MOVW $PTEIO, R2 /* PTE bits */
MOVW $PHYSIO, R3
MOVW $PADDR(L1+L1X(VIRTIO)), R4 /* start with PTE for VIRTIO */
FILLPTE()
/* mmu.c sets up the vectors later */
/*
* set up a temporary stack; avoid data & bss segments
*/
MOVW $(PHYSDRAM | (128*1024*1024)), R13
WAVE('P')
/* set the domain access control */
MOVW $Client, R0
BL dacput(SB)
/* set the translation table base */
MOVW $PADDR(L1), R0
BL ttbput(SB)
MOVW $0, R0
BL pidput(SB) /* paranoia */
/* the little dance to turn the MMU & caches on */
WAVE('l')
BL cacheuwbinv(SB)
BL mmuinvalidate(SB)
BL mmuenable(SB)
WAVE('a')
/* warp the PC into the virtual map */
MOVW $KZERO, R0
BL _r15warp(SB)
/*
* now running at KZERO+something!
*/
MOVW $setR12(SB), R12 /* reload the SB */
/*
* set up temporary stack again, in case we've just switched
* to a new register set.
*/
MOVW $(KZERO|(128*1024*1024)), R13
/* can now execute arbitrary C code */
BL cacheuwbinv(SB)
WAVE('n')
/* undo double map of 0, KZERO */
MOVW $PADDR(L1+L1X(0)), R4 /* address of PTE for 0 */
MOVW $0, R0
MOVW $16, R5
_ptudbl:
MOVW R0, (R4)
ADD $4, R4 /* bump PTE address */
ADD $MiB, R0 /* bump pa */
SUB.S $1, R5
BNE _ptudbl
BARRIERS
MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvd), CpTLBinvse
MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
BARRIERS
WAVE(' ')
/* pass Mach to main and set up the stack */
MOVW $(MACHADDR), R0 /* Mach */
MOVW R0, R13
ADD $(MACHSIZE), R13 /* stack pointer */
SUB $4, R13 /* space for link register */
BL main(SB) /* void main(Mach*) */
/* fall through */
/* not used */
TEXT _reset(SB), 1, $-4
/* turn the caches off */
MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R0
MOVW R0, CPSR
BARRIERS
BL cacheuwbinv(SB)
MRC CpSC, 0, R0, C(CpCONTROL), C(0)
BIC $(CpCwb|CpCicache|CpCdcache|CpCalign), R0
MCR CpSC, 0, R0, C(CpCONTROL), C(0)
BARRIERS
WAVE('R')
/* redo double map of 0, KZERO */
MOVW $(L1+L1X(0)), R4 /* address of PTE for 0 */
MOVW $PTEDRAM, R2 /* PTE bits */
MOVW $0, R3
MOVW $16, R5
_ptrdbl:
ORR R3, R2, R1 /* first identity-map 0 to 0, etc. */
MOVW R1, (R4)
ADD $4, R4 /* bump PTE address */
ADD $MiB, R3 /* bump pa */
SUB.S $1, R5
BNE _ptrdbl
BARRIERS
WAVE('e')
MOVW $0, R0
MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvd), CpTLBinv
MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
BARRIERS
/* back to 29- or 26-bit addressing, mainly for SB */
MRC CpSC, 0, R0, C(CpCONTROL), C(0)
BIC $(CpCd32|CpCi32), R0
MCR CpSC, 0, R0, C(CpCONTROL), C(0)
BARRIERS
/* turn the MMU off */
MOVW $PHYSDRAM, R0
BL _r15warp(SB)
BL mmuinvalidate(SB)
BL mmudisable(SB)
WAVE('s')
/* set new reset vector */
MOVW $0, R2
MOVW $0xe59ff018, R3 /* MOVW 0x18(R15), R15 */
MOVW R3, (R2)
WAVE('e')
MOVW $PHYSBOOTROM, R3
MOVW R3, 0x20(R2) /* where $0xe59ff018 jumps to */
BARRIERS
WAVE('t')
WAVE('\r')
WAVE('\n')
/* ...and jump to it */
MOVW R2, R15 /* software reboot */
_limbo: /* should not get here... */
B _limbo /* ... and can't get out */
BL _div(SB) /* hack to load _div, etc. */
TEXT _r15warp(SB), 1, $-4
BIC $KSEGM, R14
ORR R0, R14
BIC $KSEGM, R13
ORR R0, R13
RET
/* clobbers R1, R6 */
TEXT myputc(SB), 1, $-4
MOVW $PHYSCONS, R6
_busy:
MOVW 20(R6), R1
BIC.S $~(1<<5), R1 /* (x->lsr & LSRthre) == 0? */
BEQ _busy
MOVW R3, (R6) /* print */
ISB
RET
/*
* l1 caches
*/
TEXT l1cacheson(SB), 1, $-4
MOVW CPSR, R5
ORR $(PsrDirq|PsrDfiq), R5, R4
MOVW R4, CPSR /* splhi */
MRC CpSC, 0, R0, C(CpCONTROL), C(0)
ORR $(CpCdcache|CpCicache|CpCwb), R0
MCR CpSC, 0, R0, C(CpCONTROL), C(0)
BARRIERS
MOVW R5, CPSR /* splx */
RET
TEXT l1cachesoff(SB), 1, $-4
MOVM.DB.W [R14], (SP) /* save lr on stack */
MOVW CPSR, R5
ORR $(PsrDirq|PsrDfiq), R5, R4
MOVW R4, CPSR /* splhi */
BL cacheuwbinv(SB)
MRC CpSC, 0, R0, C(CpCONTROL), C(0)
BIC $(CpCdcache|CpCicache|CpCwb), R0
MCR CpSC, 0, R0, C(CpCONTROL), C(0)
BARRIERS
MOVW R5, CPSR /* splx */
MOVM.IA.W (SP), [R14] /* restore lr */
RET
/*
* cache* functions affect only the L1 caches, which are VIVT.
*/
TEXT cachedwb(SB), 1, $-4 /* D writeback */
MOVW CPSR, R3 /* splhi */
ORR $(PsrDirq), R3, R1
MOVW R1, CPSR
BARRIERS /* force outstanding stores to cache */
/* keep writing back dirty cache lines until no more exist */
_dwb:
MRC CpSC, 0, PC, C(CpCACHE), C(CpCACHEwb), CpCACHEtest
BNE _dwb
/* drain L1 write buffer, also drains L2 eviction buffer on sheeva */
BARRIERS
MOVW R3, CPSR /* splx */
RET
TEXT cachedwbse(SB), 1, $-4 /* D writeback SE */
MOVW R0, R2 /* first arg: address */
MOVW CPSR, R3 /* splhi */
ORR $(PsrDirq), R3, R1
MOVW R1, CPSR
BARRIERS /* force outstanding stores to cache */
MOVW 4(FP), R1 /* second arg: size */
// CMP.S $(4*1024), R1
// BGT _dwb
ADD R2, R1
BIC $(CACHELINESZ-1), R2
_dwbse:
MCR CpSC, 0, R2, C(CpCACHE), C(CpCACHEwb), CpCACHEse
ADD $CACHELINESZ, R2
CMP.S R2, R1
BGT _dwbse
/* drain L1 write buffer, also drains L2 eviction buffer on sheeva */
BARRIERS
MOVW R3, CPSR /* splx */
RET
TEXT cachedwbinv(SB), 1, $-4 /* D writeback+invalidate */
MOVW CPSR, R3 /* splhi */
ORR $(PsrDirq), R3, R1
MOVW R1, CPSR
BARRIERS /* force outstanding stores to cache */
/* keep writing back dirty cache lines until no more exist */
_dwbinv:
MRC CpSC, 0, PC, C(CpCACHE), C(CpCACHEwbi), CpCACHEtest
BNE _dwbinv
/* drain L1 write buffer, also drains L2 eviction buffer on sheeva */
BARRIERS
MOVW R3, CPSR /* splx */
RET
TEXT cachedwbinvse(SB), 1, $-4 /* D writeback+invalidate SE */
MOVW R0, R2 /* first arg: address */
MOVW CPSR, R3 /* splhi */
ORR $(PsrDirq), R3, R1
MOVW R1, CPSR
BARRIERS /* force outstanding stores to cache */
MOVW 4(FP), R1 /* second arg: size */
DSB
// CMP.S $(4*1024), R1
// BGT _dwbinv
ADD R2, R1
BIC $(CACHELINESZ-1), R2
_dwbinvse:
MCR CpSC, 0, R2, C(CpCACHE), C(CpCACHEwbi), CpCACHEse
ADD $CACHELINESZ, R2
CMP.S R2, R1
BGT _dwbinvse
/* drain L1 write buffer, also drains L2 eviction buffer on sheeva */
BARRIERS
MOVW R3, CPSR /* splx */
RET
TEXT cachedinvse(SB), 1, $-4 /* D invalidate SE */
MOVW R0, R2 /* first arg: address */
MOVW CPSR, R3 /* splhi */
ORR $(PsrDirq), R3, R1
MOVW R1, CPSR
MOVW 4(FP), R1 /* second arg: size */
DSB
// CMP.S $(4*1024), R1
// BGT _dinv
ADD R2, R1
BIC $(CACHELINESZ-1), R2
_dinvse:
MCR CpSC, 0, R2, C(CpCACHE), C(CpCACHEinvd), CpCACHEse
ADD $CACHELINESZ, R2
CMP.S R2, R1
BGT _dinvse
/* drain L1 write buffer, also drains L2 eviction buffer on sheeva */
BARRIERS
MOVW R3, CPSR /* splx */
RET
TEXT cacheuwbinv(SB), 1, $-4 /* D+I writeback+invalidate */
MOVW CPSR, R3 /* splhi */
ORR $(PsrDirq), R3, R1
MOVW R1, CPSR
BARRIERS /* force outstanding stores to cache */
/* keep writing back dirty cache lines until no more exist */
_uwbinv: /* D writeback+invalidate */
MRC CpSC, 0, PC, C(CpCACHE), C(CpCACHEwbi), CpCACHEtest
BNE _uwbinv
/* drain L1 write buffer, also drains L2 eviction buffer on sheeva */
BARRIERS
MOVW $0, R0 /* I invalidate */
MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvi), CpCACHEall
/* drain L1 write buffer, also drains L2 eviction buffer on sheeva */
BARRIERS
MOVW R3, CPSR /* splx */
RET
TEXT cacheiinv(SB), 1, $-4 /* I invalidate */
BARRIERS
MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvi), CpCACHEall
/* drain L1 write buffer, also drains L2 eviction buffer on sheeva */
BARRIERS
RET
TEXT cachedinv(SB), 1, $-4 /* D invalidate */
_dinv:
BARRIERS
MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEall
/* drain L1 write buffer, also drains L2 eviction buffer on sheeva */
BARRIERS
RET
/*
* l2 cache
*
* these functions assume that the necessary l1 cache operations have been
* or will be done explicitly by the caller.
*/
/* enable l2 cache in config coproc. reg. do this while l1 caches are off. */
TEXT l2cachecfgon(SB), 1, $-4
BARRIERS
MCR CpSC, CpL2, R0, C(CpTESTCFG), C(CpTCl2inv), CpTCl2all
BARRIERS
MRC CpSC, CpL2, R1, C(CpTESTCFG), C(CpTCl2cfg), CpTCl2conf
ORR $(CpTCl2ena | CpTCl2prefdis), R1 /* l2 on, prefetch off */
MCR CpSC, CpL2, R1, C(CpTESTCFG), C(CpTCl2cfg), CpTCl2conf
BARRIERS
RET
/* disable l2 cache in config coproc. reg. do this while l1 caches are off. */
TEXT l2cachecfgoff(SB), 1, $-4
BARRIERS
MRC CpSC, CpL2, R1, C(CpTESTCFG), C(CpTCl2cfg), CpTCl2conf
BIC $CpTCl2ena, R1
MCR CpSC, CpL2, R1, C(CpTESTCFG), C(CpTCl2cfg), CpTCl2conf
BARRIERS
MCR CpSC, CpL2, R0, C(CpTESTCFG), C(CpTCl2inv), CpTCl2all
BARRIERS
RET
TEXT l2cacheuwb(SB), 1, $-4 /* L2 unified writeback */
MCR CpSC, CpL2, R0, C(CpTESTCFG), C(CpTCl2flush), CpTCl2all
ISB
RET
TEXT l2cacheuwbse(SB), 1, $-4 /* L2 unified writeback SE */
MOVW R0, R2 /* first arg: address */
MOVW CPSR, R3 /* splhi */
ORR $(PsrDirq), R3, R1
MOVW R1, CPSR
MOVW 4(FP), R1 /* second arg: size */
ADD R2, R1
BIC $(CACHELINESZ-1), R2
_l2wbse:
MCR CpSC, CpL2, R2, C(CpTESTCFG), C(CpTCl2flush), CpTCl2seva
ADD $CACHELINESZ, R2
CMP.S R2, R1
BGT _l2wbse
ISB
MOVW R3, CPSR /* splx */
RET
TEXT l2cacheuwbinv(SB), 1, $-4 /* L2 unified writeback+invalidate */
MOVW CPSR, R3 /* splhi */
ORR $(PsrDirq), R3, R1
MOVW R1, CPSR
MCR CpSC, CpL2, R0, C(CpTESTCFG), C(CpTCl2flush), CpTCl2all
ISB
MCR CpSC, CpL2, R0, C(CpTESTCFG), C(CpTCl2inv), CpTCl2all
ISB
MOVW R3, CPSR /* splx */
RET
TEXT l2cacheuwbinvse(SB), 1, $-4 /* L2 unified writeback+invalidate SE */
MOVW R0, R2 /* first arg: address */
MOVW CPSR, R3 /* splhi */
ORR $(PsrDirq), R3, R1
MOVW R1, CPSR
MOVW 4(FP), R1 /* second arg: size */
ADD R2, R1
BIC $(CACHELINESZ-1), R2
_l2wbinvse:
MCR CpSC, CpL2, R2, C(CpTESTCFG), C(CpTCl2flush), CpTCl2seva
ISB
MCR CpSC, CpL2, R2, C(CpTESTCFG), C(CpTCl2inv), CpTCl2seva
ADD $CACHELINESZ, R2
CMP.S R2, R1
BGT _l2wbinvse
ISB
MOVW R3, CPSR /* splx */
RET
TEXT l2cacheuinv(SB), 1, $-4 /* L2 unified invalidate */
MCR CpSC, CpL2, R0, C(CpTESTCFG), C(CpTCl2inv), CpTCl2all
ISB
RET
TEXT l2cacheuinvse(SB), 1, $-4 /* L2 unified invalidate SE */
MOVW R0, R2 /* first arg: address */
MOVW CPSR, R3 /* splhi */
ORR $(PsrDirq), R3, R1
MOVW R1, CPSR
MOVW 4(FP), R1 /* second arg: size */
ADD R2, R1
BIC $(CACHELINESZ-1), R2
_l2invse:
MCR CpSC, CpL2, R2, C(CpTESTCFG), C(CpTCl2inv), CpTCl2seva
ADD $CACHELINESZ, R2
CMP.S R2, R1
BGT _l2invse
ISB
MOVW R3, CPSR /* splx */
RET
/*
* enable mmu, i and d caches, and high vector
*/
TEXT mmuenable(SB), 1, $-4
MRC CpSC, 0, R0, C(CpCONTROL), C(0)
ORR $(CpChv|CpCmmu|CpCdcache|CpCicache|CpCwb|CpCsystem), R0
BIC $(CpCrom), R0
MCR CpSC, 0, R0, C(CpCONTROL), C(0)
BARRIERS
RET
TEXT mmudisable(SB), 1, $-4
MRC CpSC, 0, R0, C(CpCONTROL), C(0)
BIC $(CpChv|CpCmmu|CpCdcache|CpCicache|CpCwb), R0
MCR CpSC, 0, R0, C(CpCONTROL), C(0)
BARRIERS
RET
TEXT mmuinvalidate(SB), 1, $-4 /* invalidate all */
MOVW $0, R0
MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
BARRIERS
RET
TEXT mmuinvalidateaddr(SB), 1, $-4 /* invalidate single entry */
MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinvse
BARRIERS
RET
TEXT cpidget(SB), 1, $-4 /* main ID */
MRC CpSC, 0, R0, C(CpID), C(0), CpIDid
RET
TEXT cpctget(SB), 1, $-4 /* cache type */
MRC CpSC, 0, R0, C(CpID), C(0), CpIDct
RET
TEXT controlget(SB), 1, $-4 /* control */
MRC CpSC, 0, R0, C(CpCONTROL), C(0)
RET
TEXT ttbget(SB), 1, $-4 /* translation table base */
MRC CpSC, 0, R0, C(CpTTB), C(0)
RET
TEXT ttbput(SB), 1, $-4 /* translation table base */
MCR CpSC, 0, R0, C(CpTTB), C(0)
ISB
RET
TEXT dacget(SB), 1, $-4 /* domain access control */
MRC CpSC, 0, R0, C(CpDAC), C(0)
RET
TEXT dacput(SB), 1, $-4 /* domain access control */
MCR CpSC, 0, R0, C(CpDAC), C(0)
ISB
RET
TEXT fsrget(SB), 1, $-4 /* fault status */
MRC CpSC, 0, R0, C(CpFSR), C(0)
RET
TEXT farget(SB), 1, $-4 /* fault address */
MRC CpSC, 0, R0, C(CpFAR), C(0x0)
RET
TEXT pidget(SB), 1, $-4 /* address translation pid */
MRC CpSC, 0, R0, C(CpPID), C(0x0)
RET
TEXT pidput(SB), 1, $-4 /* address translation pid */
MCR CpSC, 0, R0, C(CpPID), C(0x0)
ISB
RET
TEXT splhi(SB), 1, $-4
MOVW $(MACHADDR+4), R2 /* save caller pc in Mach */
MOVW R14, 0(R2)
MOVW CPSR, R0 /* turn off interrupts */
ORR $(PsrDirq), R0, R1
MOVW R1, CPSR
RET
TEXT spllo(SB), 1, $-4
MOVW CPSR, R0
BIC $(PsrDirq), R0, R1
MOVW R1, CPSR
RET
TEXT splx(SB), 1, $-4
MOVW $(MACHADDR+0x04), R2 /* save caller pc in Mach */
MOVW R14, 0(R2)
MOVW R0, R1 /* reset interrupt level */
MOVW CPSR, R0
MOVW R1, CPSR
RET
TEXT splxpc(SB), 1, $-4 /* for iunlock */
MOVW R0, R1
MOVW CPSR, R0
MOVW R1, CPSR
RET
TEXT spldone(SB), 1, $0
RET
TEXT islo(SB), 1, $-4
MOVW CPSR, R0
AND $(PsrDirq), R0
EOR $(PsrDirq), R0
RET
TEXT splfhi(SB), $-4
MOVW CPSR, R0
ORR $(PsrDfiq|PsrDirq), R0, R1
MOVW R1, CPSR
RET
//TEXT splflo(SB), $-4
// MOVW CPSR, R0
// BIC $(PsrDfiq), R0, R1
// MOVW R1, CPSR
// RET
TEXT tas(SB), $-4
TEXT _tas(SB), $-4
MOVW R0,R1
MOVW $1,R0
SWPW R0,(R1) /* fix: deprecated in armv7 */
RET
//TEXT tas32(SB), 1, $-4
// MOVW R0, R1
// MOVW $0xDEADDEAD, R0
// MOVW R0, R3
// SWPW R0, (R1)
// CMP.S R0, R3
// BEQ _tasout
// EOR R3, R3 /* R3 = 0 */
// CMP.S R0, R3
// BEQ _tasout
// MOVW $1, R15 /* abort: lock != 0 && lock != $0xDEADDEAD */
//_tasout:
// RET
TEXT clz(SB), 1, $-4
CLZ(0, 0) /* 0 is R0 */
RET
TEXT setlabel(SB), 1, $-4
MOVW R13, 0(R0) /* sp */
MOVW R14, 4(R0) /* pc */
BARRIERS
MOVW $0, R0
RET
TEXT gotolabel(SB), 1, $-4
MOVW 0(R0), R13 /* sp */
MOVW 4(R0), R14 /* pc */
BARRIERS
MOVW $1, R0
RET
TEXT getcallerpc(SB), 1, $-4
MOVW 0(R13), R0
RET
TEXT _idlehands(SB), 1, $-4
MOVW CPSR, R3
// ORR $PsrDirq, R3, R1 /* splhi */
BIC $PsrDirq, R3, R1 /* spllo */
MOVW R1, CPSR
MOVW $0, R0 /* wait for interrupt */
MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEintr), CpCACHEwait
ISB
MOVW R3, CPSR /* splx */
RET
TEXT barriers(SB), 1, $-4
BARRIERS
RET