Merge tag 'kvmarm-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmar...
[linux-2.6-microblaze.git] / arch / arm64 / kvm / hyp / include / hyp / switch.h
index 426ef65..313a8fa 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/barrier.h>
 #include <asm/cpufeature.h>
+#include <asm/extable.h>
 #include <asm/kprobes.h>
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
@@ -29,6 +30,9 @@
 
 extern const char __hyp_panic_string[];
 
+extern struct exception_table_entry __start___kvm_ex_table;
+extern struct exception_table_entry __stop___kvm_ex_table;
+
 /* Check whether the FP regs were dirtied while in the host-side run loop: */
 static inline bool update_fp_enabled(struct kvm_vcpu *vcpu)
 {
@@ -122,11 +126,6 @@ static inline void ___deactivate_traps(struct kvm_vcpu *vcpu)
        }
 }
 
-static inline void __activate_vm(struct kvm_s2_mmu *mmu)
-{
-       __load_guest_stage2(mmu);
-}
-
 static inline bool __translate_far_to_hpfar(u64 far, u64 *hpfar)
 {
        u64 par, tmp;
@@ -142,10 +141,10 @@ static inline bool __translate_far_to_hpfar(u64 far, u64 *hpfar)
         * saved the guest context yet, and we may return early...
         */
        par = read_sysreg(par_el1);
-       asm volatile("at s1e1r, %0" : : "r" (far));
-       isb();
-
-       tmp = read_sysreg(par_el1);
+       if (!__kvm_at("s1e1r", far))
+               tmp = read_sysreg(par_el1);
+       else
+               tmp = SYS_PAR_EL1_F; /* back to the guest */
        write_sysreg(par, par_el1);
 
        if (unlikely(tmp & SYS_PAR_EL1_F))
@@ -373,6 +372,8 @@ static inline bool esr_is_ptrauth_trap(u32 esr)
        ctxt_sys_reg(ctxt, key ## KEYHI_EL1) = __val;                   \
 } while(0)
 
+DECLARE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt);
+
 static inline bool __hyp_handle_ptrauth(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpu_context *ctxt;
@@ -382,7 +383,7 @@ static inline bool __hyp_handle_ptrauth(struct kvm_vcpu *vcpu)
            !esr_is_ptrauth_trap(kvm_vcpu_get_esr(vcpu)))
                return false;
 
-       ctxt = &__hyp_this_cpu_ptr(kvm_host_data)->host_ctxt;
+       ctxt = this_cpu_ptr(&kvm_hyp_ctxt);
        __ptrauth_save_key(ctxt, APIA);
        __ptrauth_save_key(ctxt, APIB);
        __ptrauth_save_key(ctxt, APDA);
@@ -445,7 +446,7 @@ static inline bool fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
                        kvm_vcpu_trap_get_fault_type(vcpu) == FSC_FAULT &&
                        kvm_vcpu_dabt_isvalid(vcpu) &&
                        !kvm_vcpu_abt_issea(vcpu) &&
-                       !kvm_vcpu_dabt_iss1tw(vcpu);
+                       !kvm_vcpu_abt_iss1tw(vcpu);
 
                if (valid) {
                        int ret = __vgic_v2_perform_cpuif_access(vcpu);
@@ -475,37 +476,31 @@ exit:
        return false;
 }
 
-static inline bool __needs_ssbd_off(struct kvm_vcpu *vcpu)
+static inline void __kvm_unexpected_el2_exception(void)
 {
-       if (!cpus_have_final_cap(ARM64_SSBD))
-               return false;
+       extern char __guest_exit_panic[];
+       unsigned long addr, fixup;
+       struct exception_table_entry *entry, *end;
+       unsigned long elr_el2 = read_sysreg(elr_el2);
 
-       return !(vcpu->arch.workaround_flags & VCPU_WORKAROUND_2_FLAG);
-}
+       entry = hyp_symbol_addr(__start___kvm_ex_table);
+       end = hyp_symbol_addr(__stop___kvm_ex_table);
 
-static inline void __set_guest_arch_workaround_state(struct kvm_vcpu *vcpu)
-{
-#ifdef CONFIG_ARM64_SSBD
-       /*
-        * The host runs with the workaround always present. If the
-        * guest wants it disabled, so be it...
-        */
-       if (__needs_ssbd_off(vcpu) &&
-           __hyp_this_cpu_read(arm64_ssbd_callback_required))
-               arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, 0, NULL);
-#endif
-}
+       while (entry < end) {
+               addr = (unsigned long)&entry->insn + entry->insn;
+               fixup = (unsigned long)&entry->fixup + entry->fixup;
 
-static inline void __set_host_arch_workaround_state(struct kvm_vcpu *vcpu)
-{
-#ifdef CONFIG_ARM64_SSBD
-       /*
-        * If the guest has disabled the workaround, bring it back on.
-        */
-       if (__needs_ssbd_off(vcpu) &&
-           __hyp_this_cpu_read(arm64_ssbd_callback_required))
-               arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_2, 1, NULL);
-#endif
+               if (addr != elr_el2) {
+                       entry++;
+                       continue;
+               }
+
+               write_sysreg(fixup, elr_el2);
+               return;
+       }
+
+       /* Trigger a panic after restoring the hyp context. */
+       write_sysreg(__guest_exit_panic, elr_el2);
 }
 
 #endif /* __ARM64_KVM_HYP_SWITCH_H__ */