]> www.infradead.org Git - users/hch/configfs.git/commitdiff
KVM: arm64: nv: Honor guest hypervisor's FP/SVE traps in CPTR_EL2
authorOliver Upton <oliver.upton@linux.dev>
Thu, 20 Jun 2024 16:46:48 +0000 (16:46 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Thu, 20 Jun 2024 19:04:49 +0000 (19:04 +0000)
Start folding the guest hypervisor's FP/SVE traps into the value
programmed in hardware. Note that as of writing this is dead code, since
KVM does a full put() / load() for every nested exception boundary which
saves + flushes the FP/SVE state.

However, this will become useful when we can keep the guest's FP/SVE
state alive across a nested exception boundary and the host no longer
needs to conservatively program traps.

Reviewed-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20240620164653.1130714-12-oliver.upton@linux.dev
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/hyp/vhe/switch.c

index f4ce892edcd6ca5868574bafbead6692fb3e352a..fa6c27b6ad9959942ee791cacf21a422fae9dc3d 100644 (file)
@@ -67,6 +67,8 @@ static u64 __compute_hcr(struct kvm_vcpu *vcpu)
 
 static void __activate_cptr_traps(struct kvm_vcpu *vcpu)
 {
+       u64 cptr;
+
        /*
         * With VHE (HCR.E2H == 1), accesses to CPACR_EL1 are routed to
         * CPTR_EL2. In general, CPACR_EL1 has the same layout as CPTR_EL2,
@@ -85,6 +87,35 @@ static void __activate_cptr_traps(struct kvm_vcpu *vcpu)
                __activate_traps_fpsimd32(vcpu);
        }
 
+       /*
+        * Layer the guest hypervisor's trap configuration on top of our own if
+        * we're in a nested context.
+        */
+       if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu))
+               goto write;
+
+       cptr = vcpu_sanitised_cptr_el2(vcpu);
+
+       /*
+        * Pay attention, there's some interesting detail here.
+        *
+        * The CPTR_EL2.xEN fields are 2 bits wide, although there are only two
+        * meaningful trap states when HCR_EL2.TGE = 0 (running a nested guest):
+        *
+        *  - CPTR_EL2.xEN = x0, traps are enabled
+        *  - CPTR_EL2.xEN = x1, traps are disabled
+        *
+        * In other words, bit[0] determines if guest accesses trap or not. In
+        * the interest of simplicity, clear the entire field if the guest
+        * hypervisor has traps enabled to dispel any illusion of something more
+        * complicated taking place.
+        */
+       if (!(SYS_FIELD_GET(CPACR_ELx, FPEN, cptr) & BIT(0)))
+               val &= ~CPACR_ELx_FPEN;
+       if (!(SYS_FIELD_GET(CPACR_ELx, ZEN, cptr) & BIT(0)))
+               val &= ~CPACR_ELx_ZEN;
+
+write:
        write_sysreg(val, cpacr_el1);
 }