@@ -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 */
@@ -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
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(-)