not support these instructions and requires the kernel to be
          built with binutils >= 2.25.
 
+config ARM64_VHE
+       bool "Enable support for Virtualization Host Extensions (VHE)"
+       default y
+       help
+         Virtualization Host Extensions (VHE) allow the kernel to run
+         directly at EL2 (instead of EL1) on processors that support
+         it. This leads to better performance for KVM, as they reduce
+         the cost of the world switch.
+
+         Selecting this option allows the VHE feature to be detected
+         at runtime, and does not affect processors that do not
+         implement this feature.
+
 endmenu
 
 endmenu
 
 #include <asm/cache.h>
 #include <asm/cputype.h>
 #include <asm/kernel-pgtable.h>
+#include <asm/kvm_arm.h>
 #include <asm/memory.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/pgtable.h>
        isb
        ret
 
+2:
+#ifdef CONFIG_ARM64_VHE
+       /*
+        * Check for VHE being present. For the rest of the EL2 setup,
+        * x2 being non-zero indicates that we do have VHE, and that the
+        * kernel is intended to run at EL2.
+        */
+       mrs     x2, id_aa64mmfr1_el1
+       ubfx    x2, x2, #8, #4
+#else
+       mov     x2, xzr
+#endif
+
        /* Hyp configuration. */
-2:     mov     x0, #(1 << 31)                  // 64-bit EL1
+       mov     x0, #HCR_RW                     // 64-bit EL1
+       cbz     x2, set_hcr
+       orr     x0, x0, #HCR_TGE                // Enable Host Extensions
+       orr     x0, x0, #HCR_E2H
+set_hcr:
        msr     hcr_el2, x0
+       isb
 
        /* Generic timers. */
        mrs     x0, cnthctl_el2
        /* Stage-2 translation */
        msr     vttbr_el2, xzr
 
+       cbz     x2, install_el2_stub
+
+       mov     w20, #BOOT_CPU_MODE_EL2         // This CPU booted in EL2
+       isb
+       ret
+
+install_el2_stub:
        /* Hypervisor stub */
        adrp    x0, __hyp_stub_vectors
        add     x0, x0, #:lo12:__hyp_stub_vectors