diff mbox

[03/10] fixup! ARM: virt: Initial Virtualization Extensions support

Message ID 1329329763-31508-4-git-send-email-dave.martin@linaro.org
State Not Applicable
Headers show

Commit Message

Dave Martin Feb. 15, 2012, 6:15 p.m. UTC
Instead of counting how many CPUs the hypervisor stub was installed
on, we simply record what mode the primary CPU was booted and set a
flag if an inconsistency is detected.

Signed-off-by: Dave Martin <dave.martin@linaro.org>
---
 arch/arm/include/asm/virt.h |   27 ++++++++++++++++++++++-
 arch/arm/kernel/hyp-stub.S  |   51 ++++++++++++++++++++++++++++--------------
 2 files changed, 60 insertions(+), 18 deletions(-)
diff mbox

Patch

diff --git a/arch/arm/include/asm/virt.h b/arch/arm/include/asm/virt.h
index 77d7a65..3659eb5 100644
--- a/arch/arm/include/asm/virt.h
+++ b/arch/arm/include/asm/virt.h
@@ -30,8 +30,33 @@ 
 #ifndef VIRT_H
 #define VIRT_H
 
-extern int __hyp_stub_install_count;
+#include <asm/ptrace.h>
+
+#ifndef __ASSEMBLY__
+
+/*
+ * __boot_cpu_mode records what mode the primary CPU was booted in.
+ * A correctly-implemented bootloader must start all CPUs in the same mode:
+ * if it fails to do this, the flag BOOT_CPU_MODE_MISMATCH is set to indicate
+ * that some CPU(s) were booted in a different mode.
+ *
+ * This allows the kernel to flag an error when the secondaries have come up.
+ */
+extern int __boot_cpu_mode;
 
 void __hyp_set_vectors(unsigned long phys_vector_base);
 
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Helper macro to extract the mode the primary CPU mode booted in from
+ * __boot_cpu_mode:
+ */
+#define BOOT_CPU_MODE_PRIMARY(x) (x & MODE_MASK)
+#define BOOT_CPU_MODE_MISMATCH (1<<31)
+
+#define BOOT_CPU_MODE_HAVE_HYP(x)			\
+	(BOOT_CPU_MODE_PRIMARY(x) == HYP_MODE &&	\
+		!((x) & BOOT_CPU_MODE_MISMATCH))
+
 #endif /* ! VIRT_H */
diff --git a/arch/arm/kernel/hyp-stub.S b/arch/arm/kernel/hyp-stub.S
index ec16e46..5c5f49f 100644
--- a/arch/arm/kernel/hyp-stub.S
+++ b/arch/arm/kernel/hyp-stub.S
@@ -30,6 +30,7 @@ 
 #include <linux/init.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/virt.h>
 
 /*
  * Hypervisor stub installation functions.
@@ -41,19 +42,32 @@ 
 @ Call this from the primary CPU
 ENTRY(__hyp_stub_install)
 	adr	r4, 1f
-	ldr	r5, .L__hyp_stub_install_count_offset
-	mov	r6, #0
-	str	r6, [r4, r5]		@ reset __hyp_stub_install_count to 0
+	ldr	r5, .L__boot_cpu_mode_offset
+	mrs	r6, cpsr
+	and	r6, r6, #MODE_MASK
+	str	r6, [r4, r5]		@ record the CPU mode we were booted in
 ENDPROC(__hyp_stub_install)
 
 	@ fall through...
 
 @ Secondary CPUs should call here
 ENTRY(__hyp_stub_install_secondary)
+	adr	r4, 1f
+	ldr	r5, .L__boot_cpu_mode_offset
 	mrs	r6, cpsr
-	and	r7, r6, #MODE_MASK
-	cmp	r7, #HYP_MODE
-	bxne	lr			@ give up if not in hyp mode
+	and	r6, r6, #MODE_MASK
+	ldr	r7, [r4, r5]
+	cmp	r6, r7
+	beq	2f			@ matches primary CPU boot mode?
+
+	orr	r6, r6, #BOOT_CPU_MODE_MISMATCH
+	str	r6, [r4, r5]
+	bx	lr			@ record what happened and give up
+
+	@ otherwise ...
+
+2:	cmp	r6, #HYP_MODE
+	bxne	lr			@ give up if the CPU is not in HYP mode
 
 /*
  * BUG: hyp mode init needs to happen here:
@@ -67,11 +81,12 @@  ENTRY(__hyp_stub_install_secondary)
  * for that)
  */
 	@ Now install the hypervisor stub:
+
 	adr	r7, __hyp_stub_vectors
 	mcr	p15, 4, r7, c12, c0, 0	@ set hypervisor vector base (HVBAR)
 
 	adr	r4, 1f
-	ldr	r5, .L__hyp_stub_install_count_offset
+	ldr	r5, .L__boot_cpu_mode_offset
 1:	ldr	r7, [r4, r5]
 	add	r7, r7, #1
 	str	r7, [r4, r5]		@ increment __hyp_stub_install_count
@@ -102,14 +117,16 @@  ENDPROC(__hyp_stub_do_trap)
  * r0 must be 32-byte aligned.
  *
  * Before calling this, you must check that the stub hypervisor is installed
- * everywhere, by checking that __hyp_stub_install_count == the number of
- * booted CPUs.  If not, there is a pre-existing hypervisor, some CPUs failed
- * to boot, or something else went wrong... in such cases, trying to install
- * a new hypervisor is unlikely to work as desired.
+ * everywhere, by waiting for any secondary CPUs to be brought up and then
+ * checking that BOOT_CPU_MODE_HAVE_HYP(__boot_cpu_mode) is true.
+ *
+ * If not, there is a pre-existing hypervisor, some CPUs failed to boot, or
+ * something else went wrong... in such cases, trying to install a new
+ * hypervisor is unlikely to work as desired.
  *
  * When you call into your shiny new hypervisor, sp_hyp will contain junk,
- * so you will need to set that to something sensible when calling into the
- * new hypervisor to initialise it.
+ * so you will need to set that to something sensible at the new hypervisor's
+ * initialisation entry point.
  */
 ENTRY(__hyp_set_vectors)
 	hvc	#0
@@ -117,8 +134,8 @@  ENTRY(__hyp_set_vectors)
 ENDPROC(__hyp_set_vectors)
 
 .align 2
-.L__hyp_stub_install_count_offset:
-	.long	__hyp_stub_install_count - 1b
+.L__boot_cpu_mode_offset:
+	.long	__boot_cpu_mode - 1b
 
 .align 5
 __hyp_stub_vectors:
@@ -134,5 +151,5 @@  ENDPROC(__hyp_stub_vectors)
 
 .bss
 
-__hyp_stub_install_count:
-	.long	 0
+ENTRY(__boot_cpu_mode)
+	.long	0