]> www.infradead.org Git - nvme.git/commitdiff
KVM: arm64: nv: Ensure correct VL is loaded before saving SVE state
authorOliver Upton <oliver.upton@linux.dev>
Thu, 20 Jun 2024 16:46:44 +0000 (16:46 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Thu, 20 Jun 2024 19:02:40 +0000 (19:02 +0000)
It is possible that the guest hypervisor has selected a smaller VL than
the maximum for its nested guest. As such, ZCR_EL2 may be configured for
a different VL when exiting a nested guest.

Set ZCR_EL2 (via the EL1 alias) to the maximum VL for the VM before
saving SVE state as the SVE save area is dimensioned by the max VL.

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

index 0815ff0347f5e0d7291268018a6821f3a32312b3..c53e5b14038dce9d22490c7b5c7d7e9e31969133 100644 (file)
@@ -195,11 +195,14 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu)
                         * Note that this means that at guest exit ZCR_EL1 is
                         * not necessarily the same as on guest entry.
                         *
-                        * Restoring the VL isn't needed in VHE mode since
-                        * ZCR_EL2 (accessed via ZCR_EL1) would fulfill the same
-                        * role when doing the save from EL2.
+                        * ZCR_EL2 holds the guest hypervisor's VL when running
+                        * a nested guest, which could be smaller than the
+                        * max for the vCPU. Similar to above, we first need to
+                        * switch to a VL consistent with the layout of the
+                        * vCPU's SVE state. KVM support for NV implies VHE, so
+                        * using the ZCR_EL1 alias is safe.
                         */
-                       if (!has_vhe())
+                       if (!has_vhe() || (vcpu_has_nv(vcpu) && !is_hyp_ctxt(vcpu)))
                                sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1,
                                                       SYS_ZCR_EL1);
                }