Subversion Repositories planix.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * tegra 2 SoC machine assist
 * dual arm cortex-a9 processors
 *
 * ARM v7 arch. ref. man. §B1.3.3 says that we don't need barriers
 * around writes to CPSR.
 *
 * LDREX/STREX use an exclusive monitor, which is part of the data cache unit
 * for the L1 cache, so they won't work right if the L1 cache is disabled.
 */

#include "arm.s"

#define LDREX(fp,t)   WORD $(0xe<<28|0x01900f9f | (fp)<<16 | (t)<<12)
/* `The order of operands is from left to right in dataflow order' - asm man */
#define STREX(f,tp,r) WORD $(0xe<<28|0x01800f90 | (tp)<<16 | (r)<<12 | (f)<<0)

#define MAXMB   (KiB-1)                 /* last MB has vectors */
#define TMPSTACK (DRAMSIZE - 64*MiB)    /* used only during cpu startup */
/* tas/cas strex debugging limits; started at 10000 */
#define MAXSC 100000

GLOBL   testmem(SB), $4

/*
 * Entered here from Das U-Boot or another Plan 9 kernel 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
        CPSMODE(PsrMsvc)
        CPSID                                   /* interrupts off */
        CPSAE
        SETEND(0)                               /* little-endian */
        BARRIERS
        CLREX
        SETZSB

        MOVW    CPSR, R0
        ORR     $PsrDfiq, R0
        MOVW    R0, CPSR

        /* invalidate i-cache and branch-target cache */
        MTCP    CpSC, 0, PC, C(CpCACHE), C(CpCACHEinvi), CpCACHEall
        BARRIERS

        /* put cpus other than 0 to sleep until cpu 0 is ready */
        CPUID(R1)
        BEQ     cpuinit

        /* not cpu 0 */
PUTC('Z')
PUTC('Z')
        BARRIERS
dowfi:
        WFI
        MOVW    cpus_proceed(SB), R1
        CMP     $0, R1
        BEQ     dowfi
        BL      cpureset(SB)
        B       dowfi

cpuinit:
        DELAY(printloopret, 1)
PUTC('\r')
        DELAY(printloopnl, 1)
PUTC('\n')

        DELAY(printloops, 1)
PUTC('P')
        /* disable the PL310 L2 cache on cpu0 */
        MOVW    $(PHYSL2BAG+0x100), R1
        MOVW    $0, R2
        MOVW    R2, (R1)
        BARRIERS
        /* invalidate it */
        MOVW    $((1<<16)-1), R2
        MOVW    R2, 0x77c(R1)
        BARRIERS

        /*
         * disable my MMU & caches
         */
        MFCP    CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
        ORR     $CpCsbo, R1
        BIC     $(CpCsbz|CpCmmu|CpCdcache|CpCicache|CpCpredict), R1
        MTCP    CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
        BARRIERS

        /* cortex-a9 model-specific initial configuration */
        MOVW    $0, R1
        MTCP    CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
        BARRIERS

PUTC('l')
        DELAY(printloop3, 1)

        MOVW    $testmem-KZERO(SB), R0
        BL      memdiag(SB)

PUTC('a')
        /* clear Mach for cpu 0 */
        MOVW    $PADDR(MACHADDR), R4            /* address of Mach for cpu 0 */
        MOVW    $0, R0
_machZ:
        MOVW    R0, (R4)
        ADD     $4, R4
        CMP.S   $PADDR(L1+L1X(0)), R4   /* end at top-level page table */
        BNE     _machZ

        /*
         * set up the MMU page table for cpu 0
         */

PUTC('n')
        /* clear all PTEs first, to provide a default */
//      MOVW    $PADDR(L1+L1X(0)), R4           /* address of PTE for 0 */
_ptenv0:
        ZEROPTE()
        CMP.S   $PADDR(L1+16*KiB), R4
        BNE     _ptenv0

        DELAY(printloop4, 2)
