arm/arm64: KVM: Handle out-of-RAM cache maintenance as a NOP
authorMarc Zyngier <marc.zyngier@arm.com>
Fri, 29 Jan 2016 15:01:28 +0000 (15:01 +0000)
committerSasha Levin <alexander.levin@verizon.com>
Thu, 24 Nov 2016 01:59:49 +0000 (20:59 -0500)
[ Upstream commit 57c841f131ef295b583365d2fddd6b0d16e82c10 ]

So far, our handling of cache maintenance by VA has been pretty
simple: Either the access is in the guest RAM and generates a S2
fault, which results in the page being mapped RW, or we go down
the io_mem_abort() path, and nuke the guest.

The first one is fine, but the second one is extremely weird.
Treating the CM as an I/O is wrong, and nothing in the ARM ARM
indicates that we should generate a fault for something that
cannot end-up in the cache anyway (even if the guest maps it,
it will keep on faulting at stage-2 for emulation).

So let's just skip this instruction, and let the guest get away
with it.

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
arch/arm/include/asm/kvm_emulate.h
arch/arm/kvm/mmu.c
arch/arm64/include/asm/kvm_emulate.h

index a9c80a2ea1a779ffdbcd5d56014b1b2fbbd0381b..642934a5ae9b156bd50d78864a4b5026b1aa3ba1 100644 (file)
@@ -131,6 +131,11 @@ static inline bool kvm_vcpu_dabt_iss1tw(struct kvm_vcpu *vcpu)
        return kvm_vcpu_get_hsr(vcpu) & HSR_DABT_S1PTW;
 }
 
+static inline bool kvm_vcpu_dabt_is_cm(struct kvm_vcpu *vcpu)
+{
+       return !!(kvm_vcpu_get_hsr(vcpu) & HSR_DABT_CM);
+}
+
 /* Get Access Size from a data abort */
 static inline int kvm_vcpu_dabt_get_as(struct kvm_vcpu *vcpu)
 {
index a33af44230da967dfffe8d71de81fe8890fa1888..4681b6832d9f9941c18fc6f1cf8e374107cf1827 100644 (file)
@@ -1434,6 +1434,22 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
                        goto out_unlock;
                }
 
+               /*
+                * Check for a cache maintenance operation. Since we
+                * ended-up here, we know it is outside of any memory
+                * slot. But we can't find out if that is for a device,
+                * or if the guest is just being stupid. The only thing
+                * we know for sure is that this range cannot be cached.
+                *
+                * So let's assume that the guest is just being
+                * cautious, and skip the instruction.
+                */
+               if (kvm_vcpu_dabt_is_cm(vcpu)) {
+                       kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+                       ret = 1;
+                       goto out_unlock;
+               }
+
                /*
                 * The IPA is reported as [MAX:12], so we need to
                 * complement it with the bottom 12 bits from the
index 3ca894ecf699b33693e214479ca196bced5fa0c3..b10ba3fc46d1d97b607dc99d6afbf0e5e1cf1e2e 100644 (file)
@@ -178,6 +178,11 @@ static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
        return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_S1PTW);
 }
 
+static inline bool kvm_vcpu_dabt_is_cm(const struct kvm_vcpu *vcpu)
+{
+       return !!(kvm_vcpu_get_hsr(vcpu) & ESR_ELx_CM);
+}
+
 static inline int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
 {
        return 1 << ((kvm_vcpu_get_hsr(vcpu) & ESR_ELx_SAS) >> ESR_ELx_SAS_SHIFT);