arm64: add hypervisor stub
authorMarc Zyngier <marc.zyngier@arm.com>
Fri, 19 Oct 2012 16:46:27 +0000 (17:46 +0100)
committerCatalin Marinas <catalin.marinas@arm.com>
Wed, 5 Dec 2012 11:26:49 +0000 (11:26 +0000)
If booted in EL2, install an dummy hypervisor whose only purpose
is to be replaced by a full fledged one.

A minimal API allows to:
- obtain the current HYP vectors (__hyp_get_vectors)
- set new HYP vectors (__hyp_set_vectors)

Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/virt.h
arch/arm64/kernel/Makefile
arch/arm64/kernel/head.S
arch/arm64/kernel/hyp-stub.S [new file with mode: 0644]

index f28547d..4398272 100644 (file)
@@ -33,6 +33,9 @@
  */
 extern u32 __boot_cpu_mode[2];
 
+void __hyp_set_vectors(phys_addr_t phys_vector_base);
+phys_addr_t __hyp_get_vectors(void);
+
 /* Reports the availability of HYP mode */
 static inline bool is_hyp_mode_available(void)
 {
index e2caff1..74239c3 100644 (file)
@@ -8,7 +8,8 @@ AFLAGS_head.o           := -DTEXT_OFFSET=$(TEXT_OFFSET)
 # Object file lists.
 arm64-obj-y            := cputable.o debug-monitors.o entry.o irq.o fpsimd.o   \
                           entry-fpsimd.o process.o ptrace.o setup.o signal.o   \
-                          sys.o stacktrace.o time.o traps.o io.o vdso.o
+                          sys.o stacktrace.o time.o traps.o io.o vdso.o        \
+                          hyp-stub.o
 
 arm64-obj-$(CONFIG_COMPAT)             += sys32.o kuser32.o signal32.o         \
                                           sys_compat.o
index bc6d991..5792749 100644 (file)
@@ -185,6 +185,10 @@ ENTRY(el2_setup)
        msr     hstr_el2, xzr                   // Disable CP15 traps to EL2
 #endif
 
+       /* Hypervisor stub */
+       adr     x0, __hyp_stub_vectors
+       msr     vbar_el2, x0
+
        /* spsr */
        mov     x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
                      PSR_MODE_EL1h)
diff --git a/arch/arm64/kernel/hyp-stub.S b/arch/arm64/kernel/hyp-stub.S
new file mode 100644 (file)
index 0000000..0959611
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Hypervisor stub
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ * Author:     Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+#include <asm/ptrace.h>
+#include <asm/virt.h>
+
+       .text
+       .align 11
+
+ENTRY(__hyp_stub_vectors)
+       ventry  el2_sync_invalid                // Synchronous EL2t
+       ventry  el2_irq_invalid                 // IRQ EL2t
+       ventry  el2_fiq_invalid                 // FIQ EL2t
+       ventry  el2_error_invalid               // Error EL2t
+
+       ventry  el2_sync_invalid                // Synchronous EL2h
+       ventry  el2_irq_invalid                 // IRQ EL2h
+       ventry  el2_fiq_invalid                 // FIQ EL2h
+       ventry  el2_error_invalid               // Error EL2h
+
+       ventry  el1_sync                        // Synchronous 64-bit EL1
+       ventry  el1_irq_invalid                 // IRQ 64-bit EL1
+       ventry  el1_fiq_invalid                 // FIQ 64-bit EL1
+       ventry  el1_error_invalid               // Error 64-bit EL1
+
+       ventry  el1_sync_invalid                // Synchronous 32-bit EL1
+       ventry  el1_irq_invalid                 // IRQ 32-bit EL1
+       ventry  el1_fiq_invalid                 // FIQ 32-bit EL1
+       ventry  el1_error_invalid               // Error 32-bit EL1
+ENDPROC(__hyp_stub_vectors)
+
+       .align 11
+
+el1_sync:
+       mrs     x1, esr_el2
+       lsr     x1, x1, #26
+       cmp     x1, #0x16
+       b.ne    2f                              // Not an HVC trap
+       cbz     x0, 1f
+       msr     vbar_el2, x0                    // Set vbar_el2
+       b       2f
+1:     mrs     x0, vbar_el2                    // Return vbar_el2
+2:     eret
+ENDPROC(el1_sync)
+
+.macro invalid_vector  label
+\label:
+       b \label
+ENDPROC(\label)
+.endm
+
+       invalid_vector  el2_sync_invalid
+       invalid_vector  el2_irq_invalid
+       invalid_vector  el2_fiq_invalid
+       invalid_vector  el2_error_invalid
+       invalid_vector  el1_sync_invalid
+       invalid_vector  el1_irq_invalid
+       invalid_vector  el1_fiq_invalid
+       invalid_vector  el1_error_invalid
+
+/*
+ * __hyp_set_vectors: Call this after boot to set the initial hypervisor
+ * vectors as part of hypervisor installation.  On an SMP system, this should
+ * be called on each CPU.
+ *
+ * x0 must be the physical address of the new vector table, and must be
+ * 2KB aligned.
+ *
+ * Before calling this, you must check that the stub hypervisor is installed
+ * everywhere, by waiting for any secondary CPUs to be brought up and then
+ * checking that is_hyp_mode_available() 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_el2 will contain junk,
+ * so you will need to set that to something sensible at the new hypervisor's
+ * initialisation entry point.
+ */
+
+ENTRY(__hyp_get_vectors)
+       mov     x0, xzr
+       // fall through
+ENTRY(__hyp_set_vectors)
+       hvc     #0
+       ret
+ENDPROC(__hyp_get_vectors)
+ENDPROC(__hyp_set_vectors)