A vCPU sees masked CCSIDRs when the physical CPUs has mismatched
cache types or the vCPU has 32-bit EL1. Perform the same masking for
ioctls too so that ioctls shows values consistent with the values the
vCPU actually sees.

Signed-off-by: Akihiko Odaki <akihiko.od...@daynix.com>
---
 arch/arm64/include/asm/kvm_emulate.h |  9 ++++--
 arch/arm64/kvm/sys_regs.c            | 45 ++++++++++++++--------------
 2 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_emulate.h 
b/arch/arm64/include/asm/kvm_emulate.h
index 9bdba47f7e14..b45cf8903190 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -61,6 +61,12 @@ static __always_inline bool vcpu_el1_is_32bit(struct 
kvm_vcpu *vcpu)
 }
 #endif
 
+static inline bool vcpu_cache_overridden(struct kvm_vcpu *vcpu)
+{
+       return cpus_have_const_cap(ARM64_MISMATCHED_CACHE_TYPE) ||
+              vcpu_el1_is_32bit(vcpu);
+}
+
 static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 {
        vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
@@ -88,8 +94,7 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
        if (vcpu_el1_is_32bit(vcpu))
                vcpu->arch.hcr_el2 &= ~HCR_RW;
 
-       if (cpus_have_const_cap(ARM64_MISMATCHED_CACHE_TYPE) ||
-           vcpu_el1_is_32bit(vcpu))
+       if (vcpu_cache_overridden(vcpu))
                vcpu->arch.hcr_el2 |= HCR_TID2;
 
        if (kvm_has_mte(vcpu->kvm))
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f4a7c5abcbca..273ed1aaa6b3 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -88,7 +88,7 @@ static u32 cache_levels;
 #define CSSELR_MAX 14
 
 /* Which cache CCSIDR represents depends on CSSELR value. */
-static u32 get_ccsidr(u32 csselr)
+static u32 get_ccsidr(struct kvm_vcpu *vcpu, u32 csselr)
 {
        u32 ccsidr;
 
@@ -99,6 +99,21 @@ static u32 get_ccsidr(u32 csselr)
        ccsidr = read_sysreg(ccsidr_el1);
        local_irq_enable();
 
+       /*
+        * Guests should not be doing cache operations by set/way at all, and
+        * for this reason, we trap them and attempt to infer the intent, so
+        * that we can flush the entire guest's address space at the appropriate
+        * time.
+        * To prevent this trapping from causing performance problems, let's
+        * expose the geometry of all data and unified caches (which are
+        * guaranteed to be PIPT and thus non-aliasing) as 1 set and 1 way.
+        * [If guests should attempt to infer aliasing properties from the
+        * geometry (which is not permitted by the architecture), they would
+        * only do so for virtually indexed caches.]
+        */
+       if (vcpu_cache_overridden(vcpu) && !(csselr & 1)) // data or unified 
cache
+               ccsidr &= ~GENMASK(27, 3);
+
        return ccsidr;
 }
 
@@ -1300,22 +1315,8 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct 
sys_reg_params *p,
                return write_to_read_only(vcpu, p, r);
 
        csselr = vcpu_read_sys_reg(vcpu, CSSELR_EL1);
-       p->regval = get_ccsidr(csselr);
+       p->regval = get_ccsidr(vcpu, csselr);
 
-       /*
-        * Guests should not be doing cache operations by set/way at all, and
-        * for this reason, we trap them and attempt to infer the intent, so
-        * that we can flush the entire guest's address space at the appropriate
-        * time.
-        * To prevent this trapping from causing performance problems, let's
-        * expose the geometry of all data and unified caches (which are
-        * guaranteed to be PIPT and thus non-aliasing) as 1 set and 1 way.
-        * [If guests should attempt to infer aliasing properties from the
-        * geometry (which is not permitted by the architecture), they would
-        * only do so for virtually indexed caches.]
-        */
-       if (!(csselr & 1)) // data or unified cache
-               p->regval &= ~GENMASK(27, 3);
        return true;
 }
 
@@ -2686,7 +2687,7 @@ static bool is_valid_cache(u32 val)
        }
 }
 
-static int demux_c15_get(u64 id, void __user *uaddr)
+static int demux_c15_get(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
 {
        u32 val;
        u32 __user *uval = uaddr;
@@ -2705,13 +2706,13 @@ static int demux_c15_get(u64 id, void __user *uaddr)
                if (!is_valid_cache(val))
                        return -ENOENT;
 
-               return put_user(get_ccsidr(val), uval);
+               return put_user(get_ccsidr(vcpu, val), uval);
        default:
                return -ENOENT;
        }
 }
 
-static int demux_c15_set(u64 id, void __user *uaddr)
+static int demux_c15_set(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr)
 {
        u32 val, newval;
        u32 __user *uval = uaddr;
@@ -2734,7 +2735,7 @@ static int demux_c15_set(u64 id, void __user *uaddr)
                        return -EFAULT;
 
                /* This is also invariant: you can't change it. */
-               if (newval != get_ccsidr(val))
+               if (newval != get_ccsidr(vcpu, val))
                        return -EINVAL;
                return 0;
        default:
@@ -2773,7 +2774,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const 
struct kvm_one_reg *reg
        int err;
 
        if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
-               return demux_c15_get(reg->id, uaddr);
+               return demux_c15_get(vcpu, reg->id, uaddr);
 
        err = get_invariant_sys_reg(reg->id, uaddr);
        if (err != -ENOENT)
@@ -2817,7 +2818,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const 
struct kvm_one_reg *reg
        int err;
 
        if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
-               return demux_c15_set(reg->id, uaddr);
+               return demux_c15_set(vcpu, reg->id, uaddr);
 
        err = set_invariant_sys_reg(reg->id, uaddr);
        if (err != -ENOENT)
-- 
2.38.1

_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Reply via email to