[U-Boot] [PATCH v4 7/8] ARM: extend non-secure switch to also go into HYP mode

2013-08-09 Thread Andre Przywara
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 our new secure exception vector table.

In the assembly switching routine 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 bootm command part only adds and adjusts some error reporting.

Signed-off-by: Andre Przywara andre.przyw...@linaro.org
---
 arch/arm/cpu/armv7/Makefile  |  2 +-
 arch/arm/cpu/armv7/nonsec_virt.S | 43 +++-
 arch/arm/cpu/armv7/virt-v7.c | 37 ++
 arch/arm/include/asm/armv7.h |  6 --
 arch/arm/lib/bootm.c |  7 ++-
 5 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
index 5813e87..c20df3d 100644
--- a/arch/arm/cpu/armv7/Makefile
+++ b/arch/arm/cpu/armv7/Makefile
@@ -36,7 +36,7 @@ ifneq 
($(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONF
 SOBJS  += lowlevel_init.o
 endif
 
-ifneq ($(CONFIG_ARMV7_NONSEC),)
+ifneq ($(CONFIG_ARMV7_NONSEC)$(CONFIG_ARMV7_VIRT),)
 SOBJS  += nonsec_virt.o
 COBJS  += virt-v7.o
 endif
diff --git a/arch/arm/cpu/armv7/nonsec_virt.S b/arch/arm/cpu/armv7/nonsec_virt.S
index a88fa6b..fb1651d 100644
--- a/arch/arm/cpu/armv7/nonsec_virt.S
+++ b/arch/arm/cpu/armv7/nonsec_virt.S
@@ -1,5 +1,5 @@
 /*
- * code for switching cores into non-secure state
+ * code for switching cores into non-secure state and into HYP mode
  *
  * Copyright (c) 2013  Andre Przywara andre.przyw...@linaro.org
  *
@@ -28,15 +28,16 @@
 #include asm/armv7.h
 
 .arch_extension sec
+.arch_extension virt
 
-/* the vector table for secure state */
+/* the vector table for secure state and HYP mode */
 _monitor_vectors:
.word 0 /* reset */
.word 0 /* undef */
adr pc, _secure_monitor
.word 0
.word 0
-   .word 0
+   adr pc, _hyp_trap
.word 0
.word 0
.word 0 /* pad */
@@ -54,10 +55,27 @@ _secure_monitor:
bic r1, r1, #0x4e   @ clear IRQ, FIQ, EA, nET bits
orr r1, r1, #0x31   @ enable NS, AW, FW bits
 
+#ifdef CONFIG_ARMV7_VIRT
+   mrc p15, 0, r0, c0, c1, 1   @ read ID_PFR1
+   and r0, r0, #CPUID_ARM_VIRT_MASK@ mask virtualization bits
+   cmp r0, #(1  CPUID_ARM_VIRT_SHIFT)
+   orreq   r1, r1, #0x100  @ allow HVC instruction
+#endif
+
mcr p15, 0, r1, c1, c1, 0   @ write SCR (with NS bit set)
 
+#ifdef CONFIG_ARMV7_VIRT
+   mrceq   p15, 0, r0, c12, c0, 1  @ get MVBAR value
+   mcreq   p15, 4, r0, c12, c0, 0  @ write HVBAR
+#endif
+
movspc, lr  @ return to non-secure SVC
 
+_hyp_trap:
+   mrs lr, elr_hyp @ for older asm: .byte 0x00, 0xe3, 0x0e, 0xe1
+   mov pc, lr  @ do no switch modes, but
+   @ return to caller
+
 /*
  * 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
@@ -72,9 +90,13 @@ ENTRY(_smp_pen)
mcr p15, 0, r1, c12, c0, 0  @ set VBAR
 
bl  _nonsec_init
+   mov r12, r0 @ save GICC address
+#ifdef CONFIG_ARMV7_VIRT
+   bl  _switch_to_hyp
+#endif
 
-   ldr r1, [r0, #GICC_IAR] @ acknowledge IPI
-   str r1, [r0, #GICC_EOIR]@ signal end of interrupt
+   ldr r1, [r12, #GICC_IAR]@ acknowledge IPI
+   str r1, [r12, #GICC_EOIR]   @ signal end of interrupt
 
adr r0, _smp_pen@ do not use this address again
b   smp_waitloop@ wait for IPIs, board specific
@@ -161,3 +183,14 @@ ENTRY(_nonsec_init)
 
bx  lr
 ENDPROC(_nonsec_init)
+
+ENTRY(_switch_to_hyp)
+   mov r0, lr
+   mov r1, sp  @ save SVC copy of LR and SP
+   isb
+   hvc #0   @ for older asm: .byte 0x70, 0x00, 0x40, 0xe1
+   mov sp, r1
+   mov lr, r0  @ restore SVC copy of LR and SP
+
+   bx  lr
+ENDPROC(_switch_to_hyp)
diff --git a/arch/arm/cpu/armv7/virt-v7.c b/arch/arm/cpu/armv7/virt-v7.c
index 50f0a3a..4dc8c45 

Re: [U-Boot] [PATCH v4 7/8] ARM: extend non-secure switch to also go into HYP mode

2013-08-09 Thread Christoffer Dall
On Fri, Aug 09, 2013 at 05:03:11PM +0200, Andre Przywara wrote:
 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 our new secure exception vector table.
 
 In the assembly switching routine 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 bootm command part only adds and adjusts some error reporting.
 
 Signed-off-by: Andre Przywara andre.przyw...@linaro.org
 ---
  arch/arm/cpu/armv7/Makefile  |  2 +-
  arch/arm/cpu/armv7/nonsec_virt.S | 43 
 +++-
  arch/arm/cpu/armv7/virt-v7.c | 37 ++
  arch/arm/include/asm/armv7.h |  6 --
  arch/arm/lib/bootm.c |  7 ++-
  5 files changed, 86 insertions(+), 9 deletions(-)
 
 diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile
 index 5813e87..c20df3d 100644
 --- a/arch/arm/cpu/armv7/Makefile
 +++ b/arch/arm/cpu/armv7/Makefile
 @@ -36,7 +36,7 @@ ifneq 
 ($(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONF
  SOBJS+= lowlevel_init.o
  endif
  
 -ifneq ($(CONFIG_ARMV7_NONSEC),)
 +ifneq ($(CONFIG_ARMV7_NONSEC)$(CONFIG_ARMV7_VIRT),)
  SOBJS+= nonsec_virt.o
  COBJS+= virt-v7.o
  endif
 diff --git a/arch/arm/cpu/armv7/nonsec_virt.S 
 b/arch/arm/cpu/armv7/nonsec_virt.S
 index a88fa6b..fb1651d 100644
 --- a/arch/arm/cpu/armv7/nonsec_virt.S
 +++ b/arch/arm/cpu/armv7/nonsec_virt.S
 @@ -1,5 +1,5 @@
  /*
 - * code for switching cores into non-secure state
 + * code for switching cores into non-secure state and into HYP mode
   *
   * Copyright (c) 2013Andre Przywara andre.przyw...@linaro.org
   *
 @@ -28,15 +28,16 @@
  #include asm/armv7.h
  
  .arch_extension sec
 +.arch_extension virt
  
 -/* the vector table for secure state */
 +/* the vector table for secure state and HYP mode */
  _monitor_vectors:
   .word 0 /* reset */
   .word 0 /* undef */
   adr pc, _secure_monitor
   .word 0
   .word 0
 - .word 0
 + adr pc, _hyp_trap
   .word 0
   .word 0
   .word 0 /* pad */
 @@ -54,10 +55,27 @@ _secure_monitor:
   bic r1, r1, #0x4e   @ clear IRQ, FIQ, EA, nET bits
   orr r1, r1, #0x31   @ enable NS, AW, FW bits
  
 +#ifdef CONFIG_ARMV7_VIRT
 + mrc p15, 0, r0, c0, c1, 1   @ read ID_PFR1
 + and r0, r0, #CPUID_ARM_VIRT_MASK@ mask virtualization bits
 + cmp r0, #(1  CPUID_ARM_VIRT_SHIFT)
 + orreq   r1, r1, #0x100  @ allow HVC instruction
 +#endif
 +
   mcr p15, 0, r1, c1, c1, 0   @ write SCR (with NS bit set)
  
 +#ifdef CONFIG_ARMV7_VIRT
 + mrceq   p15, 0, r0, c12, c0, 1  @ get MVBAR value
 + mcreq   p15, 4, r0, c12, c0, 0  @ write HVBAR
 +#endif
 +
   movspc, lr  @ return to non-secure SVC
  
 +_hyp_trap:
 + mrs lr, elr_hyp @ for older asm: .byte 0x00, 0xe3, 0x0e, 0xe1

I see you kep this as is, oh well.

 + mov pc, lr  @ do no switch modes, but
 + @ return to caller
 +
  /*
   * 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
 @@ -72,9 +90,13 @@ ENTRY(_smp_pen)
   mcr p15, 0, r1, c12, c0, 0  @ set VBAR
  
   bl  _nonsec_init
 + mov r12, r0 @ save GICC address
 +#ifdef CONFIG_ARMV7_VIRT
 + bl  _switch_to_hyp
 +#endif
  
 - ldr r1, [r0, #GICC_IAR] @ acknowledge IPI
 - str r1, [r0, #GICC_EOIR]@ signal end of interrupt
 + ldr r1, [r12, #GICC_IAR]@ acknowledge IPI
 + str r1, [r12, #GICC_EOIR]   @ signal end of interrupt
  
   adr r0, _smp_pen@ do not use this address again
   b   smp_waitloop@ wait for IPIs, board specific
 @@ -161,3 +183,14 @@ ENTRY(_nonsec_init)
  
   bx  lr
  ENDPROC(_nonsec_init)
 +
 +ENTRY(_switch_to_hyp)
 + mov r0, lr
 + mov r1, sp  @ save SVC copy of LR and SP
 + isb
 + hvc #0   @ for older asm: .byte 0x70, 0x00, 0x40, 0xe1
 + mov sp, r1
 + mov lr, r0