PUTC(' ')
        /*
         * set up double map of PHYSDRAM, KZERO to PHYSDRAM for first few MBs,
         * but only if KZERO and PHYSDRAM differ.
         */
        MOVW    $PTEDRAM, R2                    /* PTE bits */
        MOVW    $PHYSDRAM, R3                   /* pa */
        CMP     $KZERO, R3
        BEQ     no2map
        MOVW    $PADDR(L1+L1X(PHYSDRAM)), R4  /* address of PTE for PHYSDRAM */
        MOVW    $DOUBLEMAPMBS, R5
_ptdbl:
        FILLPTE()
        SUB.S   $1, R5
        BNE     _ptdbl
no2map:

        /*
         * back up and fill in PTEs for memory at KZERO.
         * trimslice has 1 bank of 1GB at PHYSDRAM.
         * Map the maximum.
         */
PUTC('9')
        MOVW    $PTEDRAM, R2                    /* PTE bits */
        MOVW    $PHYSDRAM, R3
        MOVW    $PADDR(L1+L1X(KZERO)), R4       /* start with PTE for KZERO */
        MOVW    $MAXMB, R5                      /* inner loop count (MBs) */
_ptekrw:                                        /* set PTEs */
        FILLPTE()
        SUB.S   $1, R5                          /* decrement inner loop count */
        BNE     _ptekrw

        /*
         * back up and fill in PTEs for MMIO
         */
PUTC(' ')
        MOVW    $PTEIO, R2                      /* PTE bits */
        MOVW    $PHYSIO, R3
        MOVW    $PADDR(L1+L1X(VIRTIO)), R4      /* start with PTE for VIRTIO */
_ptenv2:
        FILLPTE()
        CMP.S   $PADDR(L1+L1X(PHYSIOEND)), R4
        BNE     _ptenv2

        /* mmu.c sets up the trap vectors later */

        MOVW    $(PHYSDRAM | TMPSTACK), SP

        /*
         * learn l1 cache characteristics (on cpu 0 only).
         */

        MOVW    $(1-1), R0                      /* l1 */
        SLL     $1, R0                          /* R0 = (cache - 1) << 1 */
        MTCP    CpSC, CpIDcssel, R0, C(CpID), C(CpIDid), 0 /* select l1 cache */
        BARRIERS
        MFCP    CpSC, CpIDcsize, R0, C(CpID), C(CpIDid), 0 /* get sets & ways */
        MOVW    $CACHECONF, R8

        /* get log2linelen into l1setsh */
        MOVW    R0, R1
        AND     $3, R1
        ADD     $4, R1
        /* l1 & l2 must have same cache line size, thus same set shift */
        MOVW    R1, 4(R8)               /*  +4 = l1setsh */
        MOVW    R1, 12(R8)              /* +12 = l2setsh */

        /* get nways in R1 */
        SRA     $3, R0, R1
        AND     $((1<<10)-1), R1
        ADD     $1, R1

        /* get log2(nways) in R2 (assume nways is 2^n) */
        MOVW    $(BI2BY*BY2WD - 1), R2
        CLZ(1, 1)
        SUB.S   R1, R2                  /* R2 = 31 - clz(nways) */
        ADD.EQ  $1, R2
//      MOVW    R2, R3                  /* print log2(nways): 2 */

        MOVW    $32, R1
        SUB     R2, R1                  /* R1 = 32 - log2(nways) */
        MOVW    R1, 0(R8)               /* +0 = l1waysh */

        BARRIERS

        MOVW    $testmem-KZERO(SB), R0
        BL      memdiag(SB)

        /*
         * the mpcore manual says invalidate d-cache, scu, pl310 in that order,
         * but says nothing about when to disable them.
         *
         * invalidate my caches before enabling
         */
        BL      cachedinv(SB)
        MTCP    CpSC, 0, PC, C(CpCACHE), C(CpCACHEinvi), CpCACHEall
        BARRIERS

PUTC('f')
        /*
         * the mpcore manual says enable scu, d-cache, pl310, smp mode
         * in that order.  we have to reverse the last two; see main().
         */
        BL      scuon(SB)

        /*
         * turn my L1 cache on; need it for tas below.
         */
        MFCP    CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
        ORR     $(CpCdcache|CpCicache|CpCalign|CpCpredict), R1
        MTCP    CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
        BARRIERS

        /* cortex-a9 model-specific configuration */
        MOVW    $CpACl1pref, R1
        MTCP    CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
        BARRIERS

        /* we're supposed to wait until l1 & l2 are on before calling smpon */

