2013-09-19 16:06:40 +00:00
|
|
|
/*
|
2013-09-19 16:06:45 +00:00
|
|
|
* code for switching cores into non-secure state and into HYP mode
|
2013-09-19 16:06:40 +00:00
|
|
|
*
|
|
|
|
* Copyright (c) 2013 Andre Przywara <andre.przywara@linaro.org>
|
|
|
|
*
|
2013-10-07 08:56:51 +00:00
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
2013-09-19 16:06:40 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
ARM: add assembly routine to switch to non-secure state
While actually switching to non-secure state is one thing, another
part of this process is to make sure that we still have full access
to the interrupt controller (GIC).
The GIC is fully aware of secure vs. non-secure state, some
registers are banked, others may be configured to be accessible from
secure state only.
To be as generic as possible, we get the GIC memory mapped address
based on the PERIPHBASE value in the CBAR register. Since this
register is not architecturally defined, we check the MIDR before to
be from an A15 or A7.
For CPUs not having the CBAR or boards with wrong information herein
we allow providing the base address as a configuration variable.
Now that we know the GIC address, we:
a) allow private interrupts to be delivered to the core
(GICD_IGROUPR0 = 0xFFFFFFFF)
b) enable the CPU interface (GICC_CTLR[0] = 1)
c) set the priority filter to allow non-secure interrupts
(GICC_PMR = 0xFF)
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
The generic timer base frequency register is only accessible from
secure state, so we have to program it now. Actually this should be
done from primary firmware before, but some boards seems to omit
this, so if needed we do this here with a board specific value.
The Versatile Express board does not need this, so we remove the
frequency from the configuration file here.
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Since we need to call this routine also directly from the smp_pen
later (where we don't have any stack), we can only use caller saved
registers r0-r3 and r12 to not mess with the compiler.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
2013-09-19 16:06:41 +00:00
|
|
|
#include <linux/linkage.h>
|
|
|
|
#include <asm/gic.h>
|
|
|
|
#include <asm/armv7.h>
|
2014-07-12 13:24:03 +00:00
|
|
|
#include <asm/proc-armv/ptrace.h>
|
ARM: add assembly routine to switch to non-secure state
While actually switching to non-secure state is one thing, another
part of this process is to make sure that we still have full access
to the interrupt controller (GIC).
The GIC is fully aware of secure vs. non-secure state, some
registers are banked, others may be configured to be accessible from
secure state only.
To be as generic as possible, we get the GIC memory mapped address
based on the PERIPHBASE value in the CBAR register. Since this
register is not architecturally defined, we check the MIDR before to
be from an A15 or A7.
For CPUs not having the CBAR or boards with wrong information herein
we allow providing the base address as a configuration variable.
Now that we know the GIC address, we:
a) allow private interrupts to be delivered to the core
(GICD_IGROUPR0 = 0xFFFFFFFF)
b) enable the CPU interface (GICC_CTLR[0] = 1)
c) set the priority filter to allow non-secure interrupts
(GICC_PMR = 0xFF)
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
The generic timer base frequency register is only accessible from
secure state, so we have to program it now. Actually this should be
done from primary firmware before, but some boards seems to omit
this, so if needed we do this here with a board specific value.
The Versatile Express board does not need this, so we remove the
frequency from the configuration file here.
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Since we need to call this routine also directly from the smp_pen
later (where we don't have any stack), we can only use caller saved
registers r0-r3 and r12 to not mess with the compiler.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
2013-09-19 16:06:41 +00:00
|
|
|
|
|
|
|
.arch_extension sec
|
2013-09-19 16:06:45 +00:00
|
|
|
.arch_extension virt
|
2013-09-19 16:06:40 +00:00
|
|
|
|
2014-07-12 13:24:03 +00:00
|
|
|
.pushsection ._secure.text, "ax"
|
|
|
|
|
2013-10-07 02:46:56 +00:00
|
|
|
.align 5
|
2013-09-19 16:06:45 +00:00
|
|
|
/* the vector table for secure state and HYP mode */
|
2013-09-19 16:06:40 +00:00
|
|
|
_monitor_vectors:
|
|
|
|
.word 0 /* reset */
|
|
|
|
.word 0 /* undef */
|
|
|
|
adr pc, _secure_monitor
|
|
|
|
.word 0
|
|
|
|
.word 0
|
2014-07-12 13:24:03 +00:00
|
|
|
.word 0
|
2013-09-19 16:06:40 +00:00
|
|
|
.word 0
|
|
|
|
.word 0
|
|
|
|
|
2014-07-12 13:24:03 +00:00
|
|
|
.macro is_cpu_virt_capable tmp
|
|
|
|
mrc p15, 0, \tmp, c0, c1, 1 @ read ID_PFR1
|
|
|
|
and \tmp, \tmp, #CPUID_ARM_VIRT_MASK @ mask virtualization bits
|
|
|
|
cmp \tmp, #(1 << CPUID_ARM_VIRT_SHIFT)
|
|
|
|
.endm
|
|
|
|
|
2013-09-19 16:06:40 +00:00
|
|
|
/*
|
|
|
|
* secure monitor handler
|
2016-02-06 03:30:11 +00:00
|
|
|
* U-Boot calls this "software interrupt" in start.S
|
2013-09-19 16:06:40 +00:00
|
|
|
* This is executed on a "smc" instruction, we use a "smc #0" to switch
|
|
|
|
* to non-secure state.
|
2014-07-12 13:24:03 +00:00
|
|
|
* r0, r1, r2: passed to the callee
|
|
|
|
* ip: target PC
|
2013-09-19 16:06:40 +00:00
|
|
|
*/
|
|
|
|
_secure_monitor:
|
2014-07-12 13:24:05 +00:00
|
|
|
#ifdef CONFIG_ARMV7_PSCI
|
|
|
|
ldr r5, =_psci_vectors @ Switch to the next monitor
|
|
|
|
mcr p15, 0, r5, c12, c0, 1
|
|
|
|
isb
|
|
|
|
|
|
|
|
@ Obtain a secure stack, and configure the PSCI backend
|
|
|
|
bl psci_arch_init
|
|
|
|
#endif
|
|
|
|
|
2015-09-29 09:27:09 +00:00
|
|
|
#ifdef CONFIG_ARM_ERRATA_773022
|
|
|
|
mrc p15, 0, r5, c1, c0, 1
|
|
|
|
orr r5, r5, #(1 << 1)
|
|
|
|
mcr p15, 0, r5, c1, c0, 1
|
|
|
|
isb
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_ARM_ERRATA_774769
|
|
|
|
mrc p15, 0, r5, c1, c0, 1
|
|
|
|
orr r5, r5, #(1 << 25)
|
|
|
|
mcr p15, 0, r5, c1, c0, 1
|
|
|
|
isb
|
|
|
|
#endif
|
|
|
|
|
2014-07-12 13:24:03 +00:00
|
|
|
mrc p15, 0, r5, c1, c1, 0 @ read SCR
|
2014-07-12 13:24:05 +00:00
|
|
|
bic r5, r5, #0x4a @ clear IRQ, EA, nET bits
|
2014-07-12 13:24:03 +00:00
|
|
|
orr r5, r5, #0x31 @ enable NS, AW, FW bits
|
2014-07-12 13:24:05 +00:00
|
|
|
@ FIQ preserved for secure mode
|
2014-07-12 13:24:03 +00:00
|
|
|
mov r6, #SVC_MODE @ default mode is SVC
|
|
|
|
is_cpu_virt_capable r4
|
2014-07-12 13:24:00 +00:00
|
|
|
#ifdef CONFIG_ARMV7_VIRT
|
2014-07-12 13:24:03 +00:00
|
|
|
orreq r5, r5, #0x100 @ allow HVC instruction
|
|
|
|
moveq r6, #HYP_MODE @ Enter the kernel as HYP
|
2013-09-19 16:06:45 +00:00
|
|
|
#endif
|
|
|
|
|
2014-07-12 13:24:03 +00:00
|
|
|
mcr p15, 0, r5, c1, c1, 0 @ write SCR (with NS bit set)
|
2014-07-12 13:23:59 +00:00
|
|
|
isb
|
2013-09-19 16:06:40 +00:00
|
|
|
|
2014-07-12 13:24:00 +00:00
|
|
|
bne 1f
|
2013-09-19 16:06:45 +00:00
|
|
|
|
2014-07-12 13:24:00 +00:00
|
|
|
@ Reset CNTVOFF to 0 before leaving monitor mode
|
2014-07-12 13:24:03 +00:00
|
|
|
mrc p15, 0, r4, c0, c1, 1 @ read ID_PFR1
|
|
|
|
ands r4, r4, #CPUID_ARM_GENTIMER_MASK @ test arch timer bits
|
|
|
|
movne r4, #0
|
|
|
|
mcrrne p15, 4, r4, r4, c14 @ Reset CNTVOFF to zero
|
2014-07-12 13:24:00 +00:00
|
|
|
1:
|
2014-07-12 13:24:03 +00:00
|
|
|
mov lr, ip
|
|
|
|
mov ip, #(F_BIT | I_BIT | A_BIT) @ Set A, I and F
|
|
|
|
tst lr, #1 @ Check for Thumb PC
|
|
|
|
orrne ip, ip, #T_BIT @ Set T if Thumb
|
|
|
|
orr ip, ip, r6 @ Slot target mode in
|
|
|
|
msr spsr_cxfs, ip @ Set full SPSR
|
|
|
|
movs pc, lr @ ERET to non-secure
|
|
|
|
|
|
|
|
ENTRY(_do_nonsec_entry)
|
|
|
|
mov ip, r0
|
|
|
|
mov r0, r1
|
|
|
|
mov r1, r2
|
|
|
|
mov r2, r3
|
|
|
|
smc #0
|
|
|
|
ENDPROC(_do_nonsec_entry)
|
|
|
|
|
|
|
|
.macro get_cbar_addr addr
|
|
|
|
#ifdef CONFIG_ARM_GIC_BASE_ADDRESS
|
|
|
|
ldr \addr, =CONFIG_ARM_GIC_BASE_ADDRESS
|
|
|
|
#else
|
|
|
|
mrc p15, 4, \addr, c15, c0, 0 @ read CBAR
|
|
|
|
bfc \addr, #0, #15 @ clear reserved bits
|
|
|
|
#endif
|
|
|
|
.endm
|
|
|
|
|
|
|
|
.macro get_gicd_addr addr
|
|
|
|
get_cbar_addr \addr
|
|
|
|
add \addr, \addr, #GIC_DIST_OFFSET @ GIC dist i/f offset
|
|
|
|
.endm
|
|
|
|
|
|
|
|
.macro get_gicc_addr addr, tmp
|
|
|
|
get_cbar_addr \addr
|
|
|
|
is_cpu_virt_capable \tmp
|
|
|
|
movne \tmp, #GIC_CPU_OFFSET_A9 @ GIC CPU offset for A9
|
|
|
|
moveq \tmp, #GIC_CPU_OFFSET_A15 @ GIC CPU offset for A15/A7
|
|
|
|
add \addr, \addr, \tmp
|
|
|
|
.endm
|
|
|
|
|
|
|
|
#ifndef CONFIG_ARMV7_PSCI
|
2013-09-19 16:06:44 +00:00
|
|
|
/*
|
|
|
|
* Secondary CPUs start here and call the code for the core specific parts
|
|
|
|
* of the non-secure and HYP mode transition. The GIC distributor specific
|
|
|
|
* code has already been executed by a C function before.
|
|
|
|
* Then they go back to wfi and wait to be woken up by the kernel again.
|
|
|
|
*/
|
|
|
|
ENTRY(_smp_pen)
|
2014-07-12 13:24:03 +00:00
|
|
|
cpsid i
|
|
|
|
cpsid f
|
2013-09-19 16:06:44 +00:00
|
|
|
|
|
|
|
bl _nonsec_init
|
|
|
|
|
|
|
|
adr r0, _smp_pen @ do not use this address again
|
|
|
|
b smp_waitloop @ wait for IPIs, board specific
|
|
|
|
ENDPROC(_smp_pen)
|
2014-07-12 13:24:03 +00:00
|
|
|
#endif
|
2013-09-19 16:06:44 +00:00
|
|
|
|
ARM: add assembly routine to switch to non-secure state
While actually switching to non-secure state is one thing, another
part of this process is to make sure that we still have full access
to the interrupt controller (GIC).
The GIC is fully aware of secure vs. non-secure state, some
registers are banked, others may be configured to be accessible from
secure state only.
To be as generic as possible, we get the GIC memory mapped address
based on the PERIPHBASE value in the CBAR register. Since this
register is not architecturally defined, we check the MIDR before to
be from an A15 or A7.
For CPUs not having the CBAR or boards with wrong information herein
we allow providing the base address as a configuration variable.
Now that we know the GIC address, we:
a) allow private interrupts to be delivered to the core
(GICD_IGROUPR0 = 0xFFFFFFFF)
b) enable the CPU interface (GICC_CTLR[0] = 1)
c) set the priority filter to allow non-secure interrupts
(GICC_PMR = 0xFF)
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
The generic timer base frequency register is only accessible from
secure state, so we have to program it now. Actually this should be
done from primary firmware before, but some boards seems to omit
this, so if needed we do this here with a board specific value.
The Versatile Express board does not need this, so we remove the
frequency from the configuration file here.
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Since we need to call this routine also directly from the smp_pen
later (where we don't have any stack), we can only use caller saved
registers r0-r3 and r12 to not mess with the compiler.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
2013-09-19 16:06:41 +00:00
|
|
|
/*
|
|
|
|
* Switch a core to non-secure state.
|
|
|
|
*
|
|
|
|
* 1. initialize the GIC per-core interface
|
|
|
|
* 2. allow coprocessor access in non-secure modes
|
|
|
|
*
|
|
|
|
* Called from smp_pen by secondary cores and directly by the BSP.
|
|
|
|
* Do not assume that the stack is available and only use registers
|
|
|
|
* r0-r3 and r12.
|
|
|
|
*
|
|
|
|
* PERIPHBASE is used to get the GIC address. This could be 40 bits long,
|
|
|
|
* though, but we check this in C before calling this function.
|
|
|
|
*/
|
|
|
|
ENTRY(_nonsec_init)
|
2014-07-12 13:24:03 +00:00
|
|
|
get_gicd_addr r3
|
|
|
|
|
ARM: add assembly routine to switch to non-secure state
While actually switching to non-secure state is one thing, another
part of this process is to make sure that we still have full access
to the interrupt controller (GIC).
The GIC is fully aware of secure vs. non-secure state, some
registers are banked, others may be configured to be accessible from
secure state only.
To be as generic as possible, we get the GIC memory mapped address
based on the PERIPHBASE value in the CBAR register. Since this
register is not architecturally defined, we check the MIDR before to
be from an A15 or A7.
For CPUs not having the CBAR or boards with wrong information herein
we allow providing the base address as a configuration variable.
Now that we know the GIC address, we:
a) allow private interrupts to be delivered to the core
(GICD_IGROUPR0 = 0xFFFFFFFF)
b) enable the CPU interface (GICC_CTLR[0] = 1)
c) set the priority filter to allow non-secure interrupts
(GICC_PMR = 0xFF)
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
The generic timer base frequency register is only accessible from
secure state, so we have to program it now. Actually this should be
done from primary firmware before, but some boards seems to omit
this, so if needed we do this here with a board specific value.
The Versatile Express board does not need this, so we remove the
frequency from the configuration file here.
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Since we need to call this routine also directly from the smp_pen
later (where we don't have any stack), we can only use caller saved
registers r0-r3 and r12 to not mess with the compiler.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
2013-09-19 16:06:41 +00:00
|
|
|
mvn r1, #0 @ all bits to 1
|
|
|
|
str r1, [r3, #GICD_IGROUPRn] @ allow private interrupts
|
|
|
|
|
2014-07-12 13:24:03 +00:00
|
|
|
get_gicc_addr r3, r1
|
ARM: add assembly routine to switch to non-secure state
While actually switching to non-secure state is one thing, another
part of this process is to make sure that we still have full access
to the interrupt controller (GIC).
The GIC is fully aware of secure vs. non-secure state, some
registers are banked, others may be configured to be accessible from
secure state only.
To be as generic as possible, we get the GIC memory mapped address
based on the PERIPHBASE value in the CBAR register. Since this
register is not architecturally defined, we check the MIDR before to
be from an A15 or A7.
For CPUs not having the CBAR or boards with wrong information herein
we allow providing the base address as a configuration variable.
Now that we know the GIC address, we:
a) allow private interrupts to be delivered to the core
(GICD_IGROUPR0 = 0xFFFFFFFF)
b) enable the CPU interface (GICC_CTLR[0] = 1)
c) set the priority filter to allow non-secure interrupts
(GICC_PMR = 0xFF)
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
The generic timer base frequency register is only accessible from
secure state, so we have to program it now. Actually this should be
done from primary firmware before, but some boards seems to omit
this, so if needed we do this here with a board specific value.
The Versatile Express board does not need this, so we remove the
frequency from the configuration file here.
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Since we need to call this routine also directly from the smp_pen
later (where we don't have any stack), we can only use caller saved
registers r0-r3 and r12 to not mess with the compiler.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
2013-09-19 16:06:41 +00:00
|
|
|
|
2014-07-12 13:24:03 +00:00
|
|
|
mov r1, #3 @ Enable both groups
|
ARM: add assembly routine to switch to non-secure state
While actually switching to non-secure state is one thing, another
part of this process is to make sure that we still have full access
to the interrupt controller (GIC).
The GIC is fully aware of secure vs. non-secure state, some
registers are banked, others may be configured to be accessible from
secure state only.
To be as generic as possible, we get the GIC memory mapped address
based on the PERIPHBASE value in the CBAR register. Since this
register is not architecturally defined, we check the MIDR before to
be from an A15 or A7.
For CPUs not having the CBAR or boards with wrong information herein
we allow providing the base address as a configuration variable.
Now that we know the GIC address, we:
a) allow private interrupts to be delivered to the core
(GICD_IGROUPR0 = 0xFFFFFFFF)
b) enable the CPU interface (GICC_CTLR[0] = 1)
c) set the priority filter to allow non-secure interrupts
(GICC_PMR = 0xFF)
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
The generic timer base frequency register is only accessible from
secure state, so we have to program it now. Actually this should be
done from primary firmware before, but some boards seems to omit
this, so if needed we do this here with a board specific value.
The Versatile Express board does not need this, so we remove the
frequency from the configuration file here.
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Since we need to call this routine also directly from the smp_pen
later (where we don't have any stack), we can only use caller saved
registers r0-r3 and r12 to not mess with the compiler.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
2013-09-19 16:06:41 +00:00
|
|
|
str r1, [r3, #GICC_CTLR] @ and clear all other bits
|
|
|
|
mov r1, #0xff
|
|
|
|
str r1, [r3, #GICC_PMR] @ set priority mask register
|
|
|
|
|
2014-07-12 13:24:03 +00:00
|
|
|
mrc p15, 0, r0, c1, c1, 2
|
ARM: add assembly routine to switch to non-secure state
While actually switching to non-secure state is one thing, another
part of this process is to make sure that we still have full access
to the interrupt controller (GIC).
The GIC is fully aware of secure vs. non-secure state, some
registers are banked, others may be configured to be accessible from
secure state only.
To be as generic as possible, we get the GIC memory mapped address
based on the PERIPHBASE value in the CBAR register. Since this
register is not architecturally defined, we check the MIDR before to
be from an A15 or A7.
For CPUs not having the CBAR or boards with wrong information herein
we allow providing the base address as a configuration variable.
Now that we know the GIC address, we:
a) allow private interrupts to be delivered to the core
(GICD_IGROUPR0 = 0xFFFFFFFF)
b) enable the CPU interface (GICC_CTLR[0] = 1)
c) set the priority filter to allow non-secure interrupts
(GICC_PMR = 0xFF)
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
The generic timer base frequency register is only accessible from
secure state, so we have to program it now. Actually this should be
done from primary firmware before, but some boards seems to omit
this, so if needed we do this here with a board specific value.
The Versatile Express board does not need this, so we remove the
frequency from the configuration file here.
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Since we need to call this routine also directly from the smp_pen
later (where we don't have any stack), we can only use caller saved
registers r0-r3 and r12 to not mess with the compiler.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
2013-09-19 16:06:41 +00:00
|
|
|
movw r1, #0x3fff
|
2014-07-12 13:24:03 +00:00
|
|
|
movt r1, #0x0004
|
|
|
|
orr r0, r0, r1
|
|
|
|
mcr p15, 0, r0, c1, c1, 2 @ NSACR = all copros to non-sec
|
ARM: add assembly routine to switch to non-secure state
While actually switching to non-secure state is one thing, another
part of this process is to make sure that we still have full access
to the interrupt controller (GIC).
The GIC is fully aware of secure vs. non-secure state, some
registers are banked, others may be configured to be accessible from
secure state only.
To be as generic as possible, we get the GIC memory mapped address
based on the PERIPHBASE value in the CBAR register. Since this
register is not architecturally defined, we check the MIDR before to
be from an A15 or A7.
For CPUs not having the CBAR or boards with wrong information herein
we allow providing the base address as a configuration variable.
Now that we know the GIC address, we:
a) allow private interrupts to be delivered to the core
(GICD_IGROUPR0 = 0xFFFFFFFF)
b) enable the CPU interface (GICC_CTLR[0] = 1)
c) set the priority filter to allow non-secure interrupts
(GICC_PMR = 0xFF)
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
The generic timer base frequency register is only accessible from
secure state, so we have to program it now. Actually this should be
done from primary firmware before, but some boards seems to omit
this, so if needed we do this here with a board specific value.
The Versatile Express board does not need this, so we remove the
frequency from the configuration file here.
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Since we need to call this routine also directly from the smp_pen
later (where we don't have any stack), we can only use caller saved
registers r0-r3 and r12 to not mess with the compiler.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
2013-09-19 16:06:41 +00:00
|
|
|
|
|
|
|
/* The CNTFRQ register of the generic timer needs to be
|
|
|
|
* programmed in secure state. Some primary bootloaders / firmware
|
|
|
|
* omit this, so if the frequency is provided in the configuration,
|
|
|
|
* we do this here instead.
|
|
|
|
* But first check if we have the generic timer.
|
|
|
|
*/
|
2014-11-21 09:40:55 +00:00
|
|
|
#ifdef CONFIG_TIMER_CLK_FREQ
|
ARM: add assembly routine to switch to non-secure state
While actually switching to non-secure state is one thing, another
part of this process is to make sure that we still have full access
to the interrupt controller (GIC).
The GIC is fully aware of secure vs. non-secure state, some
registers are banked, others may be configured to be accessible from
secure state only.
To be as generic as possible, we get the GIC memory mapped address
based on the PERIPHBASE value in the CBAR register. Since this
register is not architecturally defined, we check the MIDR before to
be from an A15 or A7.
For CPUs not having the CBAR or boards with wrong information herein
we allow providing the base address as a configuration variable.
Now that we know the GIC address, we:
a) allow private interrupts to be delivered to the core
(GICD_IGROUPR0 = 0xFFFFFFFF)
b) enable the CPU interface (GICC_CTLR[0] = 1)
c) set the priority filter to allow non-secure interrupts
(GICC_PMR = 0xFF)
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
The generic timer base frequency register is only accessible from
secure state, so we have to program it now. Actually this should be
done from primary firmware before, but some boards seems to omit
this, so if needed we do this here with a board specific value.
The Versatile Express board does not need this, so we remove the
frequency from the configuration file here.
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Since we need to call this routine also directly from the smp_pen
later (where we don't have any stack), we can only use caller saved
registers r0-r3 and r12 to not mess with the compiler.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
2013-09-19 16:06:41 +00:00
|
|
|
mrc p15, 0, r0, c0, c1, 1 @ read ID_PFR1
|
|
|
|
and r0, r0, #CPUID_ARM_GENTIMER_MASK @ mask arch timer bits
|
|
|
|
cmp r0, #(1 << CPUID_ARM_GENTIMER_SHIFT)
|
2014-11-21 09:40:55 +00:00
|
|
|
ldreq r1, =CONFIG_TIMER_CLK_FREQ
|
ARM: add assembly routine to switch to non-secure state
While actually switching to non-secure state is one thing, another
part of this process is to make sure that we still have full access
to the interrupt controller (GIC).
The GIC is fully aware of secure vs. non-secure state, some
registers are banked, others may be configured to be accessible from
secure state only.
To be as generic as possible, we get the GIC memory mapped address
based on the PERIPHBASE value in the CBAR register. Since this
register is not architecturally defined, we check the MIDR before to
be from an A15 or A7.
For CPUs not having the CBAR or boards with wrong information herein
we allow providing the base address as a configuration variable.
Now that we know the GIC address, we:
a) allow private interrupts to be delivered to the core
(GICD_IGROUPR0 = 0xFFFFFFFF)
b) enable the CPU interface (GICC_CTLR[0] = 1)
c) set the priority filter to allow non-secure interrupts
(GICC_PMR = 0xFF)
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
The generic timer base frequency register is only accessible from
secure state, so we have to program it now. Actually this should be
done from primary firmware before, but some boards seems to omit
this, so if needed we do this here with a board specific value.
The Versatile Express board does not need this, so we remove the
frequency from the configuration file here.
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Since we need to call this routine also directly from the smp_pen
later (where we don't have any stack), we can only use caller saved
registers r0-r3 and r12 to not mess with the compiler.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
2013-09-19 16:06:41 +00:00
|
|
|
mcreq p15, 0, r1, c14, c0, 0 @ write CNTFRQ
|
|
|
|
#endif
|
|
|
|
|
|
|
|
adr r1, _monitor_vectors
|
|
|
|
mcr p15, 0, r1, c12, c0, 1 @ set MVBAR to secure vectors
|
|
|
|
isb
|
|
|
|
|
|
|
|
mov r0, r3 @ return GICC address
|
|
|
|
bx lr
|
|
|
|
ENDPROC(_nonsec_init)
|
2013-09-19 16:06:44 +00:00
|
|
|
|
|
|
|
#ifdef CONFIG_SMP_PEN_ADDR
|
|
|
|
/* void __weak smp_waitloop(unsigned previous_address); */
|
|
|
|
ENTRY(smp_waitloop)
|
|
|
|
wfi
|
|
|
|
ldr r1, =CONFIG_SMP_PEN_ADDR @ load start address
|
|
|
|
ldr r1, [r1]
|
2014-11-21 09:40:54 +00:00
|
|
|
#ifdef CONFIG_PEN_ADDR_BIG_ENDIAN
|
|
|
|
rev r1, r1
|
|
|
|
#endif
|
2013-09-19 16:06:44 +00:00
|
|
|
cmp r0, r1 @ make sure we dont execute this code
|
|
|
|
beq smp_waitloop @ again (due to a spurious wakeup)
|
2014-07-12 13:24:03 +00:00
|
|
|
mov r0, r1
|
|
|
|
b _do_nonsec_entry
|
2013-09-19 16:06:44 +00:00
|
|
|
ENDPROC(smp_waitloop)
|
|
|
|
.weak smp_waitloop
|
|
|
|
#endif
|
2013-09-19 16:06:45 +00:00
|
|
|
|
2014-07-12 13:24:03 +00:00
|
|
|
.popsection
|