arm64: KVM: Switch to C-based stage2 init
authorMarc Zyngier <marc.zyngier@arm.com>
Thu, 29 Jan 2015 13:19:45 +0000 (13:19 +0000)
committerMarc Zyngier <marc.zyngier@arm.com>
Mon, 29 Feb 2016 18:34:15 +0000 (18:34 +0000)
There is no real need to leave the stage2 initialization as part
of the early HYP bootstrap, and we can easily postpone it to
the point where we can safely run C code.

This will help VHE, which doesn't need any of this bootstrap.

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/kvm/hyp-init.S
arch/arm64/kvm/hyp/Makefile
arch/arm64/kvm/hyp/s2-setup.c [new file with mode: 0644]

index 2ad8930e7eb311f6fcf0cccf9b2a3ef741350d32..1037392ae1341004fc3642e8bc37405dbe085c6e 100644 (file)
@@ -45,6 +45,8 @@ extern u64 __vgic_v3_get_ich_vtr_el2(void);
 
 extern u32 __kvm_get_mdcr_el2(void);
 
+extern void __init_stage2_translation(void);
+
 #endif
 
 #endif /* __ARM_KVM_ASM_H__ */
index fe86cf9f288b9e381f2fc608d3ea9d5a658a25eb..43688d93c75694f68f0e1336c9ce6e8fdb869220 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/types.h>
 #include <linux/kvm_types.h>
 #include <asm/kvm.h>
+#include <asm/kvm_asm.h>
 #include <asm/kvm_mmio.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -334,6 +335,7 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
 
 static inline void __cpu_init_stage2(void)
 {
+       kvm_call_hyp(__init_stage2_translation);
 }
 
 static inline void kvm_arch_hardware_disable(void) {}
index d073b5a216f72b1db65fbef79efd942b28df6f6e..7d8747c6427cdf474d1aac9b70c7abe51aece035 100644 (file)
@@ -87,26 +87,13 @@ __do_hyp_init:
 #endif
        /*
         * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS bits in
-        * TCR_EL2 and VTCR_EL2.
+        * TCR_EL2.
         */
        mrs     x5, ID_AA64MMFR0_EL1
        bfi     x4, x5, #16, #3
 
        msr     tcr_el2, x4
 
-       ldr     x4, =VTCR_EL2_FLAGS
-       bfi     x4, x5, #16, #3
-       /*
-        * Read the VMIDBits bits from ID_AA64MMFR1_EL1 and set the VS bit in
-        * VTCR_EL2.
-        */
-       mrs     x5, ID_AA64MMFR1_EL1
-       ubfx    x5, x5, #5, #1
-       lsl     x5, x5, #VTCR_EL2_VS
-       orr     x4, x4, x5
-
-       msr     vtcr_el2, x4
-
        mrs     x4, mair_el1
        msr     mair_el2, x4
        isb
index 826032bc3945ba266142f2a5a0d8367322d71a49..5326e664fd41c5bb73d3ce7377b05cb743ade57f 100644 (file)
@@ -12,3 +12,4 @@ obj-$(CONFIG_KVM_ARM_HOST) += switch.o
 obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o
 obj-$(CONFIG_KVM_ARM_HOST) += tlb.o
 obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o
+obj-$(CONFIG_KVM_ARM_HOST) += s2-setup.o
diff --git a/arch/arm64/kvm/hyp/s2-setup.c b/arch/arm64/kvm/hyp/s2-setup.c
new file mode 100644 (file)
index 0000000..17e8cc0
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 - 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/types.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
+
+#include "hyp.h"
+
+void __hyp_text __init_stage2_translation(void)
+{
+       u64 val = VTCR_EL2_FLAGS;
+       u64 tmp;
+
+       /*
+        * Read the PARange bits from ID_AA64MMFR0_EL1 and set the PS
+        * bits in VTCR_EL2. Amusingly, the PARange is 4 bits, while
+        * PS is only 3. Fortunately, bit 19 is RES0 in VTCR_EL2...
+        */
+       val |= (read_sysreg(id_aa64mmfr0_el1) & 7) << 16;
+
+       /*
+        * Read the VMIDBits bits from ID_AA64MMFR1_EL1 and set the VS
+        * bit in VTCR_EL2.
+        */
+       tmp = (read_sysreg(id_aa64mmfr1_el1) >> 4) & 0xf;
+       val |= (tmp == 2) ? VTCR_EL2_VS : 0;
+
+       write_sysreg(val, vtcr_el2);
+}