PUTC('r')
        /* set the domain access control */
        MOVW    $Client, R0
        BL      dacput(SB)

        DELAY(printloop5, 2)
PUTC('o')
        BL      mmuinvalidate(SB)

        MOVW    $0, R0
        BL      pidput(SB)

        /* set the translation table base */
        MOVW    $PADDR(L1), R0
        BL      ttbput(SB)

PUTC('m')
        /*
         * the little dance to turn the MMU on
         */
        BL      cacheuwbinv(SB)
        BL      mmuinvalidate(SB)
        BL      mmuenable(SB)

PUTC(' ')
        /* warp the PC into the virtual map */
        MOVW    $KZERO, R0
        BL      _r15warp(SB)
        /*
         * cpu 0 is now running at KZERO+something!
         */

        BARRIERS
        MOVW    $setR12(SB), R12                /* reload kernel SB */
        MOVW    $(KZERO | TMPSTACK), SP

        BL      cacheuwbinv(SB)

PUTC('B')
        MOVW    $PHYSDRAM, R3                   /* pa */
        CMP     $KZERO, R3
        BEQ     no2unmap
        /* undo double map of PHYSDRAM, KZERO & first few MBs */
        MOVW    $(L1+L1X(PHYSDRAM)), R4         /* addr. of PTE for PHYSDRAM */
        MOVW    $0, R0
        MOVW    $DOUBLEMAPMBS, R5
_ptudbl:
        ZEROPTE()
        SUB.S   $1, R5
        BNE     _ptudbl
no2unmap:

        BL      cachedwb(SB)
        BL      mmuinvalidate(SB)

        /*
         * call main in C
         * pass Mach to main and set up the stack in it
         */
        MOVW    $MACHADDR, R0                   /* cpu 0 Mach */
        MOVW    R0, R(MACH)                     /* m = MACHADDR */
        ADD     $(MACHSIZE-4), R0, SP           /* leave space for link register */
PUTC('e')
        BL      main(SB)                        /* main(m) */
limbo:
        BL      idlehands(SB)
        B       limbo

        BL      _div(SB)                        /* hack to load _div, etc. */


/*
 * called on cpu(s) other than 0, to start them, from _vrst
 * (reset vector) in lexception.s, with interrupts disabled
 * and in SVC mode, running in the zero segment (pc is in lower 256MB).
 * SB is set for the zero segment.
 */
TEXT cpureset(SB), 1, $-4
        CLREX
        MOVW    CPSR, R0
        ORR     $PsrDfiq, R0
        MOVW    R0, CPSR

        MOVW    $(PHYSDRAM | TMPSTACK), SP      /* stack for cache ops */

        /* paranoia: turn my mmu and caches off. */
        MFCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
        ORR     $CpCsbo, R0
        BIC     $(CpCsbz|CpCmmu|CpCdcache|CpCicache|CpCpredict), R0
        MTCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
        BARRIERS

        /* cortex-a9 model-specific initial configuration */
        MOVW    $0, R1
        MTCP    CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
        ISB

        /* invalidate my caches before enabling */
        BL      cachedinv(SB)
        MTCP    CpSC, 0, PC, C(CpCACHE), C(CpCACHEinvi), CpCACHEall
        BARRIERS

        /*
         * turn my L1 cache on; need it (and mmu) for tas below.
         * need branch prediction to make delay() timing right.
         */
        MFCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
        ORR     $(CpCdcache|CpCicache|CpCalign|CpCpredict), R0
        MTCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
        BARRIERS

        /* enable l1 caches coherency, at minimum for ldrex/strex. */
        BL      smpon(SB)
        BARRIERS

        /*
         * we used to write to PHYSEVP here; now we do it in C, which offers
         * more assurance that we're up and won't go off the rails.
         */

        /* set the domain access control */
        MOVW    $Client, R0
        BL      dacput(SB)

        BL      setmach(SB)

        /*
         * redo double map of PHYSDRAM, KZERO in this cpu's ptes.
         * mmuinit will undo this later.
         */

        MOVW    $PHYSDRAM, R3
        CMP     $KZERO, R3
        BEQ     noun2map

        /* launchinit set m->mmul1 to a copy of cpu0's l1 page table */
        MOVW    12(R(MACH)), R0         /* m->mmul1 (virtual addr) */
        BL      k2paddr(SB)             /* R0 = PADDR(m->mmul1) */
        ADD     $L1X(PHYSDRAM), R0, R4  /* R4 = address of PHYSDRAM's PTE */

        MOVW    $PTEDRAM, R2            /* PTE bits */
        MOVW    $DOUBLEMAPMBS, 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
