* [U-Boot] [RFC PATCH 1/6] ARM: add secure monitor handler to switch to non-secure state
2013-04-26 13:14 [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support Andre Przywara
@ 2013-04-26 13:14 ` Andre Przywara
2013-04-26 22:11 ` Christoffer Dall
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 2/6] ARM: add assembly routine " Andre Przywara
` (5 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Andre Przywara @ 2013-04-26 13:14 UTC (permalink / raw)
To: u-boot
A prerequisite for using virtualization is to be in HYP mode, which
requires the CPU to be in non-secure state.
According to the ARM ARM this should not be done in SVC mode, so we
have to setup a SMC handler for this. We reuse the current vector
table for this and make sure that we only access the MVBAR register
if the CPU supports the virtualization extensions.
Introduce a monitor handler routine which switches the CPU to
non-secure state by setting the NS bit (and associated bits).
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
arch/arm/cpu/armv7/start.S | 20 +++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
index e9e57e6..7bfb19d 100644
--- a/arch/arm/cpu/armv7/start.S
+++ b/arch/arm/cpu/armv7/start.S
@@ -155,6 +155,10 @@ reset:
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
+
+ mrc p15, 0, r1, c0, c1, 1 @ check for security extension
+ ands r1, r1, #0x30
+ mcrne p15, 0, r0, c12, c0, 1 @ Set secure monitor MVBAR
#endif
/* the mask ROM code should have PLL and others stable */
@@ -256,6 +260,9 @@ ENTRY(c_runtime_cpu_setup)
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
+ mrc p15, 0, r1, c0, c1, 1 @ check for security extension
+ ands r1, r1, #0x30
+ mcrne p15, 0, r0, c12, c0, 1 @ Set secure monitor MVBAR
bx lr
@@ -492,9 +499,16 @@ undefined_instruction:
.align 5
software_interrupt:
- get_bad_stack_swi
- bad_save_user_regs
- bl do_software_interrupt
+ mrc p15, 0, r1, c1, c1, 0 @ read SCR
+ bic r1, r1, #0x07f
+ orr r1, r1, #0x31 @ enable NS, AW, FW
+
+ mrc p15, 0, r0, c12, c0, 0 @ save secure copy of VBAR
+ mcr p15, 0, r1, c1, c1, 0 @ write SCR, switch to non-sec
+ isb
+ mcr p15, 0, r0, c12, c0, 0 @ write non-secure copy of VBAR
+
+ movs pc, lr
.align 5
prefetch_abort:
--
1.7.12.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [U-Boot] [RFC PATCH 1/6] ARM: add secure monitor handler to switch to non-secure state
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 1/6] ARM: add secure monitor handler to switch to non-secure state Andre Przywara
@ 2013-04-26 22:11 ` Christoffer Dall
0 siblings, 0 replies; 16+ messages in thread
From: Christoffer Dall @ 2013-04-26 22:11 UTC (permalink / raw)
To: u-boot
On Fri, Apr 26, 2013 at 03:14:54PM +0200, Andre Przywara wrote:
> A prerequisite for using virtualization is to be in HYP mode, which
> requires the CPU to be in non-secure state.
> According to the ARM ARM this should not be done in SVC mode, so we
> have to setup a SMC handler for this. We reuse the current vector
> table for this and make sure that we only access the MVBAR register
> if the CPU supports the virtualization extensions.
>
> Introduce a monitor handler routine which switches the CPU to
> non-secure state by setting the NS bit (and associated bits).
>
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
> arch/arm/cpu/armv7/start.S | 20 +++++++++++++++++---
> 1 file changed, 17 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
> index e9e57e6..7bfb19d 100644
> --- a/arch/arm/cpu/armv7/start.S
> +++ b/arch/arm/cpu/armv7/start.S
> @@ -155,6 +155,10 @@ reset:
> /* Set vector address in CP15 VBAR register */
> ldr r0, =_start
> mcr p15, 0, r0, c12, c0, 0 @Set VBAR
> +
> + mrc p15, 0, r1, c0, c1, 1 @ check for security extension
> + ands r1, r1, #0x30
> + mcrne p15, 0, r0, c12, c0, 1 @ Set secure monitor MVBAR
> #endif
>
> /* the mask ROM code should have PLL and others stable */
> @@ -256,6 +260,9 @@ ENTRY(c_runtime_cpu_setup)
> /* Set vector address in CP15 VBAR register */
> ldr r0, =_start
> mcr p15, 0, r0, c12, c0, 0 @Set VBAR
> + mrc p15, 0, r1, c0, c1, 1 @ check for security extension
> + ands r1, r1, #0x30
> + mcrne p15, 0, r0, c12, c0, 1 @ Set secure monitor MVBAR
>
> bx lr
>
> @@ -492,9 +499,16 @@ undefined_instruction:
>
> .align 5
> software_interrupt:
> - get_bad_stack_swi
> - bad_save_user_regs
> - bl do_software_interrupt
I think you should add a comment block here saying that this is handling
an smc #0 call and the intent is to change to non-secure world.
> + mrc p15, 0, r1, c1, c1, 0 @ read SCR
> + bic r1, r1, #0x07f
> + orr r1, r1, #0x31 @ enable NS, AW, FW
> +
> + mrc p15, 0, r0, c12, c0, 0 @ save secure copy of VBAR
> + mcr p15, 0, r1, c1, c1, 0 @ write SCR, switch to non-sec
> + isb
> + mcr p15, 0, r0, c12, c0, 0 @ write non-secure copy of VBAR
> +
> + movs pc, lr
>
> .align 5
> prefetch_abort:
> --
> 1.7.12.1
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [U-Boot] [RFC PATCH 2/6] ARM: add assembly routine to switch to non-secure state
2013-04-26 13:14 [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support Andre Przywara
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 1/6] ARM: add secure monitor handler to switch to non-secure state Andre Przywara
@ 2013-04-26 13:14 ` Andre Przywara
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 3/6] ARM: add U-Boot command "hypmode" " Andre Przywara
` (4 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: Andre Przywara @ 2013-04-26 13:14 UTC (permalink / raw)
To: u-boot
While actually switching to non-secure state is one thing, the
more important 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 register. We check explicitly for
ARM Cortex-A7 and A15 cores, assuming an A9 otherwise, as for those
cores we know the offsets for the GIC CPU interface from the
PERIPHBASE content. Other cores could be added as needed.
With the GIC accessible, 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 = 0x80)
After having switched to non-secure state, we also enable the
non-secure GIC CPU interface, since this register is banked.
Also we allow access to all coprocessor interfaces from non-secure
state by writing the appropriate bits in the NSACR register.
For reasons obvious later we only use caller saved registers r0-r3.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
arch/arm/cpu/armv7/start.S | 45 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
index 7bfb19d..401b0eb 100644
--- a/arch/arm/cpu/armv7/start.S
+++ b/arch/arm/cpu/armv7/start.S
@@ -561,3 +561,48 @@ fiq:
#endif /* CONFIG_USE_IRQ */
#endif /* CONFIG_SPL_BUILD */
+
+/* Routine to initialize GIC CPU interface and switch to nonsecure state.
+ */
+.globl _nonsec_gic_switch
+_nonsec_gic_switch:
+ mrc p15, 4, r2, c15, c0, 0 @ r2 = PERIPHBASE
+ add r3, r2, #0x1000 @ GIC dist i/f offset
+ mvn r1, #0
+ str r1, [r3, #0x80] @ allow private interrupts
+
+ mrc p15, 0, r0, c0, c0, 0 @ MIDR
+ bfc r0, #16, #8 @ mask out variant, arch
+ bfc r0, #0, #4 @ and revision
+ movw r1, #0xc070
+ movt r1, #0x4100
+ cmp r0, r1 @ check for Cortex-A7
+ orr r1, #0xf0
+ cmpne r0, r1 @ check for Cortex-A15
+ movne r1, #0x100 @ GIC CPU offset for A9
+ moveq r1, #0x2000 @ GIC CPU offset for A15/A7
+ add r3, r2, r1 @ r3 = GIC CPU i/f addr
+
+ mov r1, #1
+ str r1, [r3, #0] @ set GICC_CTLR[enable]
+ mov r1, #0x80
+ str r1, [r3, #4] @ set GICC_PIMR[7]
+
+ movw r1, #0x3fff
+ movt r1, #0x0006
+ mcr p15, 0, r1, c1, c1, 2 @ NSACR = all copros to non-sec
+
+ ldr r1, =_start
+ mcr p15, 0, r1, c12, c0, 0 @ set VBAR
+ mcr p15, 0, r1, c12, c0, 1 @ set MVBAR
+
+ isb
+ smc #0 @ call into MONITOR mode
+ isb @ clobbers r0 and r1
+
+ mov r1, #1
+ str r1, [r3, #0] @ set GICC_CTLR[enable]
+ add r2, r2, #0x1000 @ GIC dist i/f offset
+ str r1, [r2] @ allow private interrupts
+
+ mov pc, lr
--
1.7.12.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [U-Boot] [RFC PATCH 3/6] ARM: add U-Boot command "hypmode" to switch to non-secure state
2013-04-26 13:14 [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support Andre Przywara
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 1/6] ARM: add secure monitor handler to switch to non-secure state Andre Przywara
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 2/6] ARM: add assembly routine " Andre Przywara
@ 2013-04-26 13:14 ` Andre Przywara
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 4/6] ARM: add SMP support for non-secure switch Andre Przywara
` (3 subsequent siblings)
6 siblings, 0 replies; 16+ messages in thread
From: Andre Przywara @ 2013-04-26 13:14 UTC (permalink / raw)
To: u-boot
In preparation for the actual HYP mode switch, we introduce a new
U-Boot command called "hypmode". For now we only do the non-secure
switch here.
Some part of the work is done in the assembly routine in start.S,
introduced with the previous patch, but for the full glory we need
to setup the GIC distributor interface once for the whole system,
which is done in C here.
The routine is placed in arch/arm/lib to allow easy access from
different boards or CPUs.
First we check for the availability of the security extensions.
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.
Since we need a safe way to access the GIC, we use the PERIPHBASE
registers on Cortex-A15 and A7 CPUs and do some sanity checks.
Then we actually do the GIC enablement:
a) enable the GIC distributor, both for non-secure and secure state
(GICD_CTLR[1:0] = 11b)
b) allow all interrupts to be handled from non-secure state
(GICD_IGROUPRn = 0xFFFFFFFF)
The core specific GIC setup is then done in the assembly routine.
The actual U-Boot command is pretty small: calling the routine and
doing some error reporting. A return value of 1 will be added later.
To enable the whole code we introduce the CONFIG_CMD_VIRT variable.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
arch/arm/include/asm/armv7.h | 2 +
arch/arm/lib/Makefile | 2 +
arch/arm/lib/virt-v7.c | 116 +++++++++++++++++++++++++++++++++++++++++++
common/Makefile | 1 +
common/cmd_virt.c | 59 ++++++++++++++++++++++
5 files changed, 180 insertions(+)
create mode 100644 arch/arm/lib/virt-v7.c
create mode 100644 common/cmd_virt.c
diff --git a/arch/arm/include/asm/armv7.h b/arch/arm/include/asm/armv7.h
index a73630b..3567692 100644
--- a/arch/arm/include/asm/armv7.h
+++ b/arch/arm/include/asm/armv7.h
@@ -74,4 +74,6 @@ void v7_outer_cache_inval_all(void);
void v7_outer_cache_flush_range(u32 start, u32 end);
void v7_outer_cache_inval_range(u32 start, u32 end);
+int armv7_switch_nonsec(void);
+
#endif
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 6ae161a..c5b6b69 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -58,6 +58,8 @@ COBJS-y += reset.o
COBJS-y += cache.o
COBJS-y += cache-cp15.o
+COBJS-y += virt-v7.o
+
SRCS := $(GLSOBJS:.o=.S) $(GLCOBJS:.o=.c) \
$(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
diff --git a/arch/arm/lib/virt-v7.c b/arch/arm/lib/virt-v7.c
new file mode 100644
index 0000000..416ca29
--- /dev/null
+++ b/arch/arm/lib/virt-v7.c
@@ -0,0 +1,116 @@
+/*
+ * (C) Copyright 2013
+ * Andre Przywara, Linaro
+ *
+ * routines to push ARMv7 processors from secure into non-secure state
+ * needed to enable ARMv7 virtualization for current hypervisors
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/armv7.h>
+
+/* the assembly routine doing the actual work in start.S */
+void _nonsec_gic_switch(void);
+
+#define GICD_CTLR 0x000
+#define GICD_TYPER 0x004
+#define GICD_IGROUPR0 0x080
+#define GICD_SGIR 0xf00
+
+#define CPU_ARM_CORTEX_A15 0x4100c0f0
+#define CPU_ARM_CORTEX_A7 0x4100c070
+
+static inline unsigned int read_cpsr(void)
+{
+ unsigned int reg;
+
+ asm volatile ("mrs %0, cpsr\n" : "=r" (reg));
+ return reg;
+}
+
+int armv7_switch_nonsec(void)
+{
+ unsigned int reg;
+ volatile unsigned int *gicdptr;
+ unsigned itlinesnr, i;
+
+ /* check whether the CPU supports the security extensions */
+ asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg));
+ if ((reg & 0xF0) == 0)
+ return 2;
+
+ /* the timer frequency for the generic timer needs to be
+ * programmed still in secure state, should be done by firmware.
+ * check whether we have the generic timer first
+ */
+#ifdef CONFIG_SYS_CLK_FREQ
+ asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg));
+ if ((reg & 0xF0000) == 0x10000)
+ asm("mcr p15, 0, %0, c14, c0, 0\n"
+ : : "r"(CONFIG_SYS_CLK_FREQ));
+#endif
+
+ /* the SCR register will be set directly in the monitor mode handler,
+ * according to the spec one should not tinker with it in secure state
+ * in SVC mode. Do not try to read it once in non-secure state,
+ * any access to it will trap.
+ */
+
+ /* check whether we are an Cortex-A15 or A7.
+ * The actual non-secure switch should work with all CPUs supporting
+ * the security extension, but we need the GIC address,
+ * which we know only for sure for those two CPUs.
+ */
+ asm("mrc p15, 0, %0, c0, c0, 0\n" : "=r"(reg));
+ if (((reg & 0xFF00FFF0) != 0x4100C0F0) &&
+ ((reg & 0xFF00FFF0) != 0x4100C070))
+ return 3;
+
+ /* get the GIC base address from the A15 PERIPHBASE register */
+ asm("mrc p15, 4, %0, c15, c0, 0\n" : "=r" (reg));
+
+ /* the PERIPHBASE can be mapped above 4 GB (lower 8 bits used to
+ * encode this). Bail out here since we cannot access this without
+ * enabling paging.
+ */
+ if ((reg & 0xff) != 0)
+ return 4;
+
+ /* GIC distributor registers start at offset 0x1000 */
+ gicdptr = (unsigned *)(reg + 0x1000);
+
+ /* enable the GIC distributor */
+ gicdptr[GICD_CTLR / 4] |= 0x03;
+
+ /* TYPER[4:0] contains an encoded number of all interrupts */
+ itlinesnr = gicdptr[GICD_TYPER / 4] & 0x1f;
+
+ /* set all bits in the GIC group registers to one to allow access
+ * from non-secure state
+ */
+ for (i = 0; i <= itlinesnr; i++)
+ gicdptr[GICD_IGROUPR0 / 4 + i] = (unsigned)-1;
+
+ /* call the non-sec switching code on this CPU */
+ _nonsec_gic_switch();
+
+ return 0;
+}
diff --git a/common/Makefile b/common/Makefile
index 0e0fff1..d9ba5ab 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -129,6 +129,7 @@ COBJS-y += cmd_load.o
COBJS-$(CONFIG_LOGBUFFER) += cmd_log.o
COBJS-$(CONFIG_ID_EEPROM) += cmd_mac.o
COBJS-$(CONFIG_CMD_MD5SUM) += cmd_md5sum.o
+COBJS-$(CONFIG_CMD_VIRT) += cmd_virt.o
COBJS-$(CONFIG_CMD_MEMORY) += cmd_mem.o
COBJS-$(CONFIG_CMD_IO) += cmd_io.o
COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o
diff --git a/common/cmd_virt.c b/common/cmd_virt.c
new file mode 100644
index 0000000..132b6b1
--- /dev/null
+++ b/common/cmd_virt.c
@@ -0,0 +1,59 @@
+/*
+ * (C) Copyright 2013
+ * Andre Przywara, Linaro
+ *
+ * command to switch an ARMv7 CPU with security extensions into
+ * non-secure state
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+
+#include <asm/armv7.h>
+
+static int do_nonsec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned int ret;
+
+ ret = armv7_switch_nonsec();
+
+ switch (ret) {
+ case 0:
+ break;
+ case 2:
+ printf("Security extensions not implemented.\n");
+ break;
+ case 3:
+ printf("CPU not supported, must be either Cortex-A15 or A7.\n");
+ break;
+ case 4:
+ printf("PERIPHBASE is above 4 GB, cannot access this.\n");
+ break;
+ }
+
+ return ret;
+}
+
+U_BOOT_CMD(
+ hypmode, 1, 0, do_nonsec,
+ "switch ARM CPUs into non-secure state",
+ ""
+);
--
1.7.12.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [U-Boot] [RFC PATCH 4/6] ARM: add SMP support for non-secure switch
2013-04-26 13:14 [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support Andre Przywara
` (2 preceding siblings ...)
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 3/6] ARM: add U-Boot command "hypmode" " Andre Przywara
@ 2013-04-26 13:14 ` Andre Przywara
2013-04-26 22:13 ` Christoffer Dall
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 5/6] ARM: extend non-secure switch to also go into HYP mode Andre Przywara
` (2 subsequent siblings)
6 siblings, 1 reply; 16+ messages in thread
From: Andre Przywara @ 2013-04-26 13:14 UTC (permalink / raw)
To: u-boot
Currently the non-secure switch is only done for the boot processor.
To later allow full SMP support, we have to switch all secondary
cores into non-secure state also.
So we add an entry point for secondary CPUs coming out of low-power
state and make sure we put them into WFI again after having switched
to non-secure state.
For this we acknowledge and EOI the wake-up IPI, then go into WFI.
Once being kicked out of it later, we sanity check that the start
address has actually been changed (since another attempt to switch
to non-secure would block the core) and jump to the new address.
The actual CPU kick is done by sending an inter-processor interrupt
via the GIC to all CPU interfaces except the requesting processor.
The secondary cores will then setup their respective GIC CPU
interface.
The address secondary cores jump to is board specific, we provide
the value here for the Versatile Express board.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
arch/arm/cpu/armv7/start.S | 27 ++++++++++++++++++++++++++-
arch/arm/lib/virt-v7.c | 10 +++++++++-
include/configs/vexpress_ca15_tc2.h | 1 +
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
index 401b0eb..2b47881 100644
--- a/arch/arm/cpu/armv7/start.S
+++ b/arch/arm/cpu/armv7/start.S
@@ -563,8 +563,19 @@ fiq:
#endif /* CONFIG_SPL_BUILD */
/* Routine to initialize GIC CPU interface and switch to nonsecure state.
+ * Will be executed directly by secondary CPUs after coming out of
+ * WFI, or can be called directly by C code for CPU 0.
+ * Those two paths mandate to not use any stack and to only use registers
+ * r0-r3 to comply with both the C ABI and the requirement of SMP startup
+ * code.
*/
.globl _nonsec_gic_switch
+.globl _smp_pen
+_smp_pen:
+ mrs r0, cpsr
+ orr r0, r0, #0xc0
+ msr cpsr, r0 @ disable interrupts
+ mov lr, #0 @ clear LR to mark secondary
_nonsec_gic_switch:
mrc p15, 4, r2, c15, c0, 0 @ r2 = PERIPHBASE
add r3, r2, #0x1000 @ GIC dist i/f offset
@@ -605,4 +616,18 @@ _nonsec_gic_switch:
add r2, r2, #0x1000 @ GIC dist i/f offset
str r1, [r2] @ allow private interrupts
- mov pc, lr
+ cmp lr, #0
+ movne pc, lr @ CPU 0 to return
+ @ all others: go to sleep
+_ack_int:
+ ldr r1, [r3, #0x0c] @ read GICD acknowledge
+ str r1, [r3, #0x10] @ write GICD EOI
+
+ adr r1, _smp_pen
+waitloop:
+ wfi
+ ldr r0, =CONFIG_SYSFLAGS_ADDR @ load start address
+ ldr r0, [r0]
+ cmp r0, r1 @ make sure we dont execute this code
+ beq waitloop @ again (due to a spurious wakeup)
+ mov pc, r0
diff --git a/arch/arm/lib/virt-v7.c b/arch/arm/lib/virt-v7.c
index 416ca29..5ca093a 100644
--- a/arch/arm/lib/virt-v7.c
+++ b/arch/arm/lib/virt-v7.c
@@ -29,6 +29,7 @@
/* the assembly routine doing the actual work in start.S */
void _nonsec_gic_switch(void);
+void _smp_pen(void);
#define GICD_CTLR 0x000
#define GICD_TYPER 0x004
@@ -51,6 +52,7 @@ int armv7_switch_nonsec(void)
unsigned int reg;
volatile unsigned int *gicdptr;
unsigned itlinesnr, i;
+ unsigned int *sysflags;
/* check whether the CPU supports the security extensions */
asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg));
@@ -109,7 +111,13 @@ int armv7_switch_nonsec(void)
for (i = 0; i <= itlinesnr; i++)
gicdptr[GICD_IGROUPR0 / 4 + i] = (unsigned)-1;
- /* call the non-sec switching code on this CPU */
+ /* now kick all CPUs (expect this one) by writing to GICD_SIGR */
+ sysflags = (void *)CONFIG_SYSFLAGS_ADDR;
+ sysflags[1] = (unsigned)-1;
+ sysflags[0] = (uintptr_t)_smp_pen;
+ gicdptr[GICD_SGIR / 4] = 1U << 24;
+
+ /* call the non-sec switching code on this CPU also */
_nonsec_gic_switch();
return 0;
diff --git a/include/configs/vexpress_ca15_tc2.h b/include/configs/vexpress_ca15_tc2.h
index 9e230ad..210a27c 100644
--- a/include/configs/vexpress_ca15_tc2.h
+++ b/include/configs/vexpress_ca15_tc2.h
@@ -32,5 +32,6 @@
#define CONFIG_BOOTP_VCI_STRING "U-boot.armv7.vexpress_ca15x2_tc2"
#define CONFIG_SYS_CLK_FREQ 24000000
+#define CONFIG_SYSFLAGS_ADDR 0x1c010030
#endif
--
1.7.12.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [U-Boot] [RFC PATCH 4/6] ARM: add SMP support for non-secure switch
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 4/6] ARM: add SMP support for non-secure switch Andre Przywara
@ 2013-04-26 22:13 ` Christoffer Dall
2013-05-06 13:19 ` Andre Przywara
0 siblings, 1 reply; 16+ messages in thread
From: Christoffer Dall @ 2013-04-26 22:13 UTC (permalink / raw)
To: u-boot
On Fri, Apr 26, 2013 at 6:14 AM, Andre Przywara
<andre.przywara@linaro.org> wrote:
> Currently the non-secure switch is only done for the boot processor.
> To later allow full SMP support, we have to switch all secondary
> cores into non-secure state also.
>
> So we add an entry point for secondary CPUs coming out of low-power
> state and make sure we put them into WFI again after having switched
> to non-secure state.
> For this we acknowledge and EOI the wake-up IPI, then go into WFI.
> Once being kicked out of it later, we sanity check that the start
> address has actually been changed (since another attempt to switch
> to non-secure would block the core) and jump to the new address.
>
> The actual CPU kick is done by sending an inter-processor interrupt
> via the GIC to all CPU interfaces except the requesting processor.
> The secondary cores will then setup their respective GIC CPU
> interface.
>
> The address secondary cores jump to is board specific, we provide
> the value here for the Versatile Express board.
>
> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> ---
> arch/arm/cpu/armv7/start.S | 27 ++++++++++++++++++++++++++-
> arch/arm/lib/virt-v7.c | 10 +++++++++-
> include/configs/vexpress_ca15_tc2.h | 1 +
> 3 files changed, 36 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
> index 401b0eb..2b47881 100644
> --- a/arch/arm/cpu/armv7/start.S
> +++ b/arch/arm/cpu/armv7/start.S
> @@ -563,8 +563,19 @@ fiq:
> #endif /* CONFIG_SPL_BUILD */
>
> /* Routine to initialize GIC CPU interface and switch to nonsecure state.
> + * Will be executed directly by secondary CPUs after coming out of
> + * WFI, or can be called directly by C code for CPU 0.
> + * Those two paths mandate to not use any stack and to only use registers
> + * r0-r3 to comply with both the C ABI and the requirement of SMP startup
> + * code.
> */
> .globl _nonsec_gic_switch
> +.globl _smp_pen
> +_smp_pen:
> + mrs r0, cpsr
> + orr r0, r0, #0xc0
> + msr cpsr, r0 @ disable interrupts
> + mov lr, #0 @ clear LR to mark secondary
> _nonsec_gic_switch:
> mrc p15, 4, r2, c15, c0, 0 @ r2 = PERIPHBASE
> add r3, r2, #0x1000 @ GIC dist i/f offset
> @@ -605,4 +616,18 @@ _nonsec_gic_switch:
> add r2, r2, #0x1000 @ GIC dist i/f offset
> str r1, [r2] @ allow private interrupts
>
> - mov pc, lr
> + cmp lr, #0
> + movne pc, lr @ CPU 0 to return
> + @ all others: go to sleep
> +_ack_int:
> + ldr r1, [r3, #0x0c] @ read GICD acknowledge
> + str r1, [r3, #0x10] @ write GICD EOI
> +
> + adr r1, _smp_pen
> +waitloop:
> + wfi
> + ldr r0, =CONFIG_SYSFLAGS_ADDR @ load start address
> + ldr r0, [r0]
> + cmp r0, r1 @ make sure we dont execute this code
> + beq waitloop @ again (due to a spurious wakeup)
> + mov pc, r0
> diff --git a/arch/arm/lib/virt-v7.c b/arch/arm/lib/virt-v7.c
> index 416ca29..5ca093a 100644
> --- a/arch/arm/lib/virt-v7.c
> +++ b/arch/arm/lib/virt-v7.c
> @@ -29,6 +29,7 @@
>
> /* the assembly routine doing the actual work in start.S */
> void _nonsec_gic_switch(void);
> +void _smp_pen(void);
>
> #define GICD_CTLR 0x000
> #define GICD_TYPER 0x004
> @@ -51,6 +52,7 @@ int armv7_switch_nonsec(void)
> unsigned int reg;
> volatile unsigned int *gicdptr;
> unsigned itlinesnr, i;
> + unsigned int *sysflags;
>
> /* check whether the CPU supports the security extensions */
> asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg));
> @@ -109,7 +111,13 @@ int armv7_switch_nonsec(void)
> for (i = 0; i <= itlinesnr; i++)
> gicdptr[GICD_IGROUPR0 / 4 + i] = (unsigned)-1;
>
> - /* call the non-sec switching code on this CPU */
> + /* now kick all CPUs (expect this one) by writing to GICD_SIGR */
> + sysflags = (void *)CONFIG_SYSFLAGS_ADDR;
> + sysflags[1] = (unsigned)-1;
> + sysflags[0] = (uintptr_t)_smp_pen;
> + gicdptr[GICD_SGIR / 4] = 1U << 24;
> +
> + /* call the non-sec switching code on this CPU also */
> _nonsec_gic_switch();
>
> return 0;
> diff --git a/include/configs/vexpress_ca15_tc2.h b/include/configs/vexpress_ca15_tc2.h
> index 9e230ad..210a27c 100644
> --- a/include/configs/vexpress_ca15_tc2.h
> +++ b/include/configs/vexpress_ca15_tc2.h
> @@ -32,5 +32,6 @@
> #define CONFIG_BOOTP_VCI_STRING "U-boot.armv7.vexpress_ca15x2_tc2"
>
> #define CONFIG_SYS_CLK_FREQ 24000000
> +#define CONFIG_SYSFLAGS_ADDR 0x1c010030
>
> #endif
> --
hmm, is all this likely to work across all armv7 cores? I imagined
that the SMP boot protocol could be potentially vastly different on
different implementations and this stuff would have to call into board
specific code...?
^ permalink raw reply [flat|nested] 16+ messages in thread* [U-Boot] [RFC PATCH 4/6] ARM: add SMP support for non-secure switch
2013-04-26 22:13 ` Christoffer Dall
@ 2013-05-06 13:19 ` Andre Przywara
2013-05-10 22:41 ` Christoffer Dall
0 siblings, 1 reply; 16+ messages in thread
From: Andre Przywara @ 2013-05-06 13:19 UTC (permalink / raw)
To: u-boot
On 04/27/2013 12:13 AM, Christoffer Dall wrote:
> On Fri, Apr 26, 2013 at 6:14 AM, Andre Przywara
> <andre.przywara@linaro.org> wrote:
>> Currently the non-secure switch is only done for the boot processor.
>> To later allow full SMP support, we have to switch all secondary
>> cores into non-secure state also.
>>
>> So we add an entry point for secondary CPUs coming out of low-power
>> state and make sure we put them into WFI again after having switched
>> to non-secure state.
>> For this we acknowledge and EOI the wake-up IPI, then go into WFI.
>> Once being kicked out of it later, we sanity check that the start
>> address has actually been changed (since another attempt to switch
>> to non-secure would block the core) and jump to the new address.
>>
>> The actual CPU kick is done by sending an inter-processor interrupt
>> via the GIC to all CPU interfaces except the requesting processor.
>> The secondary cores will then setup their respective GIC CPU
>> interface.
>>
>> The address secondary cores jump to is board specific, we provide
>> the value here for the Versatile Express board.
>>
>> Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
>> ---
>> arch/arm/cpu/armv7/start.S | 27 ++++++++++++++++++++++++++-
>> arch/arm/lib/virt-v7.c | 10 +++++++++-
>> include/configs/vexpress_ca15_tc2.h | 1 +
>> 3 files changed, 36 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
>> index 401b0eb..2b47881 100644
>> --- a/arch/arm/cpu/armv7/start.S
>> +++ b/arch/arm/cpu/armv7/start.S
>> @@ -563,8 +563,19 @@ fiq:
>> #endif /* CONFIG_SPL_BUILD */
>>
>> /* Routine to initialize GIC CPU interface and switch to nonsecure state.
>> + * Will be executed directly by secondary CPUs after coming out of
>> + * WFI, or can be called directly by C code for CPU 0.
>> + * Those two paths mandate to not use any stack and to only use registers
>> + * r0-r3 to comply with both the C ABI and the requirement of SMP startup
>> + * code.
>> */
>> .globl _nonsec_gic_switch
>> +.globl _smp_pen
>> +_smp_pen:
>> + mrs r0, cpsr
>> + orr r0, r0, #0xc0
>> + msr cpsr, r0 @ disable interrupts
>> + mov lr, #0 @ clear LR to mark secondary
>> _nonsec_gic_switch:
>> mrc p15, 4, r2, c15, c0, 0 @ r2 = PERIPHBASE
>> add r3, r2, #0x1000 @ GIC dist i/f offset
>> @@ -605,4 +616,18 @@ _nonsec_gic_switch:
>> add r2, r2, #0x1000 @ GIC dist i/f offset
>> str r1, [r2] @ allow private interrupts
>>
>> - mov pc, lr
>> + cmp lr, #0
>> + movne pc, lr @ CPU 0 to return
>> + @ all others: go to sleep
>> +_ack_int:
>> + ldr r1, [r3, #0x0c] @ read GICD acknowledge
>> + str r1, [r3, #0x10] @ write GICD EOI
>> +
>> + adr r1, _smp_pen
>> +waitloop:
>> + wfi
>> + ldr r0, =CONFIG_SYSFLAGS_ADDR @ load start address
>> + ldr r0, [r0]
>> + cmp r0, r1 @ make sure we dont execute this code
>> + beq waitloop @ again (due to a spurious wakeup)
>> + mov pc, r0
>> diff --git a/arch/arm/lib/virt-v7.c b/arch/arm/lib/virt-v7.c
>> index 416ca29..5ca093a 100644
>> --- a/arch/arm/lib/virt-v7.c
>> +++ b/arch/arm/lib/virt-v7.c
>> @@ -29,6 +29,7 @@
>>
>> /* the assembly routine doing the actual work in start.S */
>> void _nonsec_gic_switch(void);
>> +void _smp_pen(void);
>>
>> #define GICD_CTLR 0x000
>> #define GICD_TYPER 0x004
>> @@ -51,6 +52,7 @@ int armv7_switch_nonsec(void)
>> unsigned int reg;
>> volatile unsigned int *gicdptr;
>> unsigned itlinesnr, i;
>> + unsigned int *sysflags;
>>
>> /* check whether the CPU supports the security extensions */
>> asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg));
>> @@ -109,7 +111,13 @@ int armv7_switch_nonsec(void)
>> for (i = 0; i <= itlinesnr; i++)
>> gicdptr[GICD_IGROUPR0 / 4 + i] = (unsigned)-1;
>>
>> - /* call the non-sec switching code on this CPU */
>> + /* now kick all CPUs (expect this one) by writing to GICD_SIGR */
>> + sysflags = (void *)CONFIG_SYSFLAGS_ADDR;
>> + sysflags[1] = (unsigned)-1;
>> + sysflags[0] = (uintptr_t)_smp_pen;
>> + gicdptr[GICD_SGIR / 4] = 1U << 24;
>> +
>> + /* call the non-sec switching code on this CPU also */
>> _nonsec_gic_switch();
>>
>> return 0;
>> diff --git a/include/configs/vexpress_ca15_tc2.h b/include/configs/vexpress_ca15_tc2.h
>> index 9e230ad..210a27c 100644
>> --- a/include/configs/vexpress_ca15_tc2.h
>> +++ b/include/configs/vexpress_ca15_tc2.h
>> @@ -32,5 +32,6 @@
>> #define CONFIG_BOOTP_VCI_STRING "U-boot.armv7.vexpress_ca15x2_tc2"
>>
>> #define CONFIG_SYS_CLK_FREQ 24000000
>> +#define CONFIG_SYSFLAGS_ADDR 0x1c010030
>>
>> #endif
>> --
>
>
> hmm, is all this likely to work across all armv7 cores?
Probably not.
> I imagined that the SMP boot protocol could be potentially vastly different on
> different implementations and this stuff would have to call into board
> specific code...?
Right. For now I am trying to get this code upstream. Support for other
boards can then be merged in on demand. Looks like at least the Arndale
board can be kicked very similarly, only the SYSFLAGS address is
different. I am willing to re-architecture the SMP code as needed.
Regards,
Andre.
^ permalink raw reply [flat|nested] 16+ messages in thread* [U-Boot] [RFC PATCH 4/6] ARM: add SMP support for non-secure switch
2013-05-06 13:19 ` Andre Przywara
@ 2013-05-10 22:41 ` Christoffer Dall
0 siblings, 0 replies; 16+ messages in thread
From: Christoffer Dall @ 2013-05-10 22:41 UTC (permalink / raw)
To: u-boot
On Mon, May 06, 2013 at 03:19:40PM +0200, Andre Przywara wrote:
> On 04/27/2013 12:13 AM, Christoffer Dall wrote:
> >On Fri, Apr 26, 2013 at 6:14 AM, Andre Przywara
> ><andre.przywara@linaro.org> wrote:
> >>Currently the non-secure switch is only done for the boot processor.
> >>To later allow full SMP support, we have to switch all secondary
> >>cores into non-secure state also.
> >>
> >>So we add an entry point for secondary CPUs coming out of low-power
> >>state and make sure we put them into WFI again after having switched
> >>to non-secure state.
> >>For this we acknowledge and EOI the wake-up IPI, then go into WFI.
> >>Once being kicked out of it later, we sanity check that the start
> >>address has actually been changed (since another attempt to switch
> >>to non-secure would block the core) and jump to the new address.
> >>
> >>The actual CPU kick is done by sending an inter-processor interrupt
> >>via the GIC to all CPU interfaces except the requesting processor.
> >>The secondary cores will then setup their respective GIC CPU
> >>interface.
> >>
> >>The address secondary cores jump to is board specific, we provide
> >>the value here for the Versatile Express board.
> >>
> >>Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
> >>---
> >> arch/arm/cpu/armv7/start.S | 27 ++++++++++++++++++++++++++-
> >> arch/arm/lib/virt-v7.c | 10 +++++++++-
> >> include/configs/vexpress_ca15_tc2.h | 1 +
> >> 3 files changed, 36 insertions(+), 2 deletions(-)
> >>
> >>diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
> >>index 401b0eb..2b47881 100644
> >>--- a/arch/arm/cpu/armv7/start.S
> >>+++ b/arch/arm/cpu/armv7/start.S
> >>@@ -563,8 +563,19 @@ fiq:
> >> #endif /* CONFIG_SPL_BUILD */
> >>
> >> /* Routine to initialize GIC CPU interface and switch to nonsecure state.
> >>+ * Will be executed directly by secondary CPUs after coming out of
> >>+ * WFI, or can be called directly by C code for CPU 0.
> >>+ * Those two paths mandate to not use any stack and to only use registers
> >>+ * r0-r3 to comply with both the C ABI and the requirement of SMP startup
> >>+ * code.
> >> */
> >> .globl _nonsec_gic_switch
> >>+.globl _smp_pen
> >>+_smp_pen:
> >>+ mrs r0, cpsr
> >>+ orr r0, r0, #0xc0
> >>+ msr cpsr, r0 @ disable interrupts
> >>+ mov lr, #0 @ clear LR to mark secondary
> >> _nonsec_gic_switch:
> >> mrc p15, 4, r2, c15, c0, 0 @ r2 = PERIPHBASE
> >> add r3, r2, #0x1000 @ GIC dist i/f offset
> >>@@ -605,4 +616,18 @@ _nonsec_gic_switch:
> >> add r2, r2, #0x1000 @ GIC dist i/f offset
> >> str r1, [r2] @ allow private interrupts
> >>
> >>- mov pc, lr
> >>+ cmp lr, #0
> >>+ movne pc, lr @ CPU 0 to return
> >>+ @ all others: go to sleep
> >>+_ack_int:
> >>+ ldr r1, [r3, #0x0c] @ read GICD acknowledge
> >>+ str r1, [r3, #0x10] @ write GICD EOI
> >>+
> >>+ adr r1, _smp_pen
> >>+waitloop:
> >>+ wfi
> >>+ ldr r0, =CONFIG_SYSFLAGS_ADDR @ load start address
> >>+ ldr r0, [r0]
> >>+ cmp r0, r1 @ make sure we dont execute this code
> >>+ beq waitloop @ again (due to a spurious wakeup)
> >>+ mov pc, r0
> >>diff --git a/arch/arm/lib/virt-v7.c b/arch/arm/lib/virt-v7.c
> >>index 416ca29..5ca093a 100644
> >>--- a/arch/arm/lib/virt-v7.c
> >>+++ b/arch/arm/lib/virt-v7.c
> >>@@ -29,6 +29,7 @@
> >>
> >> /* the assembly routine doing the actual work in start.S */
> >> void _nonsec_gic_switch(void);
> >>+void _smp_pen(void);
> >>
> >> #define GICD_CTLR 0x000
> >> #define GICD_TYPER 0x004
> >>@@ -51,6 +52,7 @@ int armv7_switch_nonsec(void)
> >> unsigned int reg;
> >> volatile unsigned int *gicdptr;
> >> unsigned itlinesnr, i;
> >>+ unsigned int *sysflags;
> >>
> >> /* check whether the CPU supports the security extensions */
> >> asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg));
> >>@@ -109,7 +111,13 @@ int armv7_switch_nonsec(void)
> >> for (i = 0; i <= itlinesnr; i++)
> >> gicdptr[GICD_IGROUPR0 / 4 + i] = (unsigned)-1;
> >>
> >>- /* call the non-sec switching code on this CPU */
> >>+ /* now kick all CPUs (expect this one) by writing to GICD_SIGR */
> >>+ sysflags = (void *)CONFIG_SYSFLAGS_ADDR;
> >>+ sysflags[1] = (unsigned)-1;
> >>+ sysflags[0] = (uintptr_t)_smp_pen;
> >>+ gicdptr[GICD_SGIR / 4] = 1U << 24;
> >>+
> >>+ /* call the non-sec switching code on this CPU also */
> >> _nonsec_gic_switch();
> >>
> >> return 0;
> >>diff --git a/include/configs/vexpress_ca15_tc2.h b/include/configs/vexpress_ca15_tc2.h
> >>index 9e230ad..210a27c 100644
> >>--- a/include/configs/vexpress_ca15_tc2.h
> >>+++ b/include/configs/vexpress_ca15_tc2.h
> >>@@ -32,5 +32,6 @@
> >> #define CONFIG_BOOTP_VCI_STRING "U-boot.armv7.vexpress_ca15x2_tc2"
> >>
> >> #define CONFIG_SYS_CLK_FREQ 24000000
> >>+#define CONFIG_SYSFLAGS_ADDR 0x1c010030
> >>
> >> #endif
> >>--
> >
> >
> >hmm, is all this likely to work across all armv7 cores?
>
> Probably not.
>
> >I imagined that the SMP boot protocol could be potentially vastly different on
> >different implementations and this stuff would have to call into board
> >specific code...?
>
> Right. For now I am trying to get this code upstream. Support for
> other boards can then be merged in on demand. Looks like at least
> the Arndale board can be kicked very similarly, only the SYSFLAGS
> address is different. I am willing to re-architecture the SMP code
> as needed.
>
Sorry for the late response, I've been out sick.
So, I'm not very familiar with conventions and practices for the U-boot
project, but it seems quite clear to me that since these changes go in
arch/arm/lib/... paths those changes must be generic.
Therefore, I'm pretty sure that you need to factor out anything that's
specific to vexpress into a part of the code that's specific to vexpress
and thereby establish a board interface that generic code can call into
for other boards too, for example Arndale; in fact it would be cool if
you could show this working for both platforms at the same time, since
the working code is already available.
-Christoffer
^ permalink raw reply [flat|nested] 16+ messages in thread
* [U-Boot] [RFC PATCH 5/6] ARM: extend non-secure switch to also go into HYP mode
2013-04-26 13:14 [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support Andre Przywara
` (3 preceding siblings ...)
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 4/6] ARM: add SMP support for non-secure switch Andre Przywara
@ 2013-04-26 13:14 ` Andre Przywara
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 6/6] ARM: VExpress: enable ARMv7 virt support for VExpress A15 Andre Przywara
2013-04-26 13:18 ` [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support Peter Maydell
6 siblings, 0 replies; 16+ messages in thread
From: Andre Przywara @ 2013-04-26 13:14 UTC (permalink / raw)
To: u-boot
For the KVM and XEN hypervisors to be usable, we need to enter the
kernel in HYP mode. Now that we already are in non-secure state,
HYP mode switching is within short reach.
While doing the non-secure switch, we have to enable the HVC
instruction and setup the HYP mode HVBAR (while still secure).
The actual switch is done by dropping back from a HYP mode handler
without actually leaving HYP mode, so we introduce a new handler
routine in the exception vector table.
In the assembly switching routine - which we rename to hyp_gic_switch
on the way - we save and restore the banked LR and SP registers
around the hypercall to do the actual HYP mode switch.
The C routine first checks whether we are in HYP mode already and
also whether the virtualization extensions are available. It also
checks whether the HYP mode switch was finally successful.
The U-Boot command only adds and adjusts some error reporting.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
arch/arm/cpu/armv7/start.S | 34 +++++++++++++++++++++++-----------
arch/arm/include/asm/armv7.h | 2 +-
arch/arm/lib/virt-v7.c | 24 ++++++++++++++++--------
common/cmd_virt.c | 20 +++++++++++++-------
4 files changed, 53 insertions(+), 27 deletions(-)
diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S
index 2b47881..00890a3 100644
--- a/arch/arm/cpu/armv7/start.S
+++ b/arch/arm/cpu/armv7/start.S
@@ -41,7 +41,7 @@ _start: b reset
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
- ldr pc, _not_used
+ ldr pc, _hyp_trap
ldr pc, _irq
ldr pc, _fiq
#ifdef CONFIG_SPL_BUILD
@@ -49,7 +49,7 @@ _undefined_instruction: .word _undefined_instruction
_software_interrupt: .word _software_interrupt
_prefetch_abort: .word _prefetch_abort
_data_abort: .word _data_abort
-_not_used: .word _not_used
+_hyp_trap: .word _hyp_trap
_irq: .word _irq
_fiq: .word _fiq
_pad: .word 0x12345678 /* now 16*4=64 */
@@ -58,7 +58,7 @@ _undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
-_not_used: .word not_used
+_hyp_trap: .word hyp_trap
_irq: .word irq
_fiq: .word fiq
_pad: .word 0x12345678 /* now 16*4=64 */
@@ -502,12 +502,18 @@ software_interrupt:
mrc p15, 0, r1, c1, c1, 0 @ read SCR
bic r1, r1, #0x07f
orr r1, r1, #0x31 @ enable NS, AW, FW
+ mrc p15, 0, r0, c0, c1, 1 @ check for Virt ext
+ and r0, r0, #0xf000
+ cmp r0, #0x1000
+ orreq r1, r1, #0x100 @ allow HVC instruction
mrc p15, 0, r0, c12, c0, 0 @ save secure copy of VBAR
mcr p15, 0, r1, c1, c1, 0 @ write SCR, switch to non-sec
isb
mcr p15, 0, r0, c12, c0, 0 @ write non-secure copy of VBAR
+ mcreq p15, 4, r0, c12, c0, 0 @ write HYP mode HVBAR
+
movs pc, lr
.align 5
@@ -523,10 +529,9 @@ data_abort:
bl do_data_abort
.align 5
-not_used:
- get_bad_stack
- bad_save_user_regs
- bl do_not_used
+hyp_trap:
+ .byte 0x00, 0xe3, 0x0e, 0xe1 @ mrs lr, elr_hyp
+ mov pc, lr
#ifdef CONFIG_USE_IRQ
@@ -562,21 +567,21 @@ fiq:
#endif /* CONFIG_USE_IRQ */
#endif /* CONFIG_SPL_BUILD */
-/* Routine to initialize GIC CPU interface and switch to nonsecure state.
- * Will be executed directly by secondary CPUs after coming out of
+/* Routine to initialize GIC CPU interface, switch to nonsecure and to HYP
+ * mode. Will be executed directly by secondary CPUs after coming out of
* WFI, or can be called directly by C code for CPU 0.
* Those two paths mandate to not use any stack and to only use registers
* r0-r3 to comply with both the C ABI and the requirement of SMP startup
* code.
*/
-.globl _nonsec_gic_switch
+.globl _hyp_gic_switch
.globl _smp_pen
_smp_pen:
mrs r0, cpsr
orr r0, r0, #0xc0
msr cpsr, r0 @ disable interrupts
mov lr, #0 @ clear LR to mark secondary
-_nonsec_gic_switch:
+_hyp_gic_switch:
mrc p15, 4, r2, c15, c0, 0 @ r2 = PERIPHBASE
add r3, r2, #0x1000 @ GIC dist i/f offset
mvn r1, #0
@@ -616,6 +621,13 @@ _nonsec_gic_switch:
add r2, r2, #0x1000 @ GIC dist i/f offset
str r1, [r2] @ allow private interrupts
+ mov r2, lr
+ mov r1, sp
+ .byte 0x70, 0x00, 0x40, 0xe1 @ hvc #0
+ isb
+ mov sp, r1
+ mov lr, r2
+
cmp lr, #0
movne pc, lr @ CPU 0 to return
@ all others: go to sleep
diff --git a/arch/arm/include/asm/armv7.h b/arch/arm/include/asm/armv7.h
index 3567692..6c6955b 100644
--- a/arch/arm/include/asm/armv7.h
+++ b/arch/arm/include/asm/armv7.h
@@ -74,6 +74,6 @@ void v7_outer_cache_inval_all(void);
void v7_outer_cache_flush_range(u32 start, u32 end);
void v7_outer_cache_inval_range(u32 start, u32 end);
-int armv7_switch_nonsec(void);
+int armv7_switch_hyp(void);
#endif
diff --git a/arch/arm/lib/virt-v7.c b/arch/arm/lib/virt-v7.c
index 5ca093a..72481c6 100644
--- a/arch/arm/lib/virt-v7.c
+++ b/arch/arm/lib/virt-v7.c
@@ -3,6 +3,7 @@
* Andre Przywara, Linaro
*
* routines to push ARMv7 processors from secure into non-secure state
+ * and from non-secure SVC into HYP mode
* needed to enable ARMv7 virtualization for current hypervisors
*
* See file CREDITS for list of people who contributed to this
@@ -28,7 +29,7 @@
#include <asm/armv7.h>
/* the assembly routine doing the actual work in start.S */
-void _nonsec_gic_switch(void);
+void _hyp_gic_switch(void);
void _smp_pen(void);
#define GICD_CTLR 0x000
@@ -47,16 +48,20 @@ static inline unsigned int read_cpsr(void)
return reg;
}
-int armv7_switch_nonsec(void)
+int armv7_switch_hyp(void)
{
unsigned int reg;
volatile unsigned int *gicdptr;
unsigned itlinesnr, i;
unsigned int *sysflags;
- /* check whether the CPU supports the security extensions */
+ /* check whether we are in HYP mode already */
+ if ((read_cpsr() & 0x1F) == 0x1a)
+ return 1;
+
+ /* check whether the CPU supports the virtualization extensions */
asm("mrc p15, 0, %0, c0, c1, 1\n" : "=r"(reg));
- if ((reg & 0xF0) == 0)
+ if ((reg & 0xF000) != 0x1000)
return 2;
/* the timer frequency for the generic timer needs to be
@@ -77,8 +82,8 @@ int armv7_switch_nonsec(void)
*/
/* check whether we are an Cortex-A15 or A7.
- * The actual non-secure switch should work with all CPUs supporting
- * the security extension, but we need the GIC address,
+ * The actual HYP switch should work with all CPUs supporting
+ * the virtualization extension, but we need the GIC address,
* which we know only for sure for those two CPUs.
*/
asm("mrc p15, 0, %0, c0, c0, 0\n" : "=r"(reg));
@@ -117,8 +122,11 @@ int armv7_switch_nonsec(void)
sysflags[0] = (uintptr_t)_smp_pen;
gicdptr[GICD_SGIR / 4] = 1U << 24;
- /* call the non-sec switching code on this CPU also */
- _nonsec_gic_switch();
+ /* call the HYP switching code on this CPU also */
+ _hyp_gic_switch();
+
+ if ((read_cpsr() & 0x1F) != 0x1a)
+ return 5;
return 0;
}
diff --git a/common/cmd_virt.c b/common/cmd_virt.c
index 132b6b1..78b1aa1 100644
--- a/common/cmd_virt.c
+++ b/common/cmd_virt.c
@@ -2,8 +2,8 @@
* (C) Copyright 2013
* Andre Przywara, Linaro
*
- * command to switch an ARMv7 CPU with security extensions into
- * non-secure state
+ * command to switch an ARMv7 CPU with virtualization extensions into
+ * HYP mode to allow hypervisors to install themselves
*
* See file CREDITS for list of people who contributed to this
* project.
@@ -29,17 +29,20 @@
#include <asm/armv7.h>
-static int do_nonsec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int do_hyp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
unsigned int ret;
- ret = armv7_switch_nonsec();
+ ret = armv7_switch_hyp();
switch (ret) {
case 0:
break;
+ case 1:
+ printf("Already in HYP mode\n");
+ break;
case 2:
- printf("Security extensions not implemented.\n");
+ printf("Virtualization extensions not implemented.\n");
break;
case 3:
printf("CPU not supported, must be either Cortex-A15 or A7.\n");
@@ -47,13 +50,16 @@ static int do_nonsec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
case 4:
printf("PERIPHBASE is above 4 GB, cannot access this.\n");
break;
+ case 5:
+ printf("HYP mode switch not successful.\n");
+ break;
}
return ret;
}
U_BOOT_CMD(
- hypmode, 1, 0, do_nonsec,
- "switch ARM CPUs into non-secure state",
+ hypmode, 1, 0, do_hyp,
+ "switch ARM CPUs into HYP mode",
""
);
--
1.7.12.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [U-Boot] [RFC PATCH 6/6] ARM: VExpress: enable ARMv7 virt support for VExpress A15
2013-04-26 13:14 [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support Andre Przywara
` (4 preceding siblings ...)
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 5/6] ARM: extend non-secure switch to also go into HYP mode Andre Przywara
@ 2013-04-26 13:14 ` Andre Przywara
2013-04-26 13:18 ` [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support Peter Maydell
6 siblings, 0 replies; 16+ messages in thread
From: Andre Przywara @ 2013-04-26 13:14 UTC (permalink / raw)
To: u-boot
Enable the "hypmode" command for the Versatile Express TC2 board
with the virtualization capable Cortex-A15 CPU to allow booting
Xen or a KVM-enabled Linux kernel in HYP mode.
Signed-off-by: Andre Przywara <andre.przywara@linaro.org>
---
include/configs/vexpress_ca15_tc2.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/configs/vexpress_ca15_tc2.h b/include/configs/vexpress_ca15_tc2.h
index 210a27c..9df4400 100644
--- a/include/configs/vexpress_ca15_tc2.h
+++ b/include/configs/vexpress_ca15_tc2.h
@@ -31,6 +31,8 @@
#include "vexpress_common.h"
#define CONFIG_BOOTP_VCI_STRING "U-boot.armv7.vexpress_ca15x2_tc2"
+#define CONFIG_CMD_VIRT
+
#define CONFIG_SYS_CLK_FREQ 24000000
#define CONFIG_SYSFLAGS_ADDR 0x1c010030
--
1.7.12.1
^ permalink raw reply related [flat|nested] 16+ messages in thread* [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support
2013-04-26 13:14 [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support Andre Przywara
` (5 preceding siblings ...)
2013-04-26 13:14 ` [U-Boot] [RFC PATCH 6/6] ARM: VExpress: enable ARMv7 virt support for VExpress A15 Andre Przywara
@ 2013-04-26 13:18 ` Peter Maydell
2013-04-26 13:24 ` Andre Przywara
6 siblings, 1 reply; 16+ messages in thread
From: Peter Maydell @ 2013-04-26 13:18 UTC (permalink / raw)
To: u-boot
On 26 April 2013 14:14, Andre Przywara <andre.przywara@linaro.org> wrote:
> ARM CPUs with the virtualization extension have a new mode called
> HYP mode, which allows hypervisors to safely control and monitor
> guests. The current hypervisor (KVM and Xen) implementations
> require the kernel to be entered in that HYP mode.
>
> This patch series introduces a new U-Boot command called "hypmode"
> which can be used at any time at the U-Boot command prompt to
> switch the CPU into HYP mode - ideally this would be done before
> starting the kernel.
The obvious question here is "why do we need a new command?".
The kernel booting specification says "boot the kernel in
Hyp mode" so we should just always do that for booting Linux,
surely?
thanks
-- PMM
^ permalink raw reply [flat|nested] 16+ messages in thread* [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support
2013-04-26 13:18 ` [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support Peter Maydell
@ 2013-04-26 13:24 ` Andre Przywara
2013-04-26 13:42 ` Peter Maydell
0 siblings, 1 reply; 16+ messages in thread
From: Andre Przywara @ 2013-04-26 13:24 UTC (permalink / raw)
To: u-boot
On 04/26/2013 03:18 PM, Peter Maydell wrote:
> On 26 April 2013 14:14, Andre Przywara <andre.przywara@linaro.org> wrote:
>> ARM CPUs with the virtualization extension have a new mode called
>> HYP mode, which allows hypervisors to safely control and monitor
>> guests. The current hypervisor (KVM and Xen) implementations
>> require the kernel to be entered in that HYP mode.
>>
>> This patch series introduces a new U-Boot command called "hypmode"
>> which can be used at any time at the U-Boot command prompt to
>> switch the CPU into HYP mode - ideally this would be done before
>> starting the kernel.
>
> The obvious question here is "why do we need a new command?".
> The kernel booting specification says "boot the kernel in
> Hyp mode" so we should just always do that for booting Linux,
> surely?
Because it avoids regressions. I kind of feel uneasy to do a lot of
tinkering with secure state and the GIC unconditionally, especially if
enabled on many boards with virt-capable CPUs.
As written in question 2) later in that mail, I can also live with a
command to _dis_able the HYP mode switching in case it causes problems.
Regards,
Andre.
^ permalink raw reply [flat|nested] 16+ messages in thread
* [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support
2013-04-26 13:24 ` Andre Przywara
@ 2013-04-26 13:42 ` Peter Maydell
2013-04-26 14:14 ` Andre Przywara
0 siblings, 1 reply; 16+ messages in thread
From: Peter Maydell @ 2013-04-26 13:42 UTC (permalink / raw)
To: u-boot
On 26 April 2013 14:24, Andre Przywara <andre.przywara@linaro.org> wrote:
> On 04/26/2013 03:18 PM, Peter Maydell wrote:
>> The obvious question here is "why do we need a new command?".
>> The kernel booting specification says "boot the kernel in
>> Hyp mode" so we should just always do that for booting Linux,
>> surely?
> Because it avoids regressions. I kind of feel uneasy to do a lot of
> tinkering with secure state and the GIC unconditionally, especially if
> enabled on many boards with virt-capable CPUs.
There aren't exactly very many of those out there, so if we
default to "boot in HYP mode" then (a) KVM will just work
out of the box and (b) people doing u-boot ports to their
board will find any issues and be able to submit fixes.
If we don't turn it on by default then we'll end up stuck
in a world where KVM doesn't work on half the virt capable
boards out there.
I have no objection to a "turn this off" escape hatch if
you think it's useful.
-- PMM
^ permalink raw reply [flat|nested] 16+ messages in thread
* [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support
2013-04-26 13:42 ` Peter Maydell
@ 2013-04-26 14:14 ` Andre Przywara
2013-04-26 18:29 ` Christoffer Dall
0 siblings, 1 reply; 16+ messages in thread
From: Andre Przywara @ 2013-04-26 14:14 UTC (permalink / raw)
To: u-boot
On 04/26/2013 03:42 PM, Peter Maydell wrote:
> On 26 April 2013 14:24, Andre Przywara <andre.przywara@linaro.org> wrote:
>> On 04/26/2013 03:18 PM, Peter Maydell wrote:
>>> The obvious question here is "why do we need a new command?".
>>> The kernel booting specification says "boot the kernel in
>>> Hyp mode" so we should just always do that for booting Linux,
>>> surely?
>
>> Because it avoids regressions. I kind of feel uneasy to do a lot of
>> tinkering with secure state and the GIC unconditionally, especially if
>> enabled on many boards with virt-capable CPUs.
>
> There aren't exactly very many of those out there, so if we
> default to "boot in HYP mode" then (a) KVM will just work
> out of the box and (b) people doing u-boot ports to their
> board will find any issues and be able to submit fixes.
> If we don't turn it on by default then we'll end up stuck
> in a world where KVM doesn't work on half the virt capable
> boards out there.
OK, that's a point. I changed the code already and will include it in
the next revision.
Thanks,
Andre.
>
> I have no objection to a "turn this off" escape hatch if
> you think it's useful.
>
> -- PMM
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [U-Boot] [RFC PATCH 0/6] ARMv7: Add HYP mode switching support
2013-04-26 14:14 ` Andre Przywara
@ 2013-04-26 18:29 ` Christoffer Dall
0 siblings, 0 replies; 16+ messages in thread
From: Christoffer Dall @ 2013-04-26 18:29 UTC (permalink / raw)
To: u-boot
On Fri, Apr 26, 2013 at 7:14 AM, Andre Przywara
<andre.przywara@linaro.org> wrote:
> On 04/26/2013 03:42 PM, Peter Maydell wrote:
>> On 26 April 2013 14:24, Andre Przywara <andre.przywara@linaro.org> wrote:
>>> On 04/26/2013 03:18 PM, Peter Maydell wrote:
>>>> The obvious question here is "why do we need a new command?".
>>>> The kernel booting specification says "boot the kernel in
>>>> Hyp mode" so we should just always do that for booting Linux,
>>>> surely?
>>
>>> Because it avoids regressions. I kind of feel uneasy to do a lot of
>>> tinkering with secure state and the GIC unconditionally, especially if
>>> enabled on many boards with virt-capable CPUs.
>>
>> There aren't exactly very many of those out there, so if we
>> default to "boot in HYP mode" then (a) KVM will just work
>> out of the box and (b) people doing u-boot ports to their
>> board will find any issues and be able to submit fixes.
>> If we don't turn it on by default then we'll end up stuck
>> in a world where KVM doesn't work on half the virt capable
>> boards out there.
>
> OK, that's a point. I changed the code already and will include it in
> the next revision.
>
I strongly agree with Peter, and in fact I think it should only be a
compile time option, not a run-time option, only for those debugging
u-boot and a kernel on some new platform.
-Christoffer
^ permalink raw reply [flat|nested] 16+ messages in thread