KVM: arm64: Move S1PTW S2 fault logic out of io_mem_abort()
authorWill Deacon <will@kernel.org>
Wed, 29 Jul 2020 10:28:21 +0000 (11:28 +0100)
committerMarc Zyngier <maz@kernel.org>
Thu, 30 Jul 2020 15:02:37 +0000 (16:02 +0100)
To allow for re-injection of stage-2 faults on stage-1 page-table walks
due to either a missing or read-only memslot, move the triage logic out
of io_mem_abort() and into kvm_handle_guest_abort(), where these aborts
can be handled before anything else.

Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Quentin Perret <qperret@google.com>
Link: https://lore.kernel.org/r/20200729102821.23392-5-will@kernel.org
arch/arm64/kvm/mmio.c
arch/arm64/kvm/mmu.c

index 4e03667..58de2ae 100644 (file)
@@ -145,12 +145,6 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
                return -ENOSYS;
        }
 
-       /* Page table accesses IO mem: tell guest to fix its TTBR */
-       if (kvm_vcpu_dabt_iss1tw(vcpu)) {
-               kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
-               return 1;
-       }
-
        /*
         * Prepare MMIO operation. First decode the syndrome data we get
         * from the CPU. Then try if some in-kernel emulation feels
index 85b0ec9..dc84646 100644 (file)
@@ -2105,12 +2105,23 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
        hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable);
        write_fault = kvm_is_write_fault(vcpu);
        if (kvm_is_error_hva(hva) || (write_fault && !writable)) {
+               /*
+                * The guest has put either its instructions or its page-tables
+                * somewhere it shouldn't have. Userspace won't be able to do
+                * anything about this (there's no syndrome for a start), so
+                * re-inject the abort back into the guest.
+                */
                if (is_iabt) {
-                       /* Prefetch Abort on I/O address */
                        ret = -ENOEXEC;
                        goto out;
                }
 
+               if (kvm_vcpu_dabt_iss1tw(vcpu)) {
+                       kvm_inject_dabt(vcpu, kvm_vcpu_get_hfar(vcpu));
+                       ret = 1;
+                       goto out_unlock;
+               }
+
                /*
                 * Check for a cache maintenance operation. Since we
                 * ended-up here, we know it is outside of any memory