noun2map:

        MOVW    $0, R0
        BL      pidput(SB)

        /* set the translation table base to PADDR(m->mmul1) */
        MOVW    12(R(MACH)), R0         /* m->mmul1 */
        BL      k2paddr(SB)             /* R0 = PADDR(m->mmul1) */
        BL      ttbput(SB)

        /*
         * the little dance to turn the MMU on
         */
        BL      cacheuwbinv(SB)
        BL      mmuinvalidate(SB)
        BL      mmuenable(SB)

        /*
         * mmu is now on, with l1 pt at m->mmul1.
         */

        /* warp the PC into the virtual map */
        MOVW    $KZERO, R0
        BL      _r15warp(SB)

        /*
         * now running at KZERO+something!
         */

        BARRIERS
        MOVW    $setR12(SB), R12        /* reload kernel's SB */
        MOVW    $(KZERO | TMPSTACK), SP /* stack for cache ops*/
        BL      setmach(SB)
        ADD     $(MACHSIZE-4), R(MACH), SP /* leave space for link register */
        BL      cpustart(SB)


/*
 * converts virtual address in R0 to a physical address.
 */
TEXT k2paddr(SB), 1, $-4
        BIC     $KSEGM, R0
        ADD     $PHYSDRAM, R0
        RET

/*
 * converts physical address in R0 to a virtual address.
 */
TEXT p2kaddr(SB), 1, $-4
        BIC     $KSEGM, R0
        ORR     $KZERO, R0
        RET

/*
 * converts address in R0 to the current segment, as defined by the PC.
 * clobbers R1.
 */
TEXT addr2pcseg(SB), 1, $-4
        BIC     $KSEGM, R0
        MOVW    PC, R1
        AND     $KSEGM, R1              /* segment PC is in */
        ORR     R1, R0
        RET

/* sets R(MACH), preserves other registers */
TEXT setmach(SB), 1, $-4
        MOVM.DB.W [R14], (R13)
        MOVM.DB.W [R0-R2], (R13)

        CPUID(R2)
        SLL     $2, R2                  /* convert to word index */

        MOVW    $machaddr(SB), R0
        BL      addr2pcseg(SB)
        ADD     R2, R0                  /* R0 = &machaddr[cpuid] */
        MOVW    (R0), R0                /* R0 = machaddr[cpuid] */
        CMP     $0, R0
        MOVW.EQ $MACHADDR, R0           /* paranoia: use MACHADDR if 0 */
        BL      addr2pcseg(SB)
        MOVW    R0, R(MACH)             /* m = machaddr[cpuid] */

        MOVM.IA.W (R13), [R0-R2]
        MOVM.IA.W (R13), [R14]
        RET


/*
 * memory diagnostic
 * tests word at (R0); modifies R7 and R8
 */
TEXT memdiag(SB), 1, $-4
        MOVW    $0xabcdef89, R7
        MOVW    R7, (R0)
        MOVW    (R0), R8
        CMP     R7, R8
        BNE     mbuggery                /* broken memory */

        BARRIERS
        MOVW    (R0), R8
        CMP     R7, R8
        BNE     mbuggery                /* broken memory */

        MOVW    $0, R7
        MOVW    R7, (R0)
        BARRIERS
        RET

