Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64...
[linux-2.6-microblaze.git] / virt / kvm / arm / mmu.c
index e2e5eff..1c44aa3 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/virt.h>
+#include <asm/system_misc.h>
 
 #include "trace.h"
 
@@ -1430,6 +1431,25 @@ out:
                kvm_set_pfn_accessed(pfn);
 }
 
+static bool is_abort_sea(unsigned long fault_status)
+{
+       switch (fault_status) {
+       case FSC_SEA:
+       case FSC_SEA_TTW0:
+       case FSC_SEA_TTW1:
+       case FSC_SEA_TTW2:
+       case FSC_SEA_TTW3:
+       case FSC_SECC:
+       case FSC_SECC_TTW0:
+       case FSC_SECC_TTW1:
+       case FSC_SECC_TTW2:
+       case FSC_SECC_TTW3:
+               return true;
+       default:
+               return false;
+       }
+}
+
 /**
  * kvm_handle_guest_abort - handles all 2nd stage aborts
  * @vcpu:      the VCPU pointer
@@ -1452,19 +1472,29 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
        gfn_t gfn;
        int ret, idx;
 
+       fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
+
+       fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
+
+       /*
+        * The host kernel will handle the synchronous external abort. There
+        * is no need to pass the error into the guest.
+        */
+       if (is_abort_sea(fault_status)) {
+               if (!handle_guest_sea(fault_ipa, kvm_vcpu_get_hsr(vcpu)))
+                       return 1;
+       }
+
        is_iabt = kvm_vcpu_trap_is_iabt(vcpu);
        if (unlikely(!is_iabt && kvm_vcpu_dabt_isextabt(vcpu))) {
                kvm_inject_vabt(vcpu);
                return 1;
        }
 
-       fault_ipa = kvm_vcpu_get_fault_ipa(vcpu);
-
        trace_kvm_guest_fault(*vcpu_pc(vcpu), kvm_vcpu_get_hsr(vcpu),
                              kvm_vcpu_get_hfar(vcpu), fault_ipa);
 
        /* Check the stage-2 fault is trans. fault or write fault */
-       fault_status = kvm_vcpu_trap_get_fault_type(vcpu);
        if (fault_status != FSC_FAULT && fault_status != FSC_PERM &&
            fault_status != FSC_ACCESS) {
                kvm_err("Unsupported FSC: EC=%#x xFSC=%#lx ESR_EL2=%#lx\n",