2 * code for switching cores into non-secure state and into HYP mode
4 * Copyright (c) 2013 Andre Przywara <andre.przywara@linaro.org>
6 * SPDX-License-Identifier: GPL-2.0+
10 #include <linux/linkage.h>
12 #include <asm/armv7.h>
13 #include <asm/proc-armv/ptrace.h>
18 .pushsection ._secure.text, "ax"
21 /* the vector table for secure state and HYP mode */
25 adr pc, _secure_monitor
32 .macro is_cpu_virt_capable tmp
33 mrc p15, 0, \tmp, c0, c1, 1 @ read ID_PFR1
34 and \tmp, \tmp, #CPUID_ARM_VIRT_MASK @ mask virtualization bits
35 cmp \tmp, #(1 << CPUID_ARM_VIRT_SHIFT)
39 * secure monitor handler
40 * U-boot calls this "software interrupt" in start.S
41 * This is executed on a "smc" instruction, we use a "smc #0" to switch
42 * to non-secure state.
43 * r0, r1, r2: passed to the callee
47 mrc p15, 0, r5, c1, c1, 0 @ read SCR
48 bic r5, r5, #0x4e @ clear IRQ, FIQ, EA, nET bits
49 orr r5, r5, #0x31 @ enable NS, AW, FW bits
51 mov r6, #SVC_MODE @ default mode is SVC
52 is_cpu_virt_capable r4
53 #ifdef CONFIG_ARMV7_VIRT
54 orreq r5, r5, #0x100 @ allow HVC instruction
55 moveq r6, #HYP_MODE @ Enter the kernel as HYP
58 mcr p15, 0, r5, c1, c1, 0 @ write SCR (with NS bit set)
63 @ Reset CNTVOFF to 0 before leaving monitor mode
64 mrc p15, 0, r4, c0, c1, 1 @ read ID_PFR1
65 ands r4, r4, #CPUID_ARM_GENTIMER_MASK @ test arch timer bits
67 mcrrne p15, 4, r4, r4, c14 @ Reset CNTVOFF to zero
70 mov ip, #(F_BIT | I_BIT | A_BIT) @ Set A, I and F
71 tst lr, #1 @ Check for Thumb PC
72 orrne ip, ip, #T_BIT @ Set T if Thumb
73 orr ip, ip, r6 @ Slot target mode in
74 msr spsr_cxfs, ip @ Set full SPSR
75 movs pc, lr @ ERET to non-secure
77 ENTRY(_do_nonsec_entry)
83 ENDPROC(_do_nonsec_entry)
85 .macro get_cbar_addr addr
86 #ifdef CONFIG_ARM_GIC_BASE_ADDRESS
87 ldr \addr, =CONFIG_ARM_GIC_BASE_ADDRESS
89 mrc p15, 4, \addr, c15, c0, 0 @ read CBAR
90 bfc \addr, #0, #15 @ clear reserved bits
94 .macro get_gicd_addr addr
96 add \addr, \addr, #GIC_DIST_OFFSET @ GIC dist i/f offset
99 .macro get_gicc_addr addr, tmp
101 is_cpu_virt_capable \tmp
102 movne \tmp, #GIC_CPU_OFFSET_A9 @ GIC CPU offset for A9
103 moveq \tmp, #GIC_CPU_OFFSET_A15 @ GIC CPU offset for A15/A7
104 add \addr, \addr, \tmp
107 #ifndef CONFIG_ARMV7_PSCI
109 * Secondary CPUs start here and call the code for the core specific parts
110 * of the non-secure and HYP mode transition. The GIC distributor specific
111 * code has already been executed by a C function before.
112 * Then they go back to wfi and wait to be woken up by the kernel again.
120 adr r0, _smp_pen @ do not use this address again
121 b smp_waitloop @ wait for IPIs, board specific
126 * Switch a core to non-secure state.
128 * 1. initialize the GIC per-core interface
129 * 2. allow coprocessor access in non-secure modes
131 * Called from smp_pen by secondary cores and directly by the BSP.
132 * Do not assume that the stack is available and only use registers
135 * PERIPHBASE is used to get the GIC address. This could be 40 bits long,
136 * though, but we check this in C before calling this function.
141 mvn r1, #0 @ all bits to 1
142 str r1, [r3, #GICD_IGROUPRn] @ allow private interrupts
146 mov r1, #3 @ Enable both groups
147 str r1, [r3, #GICC_CTLR] @ and clear all other bits
149 str r1, [r3, #GICC_PMR] @ set priority mask register
151 mrc p15, 0, r0, c1, c1, 2
155 mcr p15, 0, r0, c1, c1, 2 @ NSACR = all copros to non-sec
157 /* The CNTFRQ register of the generic timer needs to be
158 * programmed in secure state. Some primary bootloaders / firmware
159 * omit this, so if the frequency is provided in the configuration,
160 * we do this here instead.
161 * But first check if we have the generic timer.
163 #ifdef CONFIG_SYS_CLK_FREQ
164 mrc p15, 0, r0, c0, c1, 1 @ read ID_PFR1
165 and r0, r0, #CPUID_ARM_GENTIMER_MASK @ mask arch timer bits
166 cmp r0, #(1 << CPUID_ARM_GENTIMER_SHIFT)
167 ldreq r1, =CONFIG_SYS_CLK_FREQ
168 mcreq p15, 0, r1, c14, c0, 0 @ write CNTFRQ
171 adr r1, _monitor_vectors
172 mcr p15, 0, r1, c12, c0, 1 @ set MVBAR to secure vectors
175 mov r0, r3 @ return GICC address
177 ENDPROC(_nonsec_init)
179 #ifdef CONFIG_SMP_PEN_ADDR
180 /* void __weak smp_waitloop(unsigned previous_address); */
183 ldr r1, =CONFIG_SMP_PEN_ADDR @ load start address
185 cmp r0, r1 @ make sure we dont execute this code
186 beq smp_waitloop @ again (due to a spurious wakeup)
189 ENDPROC(smp_waitloop)