]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm/armv7.s
bcm: simplify reboot code
[plan9front.git] / sys / src / 9 / bcm / armv7.s
1 /*
2  * Broadcom bcm2836 SoC, as used in Raspberry Pi 2
3  * 4 x Cortex-A7 processor (armv7)
4  */
5
6 #include "arm.s"
7
8 #define CACHELINESZ     64
9 #define ICACHELINESZ    32
10
11 #undef DSB
12 #undef DMB
13 #undef ISB
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 */
21
22 /* tas/cas strex debugging limits; started at 10000 */
23 #define MAXSC 1000000
24
25 TEXT armstart(SB), 1, $-4
26
27         /*
28          * if not cpu0, go to secondary startup
29          */
30         CPUID(R1)
31         BNE     reset
32
33         /*
34          * go to SVC mode, interrupts disabled
35          */
36         BL      svcmode(SB)
37
38         /*
39          * disable the mmu and caches
40          */
41         MRC     CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
42         BIC     $(CpCdcache|CpCicache|CpCmmu), R1
43         ORR     $(CpCsbo|CpCsw), R1
44         BIC     $CpCsbz, R1
45         MCR     CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
46         BARRIERS
47
48         /*
49          * turn SMP on
50          * invalidate tlb
51          */
52         MRC     CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
53         ORR     $CpACsmp, R1            /* turn SMP on */
54         MCR     CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
55         BARRIERS
56         MCR     CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
57         BARRIERS
58
59         /*
60          * clear mach and page tables
61          */
62         MOVW    $PADDR(MACHADDR), R1
63         MOVW    $PADDR(KTZERO), R2
64 _ramZ:
65         MOVW    R0, (R1)
66         ADD     $4, R1
67         CMP     R1, R2
68         BNE     _ramZ
69
70         /*
71          * start stack at top of mach (physical addr)
72          * set up page tables for kernel
73          */
74         MOVW    $PADDR(MACHADDR+MACHSIZE-4), R13
75         MOVW    $PADDR(L1), R0
76         BL      mmuinit(SB)
77
78         /*
79          * set up domain access control and page table base
80          */
81         MOVW    $Client, R1
82         MCR     CpSC, 0, R1, C(CpDAC), C(0)
83         MOVW    $PADDR(L1), R1
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 */
87
88         /*
89          * invalidate my caches before enabling
90          */
91         BL      cachedinv(SB)
92         BL      cacheiinv(SB)
93         BL      l2cacheuinv(SB)
94         BARRIERS
95
96         /*
97          * enable caches, mmu, and high vectors
98          */
99         MRC     CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
100         ORR     $(CpChv|CpCdcache|CpCicache|CpCmmu), R0
101         MCR     CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
102         BARRIERS
103
104         /*
105          * switch SB, SP, and PC into KZERO space
106          */
107         MOVW    $setR12(SB), R12
108         MOVW    $(MACHADDR+MACHSIZE-4), R13
109         MOVW    $_startpg(SB), R15
110
111 TEXT _startpg(SB), 1, $-4
112
113         /*
114          * enable cycle counter
115          */
116         MOVW    $(1<<31), R1
117         MCR     CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenacyc
118         MOVW    $1, R1
119         MCR     CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenapmnc
120
121         /*
122          * call main and loop forever if it returns
123          */
124         BL      ,main(SB)
125         B       ,0(PC)
126
127         BL      _div(SB)                /* hack to load _div, etc. */
128
129 /*
130  * startup entry for cpu(s) other than 0
131  */
132 TEXT cpureset(SB), 1, $-4
133 reset:
134         /*
135          * load physical base for SB addressing while mmu is off
136          * keep a handy zero in R0 until first function call
137          */
138         MOVW    $setR12(SB), R12
139         SUB     $KZERO, R12
140         ADD     $PHYSDRAM, R12
141         MOVW    $0, R0
142
143         /*
144          * SVC mode, interrupts disabled
145          */
146         BL      svcmode(SB)
147
148         /*
149          * disable the mmu and caches
150          */
151         MRC     CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
152         BIC     $(CpCdcache|CpCicache|CpCmmu), R1
153         ORR     $(CpCsbo|CpCsw), R1
154         BIC     $CpCsbz, R1
155         MCR     CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
156         BARRIERS
157
158         /*
159          * turn SMP on
160          * invalidate tlb
161          */
162         MRC     CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
163         ORR     $CpACsmp, R1            /* turn SMP on */
164         MCR     CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
165         BARRIERS
166         MCR     CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
167         BARRIERS
168
169         /*
170          * find Mach for this cpu
171          */
172         MRC     CpSC, 0, R2, C(CpID), C(CpIDidct), CpIDmpid
173         AND     $(MAXMACH-1), R2        /* mask out non-cpu-id bits */
174         SLL     $2, R2                  /* convert to word index */
175         MOVW    $machaddr(SB), R0
176         ADD     R2, R0                  /* R0 = &machaddr[cpuid] */
177         MOVW    (R0), R0                /* R0 = machaddr[cpuid] */
178         CMP     $0, R0
179         BEQ     0(PC)                   /* must not be zero */
180         SUB     $KZERO, R0, R(MACH)     /* m = PADDR(machaddr[cpuid]) */
181
182         /*
183          * start stack at top of local Mach
184          */
185         ADD     $(MACHSIZE-4), R(MACH), R13
186
187         /*
188          * set up domain access control and page table base
189          */
190         MOVW    $Client, R1
191         MCR     CpSC, 0, R1, C(CpDAC), C(0)
192         MOVW    12(R(MACH)), R1 /* m->mmul1 */
193         SUB     $KZERO, R1              /* phys addr */
194         ORR     $(CpTTBs|CpTTBowba|CpTTBiwba), R1
195         MCR     CpSC, 0, R1, C(CpTTB), C(0)
196         MCR     CpSC, 0, R1, C(CpTTB), C(0), CpTTB1     /* cortex has two */
197
198         /*
199          * invalidate my caches before enabling
200          */
201         BL      cachedinv(SB)
202         BL      cacheiinv(SB)
203         BARRIERS
204
205         /*
206          * enable caches, mmu, and high vectors
207          */
208         MRC     CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
209         ORR     $(CpChv|CpCdcache|CpCicache|CpCmmu), R0
210         MCR     CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
211         BARRIERS
212
213         /*
214          * switch MACH, SB, SP, and PC into KZERO space
215          */
216         ADD     $KZERO, R(MACH)
217         MOVW    $setR12(SB), R12
218         ADD     $KZERO, R13
219         MOVW    $_startpg2(SB), R15
220
221 TEXT _startpg2(SB), 1, $-4
222
223         /*
224          * enable cycle counter
225          */
226         MOVW    $(1<<31), R1
227         MCR     CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenacyc
228         MOVW    $1, R1
229         MCR     CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenapmnc
230
231         /*
232          * call cpustart and loop forever if it returns
233          */
234         MRC     CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDmpid
235         AND     $(MAXMACH-1), R0                /* mask out non-cpu-id bits */
236         BL      ,cpustart(SB)
237         B       ,0(PC)
238
239 /*
240  * get into SVC mode with interrupts disabled
241  * raspberry pi firmware since 29 Sept 2015 starts in HYP mode
242  */
243 TEXT svcmode(SB), 1, $-4
244         MOVW    CPSR, R1
245         AND     $PsrMask, R1
246         MOVW    $PsrMhyp, R2
247         CMP     R2, R1
248         MOVW    $(PsrDirq|PsrDfiq|PsrMsvc), R1
249         BNE     nothyp
250         MSR(1, 1, 1, 0xe)       /* MOVW R1, SPSR_HYP */
251         MSR(0, 14, 1, 0xe)      /* MOVW R14, ELR_HYP */
252         ERET
253 nothyp:
254         MOVW    R1, CPSR
255         RET
256
257 TEXT cpidget(SB), 1, $-4                        /* main ID */
258         MRC     CpSC, 0, R0, C(CpID), C(0), CpIDid
259         RET
260
261 TEXT fsrget(SB), 1, $-4                         /* data fault status */
262         MRC     CpSC, 0, R0, C(CpFSR), C(0), CpFSRdata
263         RET
264
265 TEXT ifsrget(SB), 1, $-4                        /* instruction fault status */
266         MRC     CpSC, 0, R0, C(CpFSR), C(0), CpFSRinst
267         RET
268
269 TEXT farget(SB), 1, $-4                         /* fault address */
270         MRC     CpSC, 0, R0, C(CpFAR), C(0x0)
271         RET
272
273 TEXT cpctget(SB), 1, $-4                        /* cache type */
274         MRC     CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDct
275         RET
276
277 TEXT lcycles(SB), 1, $-4
278         MRC     CpSC, 0, R0, C(CpCLD), C(CpCLDcyc), 0
279         RET
280
281 TEXT splhi(SB), 1, $-4
282         MOVW    R14, 4(R(MACH))         /* save caller pc in m->splpc */
283
284         MOVW    CPSR, R0                        /* turn off irqs (but not fiqs) */
285         ORR     $(PsrDirq), R0, R1
286         MOVW    R1, CPSR
287         RET
288
289 TEXT splfhi(SB), 1, $-4
290         MOVW    R14, 4(R(MACH))         /* save caller pc in m->splpc */
291
292         MOVW    CPSR, R0                        /* turn off irqs and fiqs */
293         ORR     $(PsrDirq|PsrDfiq), R0, R1
294         MOVW    R1, CPSR
295         RET
296
297 TEXT splflo(SB), 1, $-4
298         MOVW    CPSR, R0                        /* turn on fiqs */
299         BIC     $(PsrDfiq), R0, R1
300         MOVW    R1, CPSR
301         RET
302
303 TEXT spllo(SB), 1, $-4
304         MOVW    CPSR, R0                        /* turn on irqs and fiqs */
305         MOVW    $0, R1
306         CMP.S   R1, R(MACH)
307         MOVW.NE R1, 4(R(MACH))                  /* clear m->splpc */
308         BIC     $(PsrDirq|PsrDfiq), R0, R1
309         MOVW    R1, CPSR
310         RET
311
312 TEXT splx(SB), 1, $-4
313         MOVW    R14, 4(R(MACH))         /* save caller pc in m->splpc */
314
315         MOVW    R0, R1                          /* reset interrupt level */
316         MOVW    CPSR, R0
317         MOVW    R1, CPSR
318         RET
319
320 TEXT spldone(SB), 1, $0                         /* end marker for devkprof.c */
321         RET
322
323 TEXT islo(SB), 1, $-4
324         MOVW    CPSR, R0
325         AND     $(PsrDirq), R0
326         EOR     $(PsrDirq), R0
327         RET
328
329 TEXT cas(SB), $0
330 TEXT cmpswap(SB), $0
331         MOVW    ov+4(FP), R1
332         MOVW    nv+8(FP), R2
333 spincas:
334         LDREX   (R0), R3
335         CMP.S   R3, R1
336         BNE     fail
337         STREX   R2, (R0), R4
338         CMP.S   $0, R4
339         BNE     spincas
340         MOVW    $1, R0
341         DMB
342         RET
343 fail:
344         CLREX
345         MOVW    $0, R0
346         RET
347
348 TEXT    tas(SB), $-4
349 TEXT    _tas(SB), $-4                   /* _tas(ulong *) */
350         /* returns old (R0) after modifying (R0) */
351         MOVW    R0,R5
352         DMB
353
354         MOVW    $1,R2           /* new value of (R0) */
355         MOVW    $MAXSC, R8
356 tas1:
357         LDREX (R5), R7
358         CMP.S   $0, R7          /* old value non-zero (lock taken)? */
359         BNE     lockbusy        /* we lose */
360         SUB.S   $1, R8
361         BEQ     lockloop2
362         STREX R2,(R5),R4
363         CMP.S   $0, R4
364         BNE     tas1            /* strex failed? try again */
365         DMB
366         B       tas0
367 lockloop2:
368         BL      abort(SB)
369 lockbusy:
370         CLREX
371 tas0:
372         MOVW    R7, R0          /* return old value */
373         RET
374
375 TEXT setlabel(SB), 1, $-4
376         MOVW    R13, 0(R0)              /* sp */
377         MOVW    R14, 4(R0)              /* pc */
378         MOVW    $0, R0
379         RET
380
381 TEXT gotolabel(SB), 1, $-4
382         MOVW    0(R0), R13              /* sp */
383         MOVW    4(R0), R14              /* pc */
384         MOVW    $1, R0
385         RET
386
387 TEXT getcallerpc(SB), 1, $-4
388         MOVW    0(R13), R0
389         RET
390
391 TEXT idlehands(SB), $-4
392         MOVW    CPSR, R3
393         ORR     $(PsrDirq|PsrDfiq), R3, R1              /* splfhi */
394         MOVW    R1, CPSR
395
396         DSB
397         MOVW    nrdy(SB), R0
398         CMP     $0, R0
399         WFI_EQ
400         DSB
401
402         MOVW    R3, CPSR                        /* splx */
403         RET
404
405
406 TEXT coherence(SB), $-4
407         BARRIERS
408         RET
409
410 TEXT sev(SB), $-4
411         SEV
412         RET
413
414 /*
415  * invalidate tlb
416  */
417 TEXT mmuinvalidate(SB), 1, $-4
418         DSB
419         MOVW    $0, R0
420         MCR     CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
421         BARRIERS
422         RET
423
424 /*
425  * mmuinvalidateaddr(va)
426  *   invalidate tlb entry for virtual page address va, ASID 0
427  */
428 TEXT mmuinvalidateaddr(SB), 1, $-4
429         DSB
430         MCR     CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinvse
431         BARRIERS
432         RET
433
434 /*
435  * `single-element' cache operations.
436  * in arm arch v7, if effective to PoC, they operate on all cache levels, so separate
437  * l2 functions are unnecessary.
438  */
439
440 TEXT cachedwbse(SB), $-4                        /* D writeback SE */
441         MOVW    R0, R2
442
443         MOVW    CPSR, R3
444         CPSID                                   /* splhi */
445
446         BARRIERS                        /* force outstanding stores to cache */
447         MOVW    R2, R0
448         MOVW    4(FP), R1
449         ADD     R0, R1                          /* R1 is end address */
450         BIC     $(CACHELINESZ-1), R0            /* cache line start */
451 _dwbse:
452         MCR     CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEse
453         /* can't have a BARRIER here since it zeroes R0 */
454         ADD     $CACHELINESZ, R0
455         CMP.S   R0, R1
456         BGT     _dwbse
457         B       _wait
458
459 /*
460  * TLB on armv7 loads from cache, so no need for writeback
461  */
462 TEXT cachedwbtlb(SB), $-4
463         DSB
464         ISB
465         RET
466
467 TEXT cachedwbinvse(SB), $-4                     /* D writeback+invalidate SE */
468         MOVW    R0, R2
469
470         MOVW    CPSR, R3
471         CPSID                                   /* splhi */
472
473         BARRIERS                        /* force outstanding stores to cache */
474         MOVW    R2, R0
475         MOVW    4(FP), R1
476         ADD     R0, R1                          /* R1 is end address */
477         BIC     $(CACHELINESZ-1), R0            /* cache line start */
478 _dwbinvse:
479         MCR     CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEse
480         /* can't have a BARRIER here since it zeroes R0 */
481         ADD     $CACHELINESZ, R0
482         CMP.S   R0, R1
483         BGT     _dwbinvse
484 _wait:                                          /* drain write buffer */
485         BARRIERS
486
487         MOVW    R3, CPSR                        /* splx */
488         RET
489
490 TEXT cachedinvse(SB), $-4                       /* D invalidate SE */
491         MOVW    R0, R2
492
493         MOVW    CPSR, R3
494         CPSID                                   /* splhi */
495
496         BARRIERS                        /* force outstanding stores to cache */
497         MOVW    R2, R0
498         MOVW    4(FP), R1
499         ADD     R0, R1                          /* R1 is end address */
500         BIC     $(CACHELINESZ-1), R0            /* cache line start */
501 _dinvse:
502         MCR     CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEse
503         /* can't have a BARRIER here since it zeroes R0 */
504         ADD     $CACHELINESZ, R0
505         CMP.S   R0, R1
506         BGT     _dinvse
507         B       _wait
508
509 #include "cache.v7.s"