2 * Broadcom bcm2836 SoC, as used in Raspberry Pi 2
3 * 4 x Cortex-A7 processor (armv7)
9 #define ICACHELINESZ 32
14 #define DSB WORD $0xf57ff04f /* data synch. barrier; last f = SY */
15 #define DMB WORD $0xf57ff05f /* data mem. barrier; last f = SY */
16 #define ISB WORD $0xf57ff06f /* instr. sync. barrier; last f = SY */
17 #define WFI WORD $0xe320f003 /* wait for interrupt */
18 #define WFI_EQ WORD $0x0320f003 /* wait for interrupt if eq */
19 #define ERET WORD $0xe160006e /* exception return from HYP */
20 #define SEV WORD $0xe320f004 /* send event */
22 /* tas/cas strex debugging limits; started at 10000 */
25 TEXT armstart(SB), 1, $-4
28 * if not cpu0, go to secondary startup
34 * go to SVC mode, interrupts disabled
39 * disable the mmu and caches
41 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
42 BIC $(CpCdcache|CpCicache|CpCmmu), R1
43 ORR $(CpCsbo|CpCsw), R1
45 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
51 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
53 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
57 * clear mach and page tables
59 MOVW $PADDR(MACHADDR), R1
60 MOVW $PADDR(KTZERO), R2
69 * start stack at top of mach (physical addr)
70 * set up page tables for kernel
72 MOVW $PADDR(MACHADDR+MACHSIZE-4), R13
79 * set up domain access control and page table base
82 MCR CpSC, 0, R1, C(CpDAC), C(0)
84 ORR $(CpTTBs|CpTTBowba|CpTTBiwba), R1
85 MCR CpSC, 0, R1, C(CpTTB), C(0)
86 MCR CpSC, 0, R1, C(CpTTB), C(0), CpTTB1 /* cortex has two */
89 * invalidate my caches before enabling
99 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
101 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
105 * enable caches, mmu, and high vectors
107 MRC CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
108 ORR $(CpChv|CpCdcache|CpCicache|CpCmmu), R0
109 MCR CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
113 * switch SB, SP, and PC into KZERO space
115 MOVW $setR12(SB), R12
116 MOVW $(MACHADDR+MACHSIZE-4), R13
117 MOVW $_startpg(SB), R15
119 TEXT _startpg(SB), 1, $-4
122 * enable cycle counter
125 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenacyc
127 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenapmnc
129 /* first arg to main is saved R2 */
133 * call main and loop forever if it returns
138 BL _div(SB) /* hack to load _div, etc. */
141 * startup entry for cpu(s) other than 0
143 TEXT cpureset(SB), 1, $-4
146 * load physical base for SB addressing while mmu is off
148 MOVW $setR12(SB), R12
153 * SVC mode, interrupts disabled
158 * disable the mmu and caches
160 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
161 BIC $(CpCdcache|CpCicache|CpCmmu), R1
162 ORR $(CpCsbo|CpCsw), R1
164 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
170 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
172 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
176 * find Mach for this cpu
178 MRC CpSC, 0, R2, C(CpID), C(CpIDidct), CpIDmpid
179 AND $(MAXMACH-1), R2 /* mask out non-cpu-id bits */
180 SLL $2, R2 /* convert to word index */
181 MOVW $machaddr(SB), R0
184 ADD R2, R0 /* R0 = &machaddr[cpuid] */
185 MOVW (R0), R0 /* R0 = machaddr[cpuid] */
187 BEQ 0(PC) /* must not be zero */
188 SUB $KZERO, R0, R(MACH) /* m = PADDR(machaddr[cpuid]) */
191 * start stack at top of local Mach
193 ADD $(MACHSIZE-4), R(MACH), R13
198 * set up domain access control and page table base
201 MCR CpSC, 0, R1, C(CpDAC), C(0)
202 MOVW 12(R(MACH)), R1 /* m->mmul1 */
203 SUB $KZERO, R1 /* phys addr */
204 ORR $(CpTTBs|CpTTBowba|CpTTBiwba), R1
205 MCR CpSC, 0, R1, C(CpTTB), C(0)
206 MCR CpSC, 0, R1, C(CpTTB), C(0), CpTTB1 /* cortex has two */
209 * invalidate my caches before enabling
218 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
220 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
224 * enable caches, mmu, and high vectors
226 MRC CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
227 ORR $(CpChv|CpCdcache|CpCicache|CpCmmu), R0
228 MCR CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
232 * switch MACH, SB, SP, and PC into KZERO space
235 MOVW $setR12(SB), R12
237 MOVW $_startpg2(SB), R15
239 TEXT _startpg2(SB), 1, $-4
242 * enable cycle counter
245 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenacyc
247 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenapmnc
250 * call cpustart and loop forever if it returns
252 MRC CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDmpid
253 AND $(MAXMACH-1), R0 /* mask out non-cpu-id bits */
258 * get into SVC mode with interrupts disabled
259 * raspberry pi firmware since 29 Sept 2015 starts in HYP mode
261 TEXT svcmode(SB), 1, $-4
266 MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1
268 MSR(1, 1, 1, 0xe) /* MOVW R1, SPSR_HYP */
269 MSR(0, 14, 1, 0xe) /* MOVW R14, ELR_HYP */
275 TEXT cpidget(SB), 1, $-4 /* main ID */
276 MRC CpSC, 0, R0, C(CpID), C(0), CpIDid
279 TEXT fsrget(SB), 1, $-4 /* data fault status */
280 MRC CpSC, 0, R0, C(CpFSR), C(0), CpFSRdata
283 TEXT ifsrget(SB), 1, $-4 /* instruction fault status */
284 MRC CpSC, 0, R0, C(CpFSR), C(0), CpFSRinst
287 TEXT farget(SB), 1, $-4 /* fault address */
288 MRC CpSC, 0, R0, C(CpFAR), C(0x0)
291 TEXT cpctget(SB), 1, $-4 /* cache type */
292 MRC CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDct
295 TEXT lcycles(SB), 1, $-4
296 MRC CpSC, 0, R0, C(CpCLD), C(CpCLDcyc), 0
299 TEXT splhi(SB), 1, $-4
300 MOVW R14, 4(R(MACH)) /* save caller pc in m->splpc */
302 MOVW CPSR, R0 /* turn off irqs (but not fiqs) */
303 ORR $(PsrDirq), R0, R1
307 TEXT splfhi(SB), 1, $-4
308 MOVW R14, 4(R(MACH)) /* save caller pc in m->splpc */
310 MOVW CPSR, R0 /* turn off irqs and fiqs */
311 ORR $(PsrDirq|PsrDfiq), R0, R1
315 TEXT splflo(SB), 1, $-4
316 MOVW CPSR, R0 /* turn on fiqs */
317 BIC $(PsrDfiq), R0, R1
321 TEXT spllo(SB), 1, $-4
322 MOVW CPSR, R0 /* turn on irqs and fiqs */
325 MOVW.NE R1, 4(R(MACH)) /* clear m->splpc */
326 BIC $(PsrDirq|PsrDfiq), R0, R1
330 TEXT splx(SB), 1, $-4
331 MOVW R14, 4(R(MACH)) /* save caller pc in m->splpc */
333 MOVW R0, R1 /* reset interrupt level */
338 TEXT spldone(SB), 1, $0 /* end marker for devkprof.c */
341 TEXT islo(SB), 1, $-4
367 TEXT _tas(SB), $-4 /* _tas(ulong *) */
368 /* returns old (R0) after modifying (R0) */
372 MOVW $1,R2 /* new value of (R0) */
376 CMP.S $0, R7 /* old value non-zero (lock taken)? */
377 BNE lockbusy /* we lose */
382 BNE tas1 /* strex failed? try again */
390 MOVW R7, R0 /* return old value */
393 TEXT setlabel(SB), 1, $-4
394 MOVW R13, 0(R0) /* sp */
395 MOVW R14, 4(R0) /* pc */
399 TEXT gotolabel(SB), 1, $-4
400 MOVW 0(R0), R13 /* sp */
401 MOVW 4(R0), R14 /* pc */
405 TEXT getcallerpc(SB), 1, $-4
409 TEXT idlehands(SB), $-4
411 ORR $(PsrDirq|PsrDfiq), R3, R1 /* splfhi */
420 MOVW R3, CPSR /* splx */
424 TEXT coherence(SB), $-4
435 TEXT mmuinvalidate(SB), 1, $-4
438 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
443 * mmuinvalidateaddr(va)
444 * invalidate tlb entry for virtual page address va, ASID 0
446 TEXT mmuinvalidateaddr(SB), 1, $-4
448 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinvse
453 * `single-element' cache operations.
454 * in arm arch v7, if effective to PoC, they operate on all cache levels, so separate
455 * l2 functions are unnecessary.
458 TEXT cachedwbse(SB), $-4 /* D writeback SE */
464 BARRIERS /* force outstanding stores to cache */
467 ADD R0, R1 /* R1 is end address */
468 BIC $(CACHELINESZ-1), R0 /* cache line start */
470 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEse
471 /* can't have a BARRIER here since it zeroes R0 */
478 * TLB on armv7 loads from cache, so no need for writeback
480 TEXT cachedwbtlb(SB), $-4
485 TEXT cachedwbinvse(SB), $-4 /* D writeback+invalidate SE */
491 BARRIERS /* force outstanding stores to cache */
494 ADD R0, R1 /* R1 is end address */
495 BIC $(CACHELINESZ-1), R0 /* cache line start */
497 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEse
498 /* can't have a BARRIER here since it zeroes R0 */
502 _wait: /* drain write buffer */
505 MOVW R3, CPSR /* splx */
508 TEXT cachedinvse(SB), $-4 /* D invalidate SE */
514 BARRIERS /* force outstanding stores to cache */
517 ADD R0, R1 /* R1 is end address */
518 BIC $(CACHELINESZ-1), R0 /* cache line start */
520 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEse
521 /* can't have a BARRIER here since it zeroes R0 */
527 #include "cache.v7.s"