Skip to content

Commit

Permalink
armstub7: Major refactoring and size improvements, see details:
Browse files Browse the repository at this point in the history
- The bootstub has been completely rewritten taking advantage of the
  Thumb-2 instruction set, which results in major space gains
- Res0 bits of NSACR are no longer set (supersedes #85)
- CNTVOFF is set to zero, now consistent with armstub8 (supersedes #113)
- SMC instructions are now disabled, now consistent with armstub8
- ACTLR is now configured to allow Non-secure access to several CPU
  configuration registers (CPUACTLR/CPUECTLR/L2CTLR/L2ECTLR/L2ACTLR),
  which makes it possible to e.g. enable Spectre v4 mitigations directly
  in the kernel without needing a separate bootstub variant
  (potentially supersedes #115)

Free space in each affected bootstub after this commit:

  armstub7.bin:        108 bytes
  armstub8-32.bin:     104 bytes
  armstub8-32-gic.bin:  44 bytes (!)
  • Loading branch information
fincs authored and pelwell committed Oct 8, 2020
1 parent 0c39cb5 commit 14985bb
Showing 1 changed file with 130 additions and 109 deletions.
239 changes: 130 additions & 109 deletions armstubs/armstub7.S
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright (c) 2016 Raspberry Pi (Trading) Ltd.
Copyright (c) 2016-2020 Raspberry Pi (Trading) Ltd.
All rights reserved.
Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -27,146 +27,167 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

.arch_extension sec
.arch_extension virt
.syntax unified

.section .init
.globl _start
/* the vector table for secure state and HYP mode */
_start:
b jmp_loader /* reset */
#if defined(BCM2711) && (BCM2711 == 1)
osc: .word 54000000
#define MACHINE_ID 3138

#if BCM2711
#define OSC_FREQ 54000000
#define LOCAL_BASE 0xff800000
#else
osc: .word 19200000
#define OSC_FREQ 19200000
#define LOCAL_BASE 0x40000000
#endif

/*
* secure monitor handler
* U-boot calls this "software interrupt" in start.S
* This is executed on a "smc" instruction, we use a "smc #0" to switch
* to non-secure state.
* We use only r0 and r1 here, due to constraints in the caller.
*/
_secure_monitor:
movw r1, #0x131 @ set NS, AW, FW, HVC
mcr p15, 0, r1, c1, c1, 0 @ write SCR (with NS bit set)
#define ARML_PRESCALER 0x08
#define ARML_MBOX_CLR03 0xcc

movw r0, #0x1da @ Set HYP_MODE | F_BIT | I_BIT | A_BIT
msr spsr_cxfs, r0 @ Set full SPSR
#ifdef GIC
/* Distributor */
#define GIC_DISTB 0x41000
#define GICD_CTLR 0x0
#define GICD_IGROUPR 0x80
#define IT_NR 0x8 /* Number of interrupt enable registers (256 total irqs) */

#if defined(BCM2711) && (BCM2711 == 1)
mov r1, #0x22 @ Set L2 read/write latency to 3
mcr p15, 1, r1, c9, c0, 2 @ Write L2CTLR
/* CPU interface */
#define GIC_CPUB 0x42000
#define GICC_CTRLR 0x0
#define GICC_PMR 0x4
#endif

movs pc, lr @ return to non-secure SVC

value: .word 0x63fff
#define machid 3138
#if defined(BCM2711) && (BCM2711 == 1)

#define PRESCALER_2711 0xff800008
#define MBOX_2711 0xff8000cc

mbox: .word MBOX_2711
GIC_DISTB: .word 0xff841000
#if BCM2710
#define NSACR_VAL 0xc00
#else
mbox: .word 0x400000cc
#define NSACR_VAL 0x60c00
#endif
jmp_loader:
@ Check which proc we are and run proc 0 only

.if !BCM2710
mrc p15, 0, r0, c1, c0, 1 @ Read Auxiliary Control Register
orr r0, r0, #(1<<6) @ SMP
mcr p15, 0, r0, c1, c0, 1 @ Write Auxiliary Control Register
.else
mrrc p15, 1, r0, r1, c15 @ CPU Extended Control Register
orr r0, r0, #(1<<6) @ SMP
and r1, r1, #(~3) @ Set L2 load data prefetch to 0b00 = 16
mcrr p15, 1, r0, r1, c15 @ CPU Extended Control Register
.endif
mrc p15, 0, r0, c1, c0, 0 @ Read System Control Register
/* Cortex A72 manual 4.3.67 says SMP must be set before enabling the cache. */
orr r0, r0, #(1<<12) @ icache enable
mcr p15, 0, r0, c1, c0, 0 @ Write System Control Register

mrc p15, 0, r7, c0, c0, 5 @ Put core number into R7

#ifdef GIC
.section .init
.global _start

#define GIC_CPUB_offset 0x1000
/* Vector table for secure state and HYP mode */
_start:
mrc p15, 0, r6, c0, c0, 5 @ Read MPIDR into r6
blx _main @ Jump to bootstub entrypoint (Thumb-2)

#define GICC_CTRLR 0x0
#define GICC_PMR 0x4
#define IT_NR 0x8 @ Number of interrupt enable registers (256 total irqs)
#define GICD_CTRLR 0x0
#define GICD_IGROUPR 0x80
/*
* Secure monitor handler
* This is executed on a "smc" instruction, we use a "smc #0" to switch
* to non-secure state.
* We only clobber ip (r12) here, so that the caller's r0-r7 remain valid.
*/
_secure_monitor:
#if BCM2710
mcr p15, 0, r1, c1, c0, 1 @ Write ACTLR (Secure)
#endif
mov ip, #0x1b1 @ Set NS, AW, FW, SCD, HVC
mcr p15, 0, ip, c1, c1, 0 @ Write SCR (which sets the NS bit)
mov ip, #0x1fa @ Set HYP_MODE | T_BIT | F_BIT | I_BIT | A_BIT
msr spsr_cxfs, ip @ Set full SPSR
movs pc, lr @ Return to non-secure HYP

setup_gic: @ Called from secure mode - set all interrupts to group 1 and enable.
ldr r2, GIC_DISTB
/*
* Main bootstub entrypoint (entered in secure SVC mode)
* This code is Thumb-2 in order to save space.
*/
.thumb_func
_main:
movs r0, #0 @ Set r0 to zero (used by code below and also as a kernel argument)
lsls r6, r6, #30 @ Extract processor number field from MPIDR (shifted left by 30)
ldr r7, =LOCAL_BASE @ Load ARM local peripherals base address for later use

#if !BCM2710
mrc p15, 0, r1, c1, c0, 1 @ Read Auxiliary Control Register
orr r1, r1, #(1<<6) @ Enable SMP
mcr p15, 0, r1, c1, c0, 1 @ Write Auxiliary Control Register
#else
mrrc p15, 1, r1, r2, c15 @ CPU Extended Control Register
orr r1, r1, #(1<<6) @ Enable SMP
#if BCM2711
bic r2, r2, #3 @ Set L2 load data prefetch to 0b00 = 16 requests (A72-specific)
#endif
mcrr p15, 1, r1, r2, c15 @ CPU Extended Control Register
#endif

ands r7,r7, #3 @ primary core
mrc p15, 0, r1, c1, c0, 0 @ Read System Control Register
/* Cortex A72 manual 4.3.67 says SMP must be set before enabling the cache. */
orr r1, r1, #(1<<12) @ Enable icache
mcr p15, 0, r1, c1, c0, 0 @ Write System Control Register

movne r0, #3 @ Enable group 0 and 1 IRQs from distributor
strne r0, [r2, #GICD_CTRLR]
#ifdef GIC

mov r0, #~0
mov r1, #~0 @ group 1 all the things
strd r0, r1, [r2,#(GICD_IGROUPR)]! @ update to bring the CPU registers within range
strd r0, r1, [r2,#8]
strd r0, r1, [r2,#16]
strd r0, r1, [r2,#24]
@ Configure the GIC Distributor
add r5, r7, #GIC_DISTB @ Get base address of GIC_DISTB
cbnz r6, 9f @ Skip setting GICD_CTLR if we are not core 0
movs r1, #3
str r1, [r5, #GICD_CTLR] @ Enable group 0 and 1 IRQs from distributor
9:
mov r1, #~0 @ Route all interrupts to group 1
movs r2, #IT_NR
add r5, r5, #GICD_IGROUPR @ Note: GICD_IGROUPR0 is banked for each core so all cores must set it
0: str r1, [r5], #4
subs r2, r2, #1
bne 0b

movw r1, #0x1e7
str r1, [r2, #(GIC_CPUB_offset - GICD_IGROUPR) ]! @ Enable group 1 IRQs from CPU interface
@ Enable all interrupts coming from group 1 on this core
add r5, r7, #GIC_CPUB @ Get base address of GIC_CPUB
mov r1, #0x1e7
str r1, [r5, #GICC_CTRLR] @ Enable group 1 IRQs from CPU interface

movw r1, #0xff
str r1, [r2, #GICC_PMR] @ priority mask
movs r1, #0xff
str r1, [r5, #GICC_PMR] @ Set priority mask

#endif

mov r0, #1
mcr p15, 0, r0, c14, c3, 1 @ CNTV_CTL (enable=1, imask=0)

@ set to non-sec
ldr r1, value @ value = 0x63fff
@ Allow non-secure access to coprocessors
ldr r1, =NSACR_VAL
mcr p15, 0, r1, c1, c1, 2 @ NSACR = all copros to non-sec
@ timer frequency
ldr r1, osc @ osc = 19.2 / 54MHz
mcr p15, 0, r1, c14, c0, 0 @ write CNTFRQ
#if defined(BCM2711) && (BCM2711 == 1)

@ Initialize the architectural timer
ldr r1, =OSC_FREQ @ osc = 19.2 or 54MHz
mcr p15, 0, r1, c14, c0, 0 @ Write CNTFRQ
#if BCM2711
mov r1, #0x80000000 @ Set ARM_LOCAL_TIMER_PRE_ADD to 1
ldr r2, mbox
str r1, [r2, #(PRESCALER_2711 - MBOX_2711)]
str r1, [r7, #ARML_PRESCALER]
#endif
movs r1, #1
mcr p15, 0, r1, c14, c3, 1 @ CNTV_CTL (enable=1, imask=0)

adr ip, _start
mcr p15, 0, ip, c12, c0, 1 @ set MVBAR to secure vectors

@ Initialize exception vectors and switch to non-secure HYP mode
mcr p15, 0, r0, c12, c0, 1 @ Set MVBAR to secure vectors (i.e. zero)
isb
smc #0 @ call into MONITOR mode

mcr p15, 0, ip, c12, c0, 0 @ write non-secure copy of VBAR

ldrd r2,r3, atags @ ATAGS and kernel

ands r7,r7, #3 @ primary core
beq 9f
#if BCM2710
movs r1, #0x73 @ Value for ACTLR: enable non-secure access to CPUACTLR/CPUECTLR/L2CTLR/L2ECTLR/L2ACTLR
#endif
smc #0 @ Call into MONITOR mode
mcr p15, 0, r0, c12, c0, 0 @ Write non-secure copy of VBAR
mcrr p15, 4, r0, r0, c14 @ Reset CNTVOFF to zero (must be done now in non-secure HYP mode)

ldr r5, mbox @ mbox
#if BCM2711
movs r1, #0x22 @ Value for L2CTLR: set L2 read/write latency to 3
mcr p15, 1, r1, c9, c0, 2 @ Write L2CTLR
#endif

1:
wfe
ldr r3, [r5, r7, lsl #4]
cmp r3, #0 @ magic
beq 1b
@ clear mailbox
str r3, [r5, r7, lsl #4]
@ Set kernel entrypoint arguments
mov r1, #MACHINE_ID @ BCM2708 machine id
ldrd r2, r3, atags @ ATAGS and kernel

@ Secondary cores only: synchronize with core 0 using the mailbox
cbz r6, 9f @ Skip this section if we are core 0
lsrs r6, r6, #(30-4) @ Calculate offset to mailbox register (i.e. ARML_MBOX_CLR03 + coreid*0x10)
adds r6, r6, #ARML_MBOX_CLR03
0: wfe
ldr r3, [r7, r6] @ Read message (secondary kernel entrypoint)
cmp r3, #0 @ If zero, there is no message
beq 0b
str r3, [r7, r6] @ Clear mailbox
9:
mov r0, #0
movw r1, #machid @ BCM2708 machine id

@ Jump to kernel
bx r3

@ Assembler generated constant pool goes here
.pool

.org 0xf0
.word 0x5afe570b @ magic value to indicate firmware should overwrite atags and kernel
.word 0 @ version
Expand Down

0 comments on commit 14985bb

Please sign in to comment.