/* modifies R0, R3—R6 */
TEXT printhex(SB), 1, $-4
        MOVW    R0, R3
        PUTC('0')
        PUTC('x')
        MOVW    $(32-4), R5     /* bits to shift right */
nextdig:
        SRA     R5, R3, R4
        AND     $0xf, R4
        ADD     $'0', R4
        CMP.S   $'9', R4
        BLE     nothex          /* if R4 <= 9, jump */
        ADD     $('a'-('9'+1)), R4
nothex:
        PUTC(R4)
        SUB.S   $4, R5
        BGE     nextdig

        PUTC('\r')
        PUTC('\n')
        DELAY(proct, 50)
        RET

mbuggery:
        PUTC('?')
        PUTC('m')
mtopanic:
        MOVW    $membmsg(SB), R0
        MOVW    R14, R1         /* get R14's segment ... */
        AND     $KSEGM, R1
        BIC     $KSEGM, R0      /* strip segment from address */
        ORR     R1, R0          /* combine them */
        BL      panic(SB)
mbugloop:
        WFI
        B       mbugloop

        DATA    membmsg+0(SB)/8,$"memory b"
        DATA    membmsg+8(SB)/6,$"roken\z"
        GLOBL   membmsg(SB), $14

TEXT _r15warp(SB), 1, $-4
        BIC     $KSEGM, R14                     /* link reg, will become PC */
        ORR     R0, R14
        BIC     $KSEGM, SP
        ORR     R0, SP
        RET

/*
 * `single-element' cache operations.
 * in arm arch v7, they operate on all architected cache levels, so separate
 * l2 functions are usually unnecessary.
 */

TEXT cachedwbse(SB), $-4                        /* D writeback SE */
        MOVW    R0, R2

        MOVW    CPSR, R3
        CPSID                                   /* splhi */

        BARRIERS                        /* force outstanding stores to cache */
        MOVW    R2, R0
        MOVW    4(FP), R1
        ADD     R0, R1                          /* R1 is end address */
        BIC     $(CACHELINESZ-1), R0            /* cache line start */
_dwbse:
        MTCP    CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEse
        ADD     $CACHELINESZ, R0
        CMP.S   R0, R1
        BGT     _dwbse
        B       _wait

TEXT cachedwbinvse(SB), $-4                     /* D writeback+invalidate SE */
        MOVW    R0, R2

        MOVW    CPSR, R3
        CPSID                                   /* splhi */

        BARRIERS                        /* force outstanding stores to cache */
        MOVW    R2, R0
        MOVW    4(FP), R1
        ADD     R0, R1                          /* R1 is end address */
        BIC     $(CACHELINESZ-1), R0            /* cache line start */
_dwbinvse:
        MTCP    CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEse
        ADD     $CACHELINESZ, R0
        CMP.S   R0, R1
        BGT     _dwbinvse
_wait:                                          /* drain write buffer */
        BARRIERS

        MOVW    R3, CPSR                        /* splx */
        RET

TEXT cachedinvse(SB), $-4                       /* D invalidate SE */
        MOVW    R0, R2

        MOVW    CPSR, R3
        CPSID                                   /* splhi */

        BARRIERS                        /* force outstanding stores to cache */
        MOVW    R2, R0
        MOVW    4(FP), R1
        ADD     R0, R1                          /* R1 is end address */

        /*
         * if start & end addresses are not on cache-line boundaries,
         * flush first & last cache lines before invalidating.
         */
        AND.S   $(CACHELINESZ-1), R0, R4
        BEQ     stok
        BIC     $(CACHELINESZ-1), R0, R4        /* cache line start */
        MTCP    CpSC, 0, R4, C(CpCACHE), C(CpCACHEwb), CpCACHEse
stok:
        AND.S   $(CACHELINESZ-1), R1, R4
        BEQ     endok
        BIC     $(CACHELINESZ-1), R1, R4        /* cache line start */
        MTCP    CpSC, 0, R4, C(CpCACHE), C(CpCACHEwb), CpCACHEse
endok:
        BIC     $(CACHELINESZ-1), R0            /* cache line start */
