uboot/arch/arm/cpu/armv7/nonsec_virt.S
<<
>>
Prefs
   1/*
   2 * code for switching cores into non-secure state and into HYP mode
   3 *
   4 * Copyright (c) 2013   Andre Przywara <andre.przywara@linaro.org>
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9#include <config.h>
  10#include <linux/linkage.h>
  11#include <asm/gic.h>
  12#include <asm/armv7.h>
  13#include <asm/proc-armv/ptrace.h>
  14
  15.arch_extension sec
  16.arch_extension virt
  17
  18        .pushsection ._secure.text, "ax"
  19
  20        .align  5
  21/* the vector table for secure state and HYP mode */
  22_monitor_vectors:
  23        .word 0 /* reset */
  24        .word 0 /* undef */
  25        adr pc, _secure_monitor
  26        .word 0
  27        .word 0
  28        .word 0
  29        .word 0
  30        .word 0
  31
  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)
  36.endm
  37
  38/*
  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
  44 * ip: target PC
  45 */
  46_secure_monitor:
  47#ifdef CONFIG_ARMV7_PSCI
  48        ldr     r5, =_psci_vectors              @ Switch to the next monitor
  49        mcr     p15, 0, r5, c12, c0, 1
  50        isb
  51
  52        @ Obtain a secure stack
  53        bl      psci_stack_setup
  54
  55        @ Configure the PSCI backend
  56        push    {r0, r1, r2, ip}
  57        bl      psci_arch_init
  58        pop     {r0, r1, r2, ip}
  59#endif
  60
  61#ifdef CONFIG_ARM_ERRATA_773022
  62        mrc     p15, 0, r5, c1, c0, 1
  63        orr     r5, r5, #(1 << 1)
  64        mcr     p15, 0, r5, c1, c0, 1
  65        isb
  66#endif
  67
  68#ifdef CONFIG_ARM_ERRATA_774769
  69        mrc     p15, 0, r5, c1, c0, 1
  70        orr     r5, r5, #(1 << 25)
  71        mcr     p15, 0, r5, c1, c0, 1
  72        isb
  73#endif
  74
  75        mrc     p15, 0, r5, c1, c1, 0           @ read SCR
  76        bic     r5, r5, #0x4a                   @ clear IRQ, EA, nET bits
  77        orr     r5, r5, #0x31                   @ enable NS, AW, FW bits
  78                                                @ FIQ preserved for secure mode
  79        mov     r6, #SVC_MODE                   @ default mode is SVC
  80        is_cpu_virt_capable r4
  81#ifdef CONFIG_ARMV7_VIRT
  82        orreq   r5, r5, #0x100                  @ allow HVC instruction
  83        moveq   r6, #HYP_MODE                   @ Enter the kernel as HYP
  84#endif
  85
  86        mcr     p15, 0, r5, c1, c1, 0           @ write SCR (with NS bit set)
  87        isb
  88
  89        bne     1f
  90
  91        @ Reset CNTVOFF to 0 before leaving monitor mode
  92        mrc     p15, 0, r4, c0, c1, 1           @ read ID_PFR1
  93        ands    r4, r4, #CPUID_ARM_GENTIMER_MASK        @ test arch timer bits
  94        movne   r4, #0
  95        mcrrne  p15, 4, r4, r4, c14             @ Reset CNTVOFF to zero
  961:
  97        mov     lr, ip
  98        mov     ip, #(F_BIT | I_BIT | A_BIT)    @ Set A, I and F
  99        tst     lr, #1                          @ Check for Thumb PC
 100        orrne   ip, ip, #T_BIT                  @ Set T if Thumb
 101        orr     ip, ip, r6                      @ Slot target mode in
 102        msr     spsr_cxfs, ip                   @ Set full SPSR
 103        movs    pc, lr                          @ ERET to non-secure
 104
 105ENTRY(_do_nonsec_entry)
 106        mov     ip, r0
 107        mov     r0, r1
 108        mov     r1, r2
 109        mov     r2, r3
 110        smc     #0
 111ENDPROC(_do_nonsec_entry)
 112
 113.macro get_cbar_addr    addr
 114#ifdef CONFIG_ARM_GIC_BASE_ADDRESS
 115        ldr     \addr, =CONFIG_ARM_GIC_BASE_ADDRESS
 116#else
 117        mrc     p15, 4, \addr, c15, c0, 0       @ read CBAR
 118        bfc     \addr, #0, #15                  @ clear reserved bits
 119#endif
 120.endm
 121
 122.macro get_gicd_addr    addr
 123        get_cbar_addr   \addr
 124        add     \addr, \addr, #GIC_DIST_OFFSET  @ GIC dist i/f offset
 125.endm
 126
 127.macro get_gicc_addr    addr, tmp
 128        get_cbar_addr   \addr
 129        is_cpu_virt_capable \tmp
 130        movne   \tmp, #GIC_CPU_OFFSET_A9        @ GIC CPU offset for A9
 131        moveq   \tmp, #GIC_CPU_OFFSET_A15       @ GIC CPU offset for A15/A7
 132        add     \addr, \addr, \tmp
 133.endm
 134
 135#ifndef CONFIG_ARMV7_PSCI
 136/*
 137 * Secondary CPUs start here and call the code for the core specific parts
 138 * of the non-secure and HYP mode transition. The GIC distributor specific
 139 * code has already been executed by a C function before.
 140 * Then they go back to wfi and wait to be woken up by the kernel again.
 141 */
 142ENTRY(_smp_pen)
 143        cpsid   i
 144        cpsid   f
 145
 146        bl      _nonsec_init
 147
 148        adr     r0, _smp_pen                    @ do not use this address again
 149        b       smp_waitloop                    @ wait for IPIs, board specific
 150ENDPROC(_smp_pen)
 151#endif
 152
 153/*
 154 * Switch a core to non-secure state.
 155 *
 156 *  1. initialize the GIC per-core interface
 157 *  2. allow coprocessor access in non-secure modes
 158 *
 159 * Called from smp_pen by secondary cores and directly by the BSP.
 160 * Do not assume that the stack is available and only use registers
 161 * r0-r3 and r12.
 162 *
 163 * PERIPHBASE is used to get the GIC address. This could be 40 bits long,
 164 * though, but we check this in C before calling this function.
 165 */
 166ENTRY(_nonsec_init)
 167        get_gicd_addr   r3
 168
 169        mvn     r1, #0                          @ all bits to 1
 170        str     r1, [r3, #GICD_IGROUPRn]        @ allow private interrupts
 171
 172        get_gicc_addr   r3, r1
 173
 174        mov     r1, #3                          @ Enable both groups
 175        str     r1, [r3, #GICC_CTLR]            @ and clear all other bits
 176        mov     r1, #0xff
 177        str     r1, [r3, #GICC_PMR]             @ set priority mask register
 178
 179        mrc     p15, 0, r0, c1, c1, 2
 180        movw    r1, #0x3fff
 181        movt    r1, #0x0004
 182        orr     r0, r0, r1
 183        mcr     p15, 0, r0, c1, c1, 2           @ NSACR = all copros to non-sec
 184
 185/* The CNTFRQ register of the generic timer needs to be
 186 * programmed in secure state. Some primary bootloaders / firmware
 187 * omit this, so if the frequency is provided in the configuration,
 188 * we do this here instead.
 189 * But first check if we have the generic timer.
 190 */
 191#ifdef CONFIG_TIMER_CLK_FREQ
 192        mrc     p15, 0, r0, c0, c1, 1           @ read ID_PFR1
 193        and     r0, r0, #CPUID_ARM_GENTIMER_MASK        @ mask arch timer bits
 194        cmp     r0, #(1 << CPUID_ARM_GENTIMER_SHIFT)
 195        ldreq   r1, =CONFIG_TIMER_CLK_FREQ
 196        mcreq   p15, 0, r1, c14, c0, 0          @ write CNTFRQ
 197#endif
 198
 199        adr     r1, _monitor_vectors
 200        mcr     p15, 0, r1, c12, c0, 1          @ set MVBAR to secure vectors
 201        isb
 202
 203        mov     r0, r3                          @ return GICC address
 204        bx      lr
 205ENDPROC(_nonsec_init)
 206
 207#ifdef CONFIG_SMP_PEN_ADDR
 208/* void __weak smp_waitloop(unsigned previous_address); */
 209ENTRY(smp_waitloop)
 210        wfi
 211        ldr     r1, =CONFIG_SMP_PEN_ADDR        @ load start address
 212        ldr     r1, [r1]
 213#ifdef CONFIG_PEN_ADDR_BIG_ENDIAN
 214        rev     r1, r1
 215#endif
 216        cmp     r0, r1                  @ make sure we dont execute this code
 217        beq     smp_waitloop            @ again (due to a spurious wakeup)
 218        mov     r0, r1
 219        b       _do_nonsec_entry
 220ENDPROC(smp_waitloop)
 221.weak smp_waitloop
 222#endif
 223
 224        .popsection
 225