_dinvse:
        MTCP    CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEse
        ADD     $CACHELINESZ, R0
        CMP.S   R0, R1
        BGT     _dinvse
        B       _wait

/*
 *  enable mmu and high vectors
 */
TEXT mmuenable(SB), 1, $-4
        MFCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
        ORR     $CpCmmu, R0
        MTCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
        BARRIERS
        RET

TEXT mmudisable(SB), 1, $-4
        MFCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
        BIC     $CpCmmu, R0
        MTCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
        BARRIERS
        RET

/*
 * If one of these MCR instructions crashes or hangs the machine,
 * check your Level 1 page table (at TTB) closely.
 */
TEXT mmuinvalidate(SB), $-4                     /* invalidate all */
        MOVW    CPSR, R2
        CPSID                                   /* interrupts off */
        BARRIERS
        MTCP    CpSC, 0, PC, C(CpTLB), C(CpTLBinvu), CpTLBinv
        BARRIERS
        MOVW    R2, CPSR                        /* interrupts restored */
        RET

TEXT mmuinvalidateaddr(SB), $-4                 /* invalidate single entry */
        MTCP    CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinvse
        BARRIERS
        RET

TEXT cpidget(SB), 1, $-4                        /* main ID */
        MFCP    CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDid
        RET

TEXT cpctget(SB), 1, $-4                        /* cache type */
        MFCP    CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDct
        RET

TEXT controlget(SB), 1, $-4                     /* system control (sctlr) */
        MFCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
        RET

TEXT ttbget(SB), 1, $-4                         /* translation table base */
        MFCP    CpSC, 0, R0, C(CpTTB), C(0), CpTTB0
        RET

TEXT ttbput(SB), 1, $-4                         /* translation table base */
        MOVW    CPSR, R2
        CPSID
        MOVW    R0, R1
        BARRIERS                /* finish prior accesses before changing ttb */
        MTCP    CpSC, 0, R1, C(CpTTB), C(0), CpTTB0
        MTCP    CpSC, 0, R1, C(CpTTB), C(0), CpTTB1     /* non-secure too */
        MOVW    $0, R0
        MTCP    CpSC, 0, R0, C(CpTTB), C(0), CpTTBctl
        BARRIERS
        MOVW    R2, CPSR
        RET

TEXT dacget(SB), 1, $-4                         /* domain access control */
        MFCP    CpSC, 0, R0, C(CpDAC), C(0)
        RET

TEXT dacput(SB), 1, $-4                         /* domain access control */
        MOVW    R0, R1
        BARRIERS
        MTCP    CpSC, 0, R1, C(CpDAC), C(0)
        ISB
        RET

TEXT fsrget(SB), 1, $-4                         /* fault status */
        MFCP    CpSC, 0, R0, C(CpFSR), C(0), CpDFSR
        RET

TEXT farget(SB), 1, $-4                         /* fault address */
        MFCP    CpSC, 0, R0, C(CpFAR), C(0), CpDFAR
        RET

TEXT getpsr(SB), 1, $-4
        MOVW    CPSR, R0
        RET

TEXT getscr(SB), 1, $-4                         /* secure configuration */
        MFCP    CpSC, 0, R0, C(CpCONTROL), C(CpCONTROLscr), CpSCRscr
        RET

TEXT pidget(SB), 1, $-4                         /* address translation pid */
        MFCP    CpSC, 0, R0, C(CpPID), C(0x0)
        RET

TEXT pidput(SB), 1, $-4                         /* address translation pid */
        MTCP    CpSC, 0, R0, C(CpPID), C(0), 0  /* pid, v7a deprecated */
        MTCP    CpSC, 0, R0, C(CpPID), C(0), 1  /* context id, errata 754322 */
        ISB
        RET

/*
 * access to yet more coprocessor registers
 */

TEXT getauxctl(SB), 1, $-4              /* get cortex-a9 aux. ctl. */
        MFCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpAuxctl
        RET

TEXT putauxctl(SB), 1, $-4              /* put cortex-a9 aux. ctl. */
        BARRIERS
        MTCP    CpSC, 0, R0, C(CpCONTROL), C(0), CpAuxctl
        BARRIERS
        RET

TEXT getclvlid(SB), 1, $-4
        MFCP    CpSC, CpIDcsize, R0, C(CpID), C(CpIDidct), CpIDclvlid
        RET

TEXT getcyc(SB), 1, $-4
        MFCP    CpSC, 0, R0, C(CpCLD), C(CpCLDcyc), 0
        RET

TEXT getdebug(SB), 1, $-4               /* get cortex-a9 debug enable register */
        MFCP    CpSC, 0, R0, C(1), C(1), 1
        RET

TEXT getpc(SB), 1, $-4
        MOVW    PC, R0
        RET

TEXT getsb(SB), 1, $-4
        MOVW    R12, R0
        RET

TEXT setsp(SB), 1, $-4
        MOVW    R0, SP
        RET


TEXT splhi(SB), 1, $-4
        MOVW    CPSR, R0                        /* return old CPSR */
        CPSID                                   /* turn off interrupts */
        CMP.S   $0, R(MACH)
        MOVW.NE R14, 4(R(MACH))                 /* save caller pc in m->splpc */
        RET

TEXT spllo(SB), 1, $-4                  /* start marker for devkprof.c */
        MOVW    CPSR, R0                        /* return old CPSR */
        MOVW    $0, R1
        CMP.S   R1, R(MACH)
        MOVW.NE R1, 4(R(MACH))                  /* clear m->splpc */
        CPSIE
        RET

TEXT splx(SB), 1, $-4
        MOVW    CPSR, R3                        /* must return old CPSR */
        CPSID

        CMP.S   $0, R(MACH)
        MOVW.NE R14, 4(R(MACH))                 /* save caller pc in m->splpc */
        MOVW    R0, CPSR                        /* reset interrupt level */
        MOVW    R3, R0                          /* must return old CPSR */
        RET

TEXT spldone(SB), 1, $0                         /* end marker for devkprof.c */
        RET

TEXT islo(SB), 1, $-4
        MOVW    CPSR, R0
        AND     $(PsrDirq), R0
        EOR     $(PsrDirq), R0
        RET

TEXT clz(SB), $-4
        CLZ(0, 0)                       /* 0 is R0 */
        RET

TEXT setlabel(SB), 1, $-4
        MOVW    SP, 0(R0)
        MOVW    R14, 4(R0)              /* pc */
        MOVW    $0, R0
        RET

TEXT gotolabel(SB), 1, $-4
        MOVW    0(R0), SP
        MOVW    4(R0), R14              /* pc */
        MOVW    $1, R0
        RET

TEXT getcallerpc(SB), 1, $-4
        MOVW    0(SP), R0
        RET

TEXT wfi(SB), $-4
        MOVW    CPSR, R1
        /*
         * an interrupt should break us out of wfi.  masking interrupts
         * slows interrupt response slightly but prevents recursion.
         */
//      CPSIE
        CPSID

        BARRIERS
        WFI

        MOVW    R1, CPSR
        RET

TEXT coherence(SB), $-4
        BARRIERS
        RET

GLOBL cpus_proceed+0(SB), $4

#include "cache.v7.s"

TEXT    tas(SB), $-4                    /* _tas(ulong *) */
        /* returns old (R0) after modifying (R0) */
        MOVW    R0,R5
        DMB

        MOVW    $1,R2           /* new value of (R0) */
        MOVW    $MAXSC, R8
tas1:
        LDREX(5,7)              /* LDREX 0(R5),R7 */
        CMP.S   $0, R7          /* old value non-zero (lock taken)? */
        BNE     lockbusy        /* we lose */
        SUB.S   $1, R8
        BEQ     lockloop2
        STREX(2,5,4)            /* STREX R2,(R5),R4 */
        CMP.S   $0, R4
        BNE     tas1            /* strex failed? try again */
        DMB
        B       tas0
lockloop2:
        PUTC('?')
        PUTC('l')
        PUTC('t')
        BL      abort(SB)
lockbusy:
        CLREX
tas0:
        MOVW    R7, R0          /* return old value */
        RET

Generated by GNU Enscript 1.6.6.