On Tue, 23 Dec 2025 at 01:23, Mark Brown <[email protected]> wrote: > > SME introduces a mode called streaming mode where the Z, P and optionally > FFR registers can be accessed using the SVE instructions but with the SME > vector length. Reflect this in the ABI for accessing the guest registers by > making the vector length for the vcpu reflect the vector length that would > be seen by the guest were it running, using the SME vector length when the > guest is configured for streaming mode. > > Since SME may be present without SVE we also update the existing checks for > access to the Z, P and V registers to check for either SVE or streaming > mode. When not in streaming mode the guest floating point state may be > accessed via the V registers. > > Any VMM that supports SME must be aware of the need to configure streaming > mode prior to writing the floating point registers that this creates. > > Signed-off-by: Mark Brown <[email protected]> > --- > arch/arm64/kvm/guest.c | 38 ++++++++++++++++++++++++++++++++++---- > 1 file changed, 34 insertions(+), 4 deletions(-) > > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c > index 2a1fdcb0ec49..90dcacb35f01 100644 > --- a/arch/arm64/kvm/guest.c > +++ b/arch/arm64/kvm/guest.c > @@ -73,6 +73,11 @@ static u64 core_reg_offset_from_id(u64 id) > return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | > KVM_REG_ARM_CORE); > } > > +static bool vcpu_has_sve_regs(const struct kvm_vcpu *vcpu) > +{ > + return vcpu_has_sve(vcpu) || vcpu_in_streaming_mode(vcpu); > +} > + > static int core_reg_size_from_offset(const struct kvm_vcpu *vcpu, u64 off) > { > int size; > @@ -110,9 +115,10 @@ static int core_reg_size_from_offset(const struct > kvm_vcpu *vcpu, u64 off) > /* > * The KVM_REG_ARM64_SVE regs must be used instead of > * KVM_REG_ARM_CORE for accessing the FPSIMD V-registers on > - * SVE-enabled vcpus: > + * SVE-enabled vcpus or when a SME enabled vcpu is in > + * streaming mode: > */ > - if (vcpu_has_sve(vcpu) && core_reg_offset_is_vreg(off)) > + if (vcpu_has_sve_regs(vcpu) && core_reg_offset_is_vreg(off)) > return -EINVAL; > > return size; > @@ -426,6 +432,24 @@ struct vec_state_reg_region { > unsigned int upad; /* extra trailing padding in user memory */ > }; > > +/* > + * We represent the Z and P registers to userspace using either the > + * SVE or SME vector length, depending on which features the guest has > + * and if the guest is in streaming mode. > + */ > +static unsigned int vcpu_sve_cur_vq(struct kvm_vcpu *vcpu) > +{ > + unsigned int vq = 0; > + > + if (vcpu_has_sve(vcpu)) > + vq = vcpu_sve_max_vq(vcpu); > + > + if (vcpu_in_streaming_mode(vcpu)) > + vq = vcpu_sme_max_vq(vcpu); > + > + return vq; > +} > + > /* > * Validate SVE register ID and get sanitised bounds for user/kernel SVE > * register copy > @@ -466,7 +490,7 @@ static int sve_reg_to_region(struct vec_state_reg_region > *region, > if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0)
Should this be vcpu_has_sve_regs()? (zreg range) > return -ENOENT; > > - vq = vcpu_sve_max_vq(vcpu); > + vq = vcpu_sve_cur_vq(vcpu); > > reqoffset = SVE_SIG_ZREG_OFFSET(vq, reg_num) - > SVE_SIG_REGS_OFFSET; > @@ -476,7 +500,7 @@ static int sve_reg_to_region(struct vec_state_reg_region > *region, > if (!vcpu_has_sve(vcpu) || (reg->id & SVE_REG_SLICE_MASK) > 0) And should this also be vcpu_has_sve_regs()? (preg range) Should you also handle FFR here, considering that in streaming mode it's optional? Cheers, /fuad > return -ENOENT; > > - vq = vcpu_sve_max_vq(vcpu); > + vq = vcpu_sve_cur_vq(vcpu); > > reqoffset = SVE_SIG_PREG_OFFSET(vq, reg_num) - > SVE_SIG_REGS_OFFSET; > @@ -515,6 +539,9 @@ static int get_sve_reg(struct kvm_vcpu *vcpu, const > struct kvm_one_reg *reg) > if (!kvm_arm_vcpu_vec_finalized(vcpu)) > return -EPERM; > > + if (!vcpu_has_sve_regs(vcpu)) > + return -EBUSY; > + > if (copy_to_user(uptr, vcpu->arch.sve_state + region.koffset, > region.klen) || > clear_user(uptr + region.klen, region.upad)) > @@ -541,6 +568,9 @@ static int set_sve_reg(struct kvm_vcpu *vcpu, const > struct kvm_one_reg *reg) > if (!kvm_arm_vcpu_vec_finalized(vcpu)) > return -EPERM; > > + if (!vcpu_has_sve_regs(vcpu)) > + return -EBUSY; > + > if (copy_from_user(vcpu->arch.sve_state + region.koffset, uptr, > region.klen)) > return -EFAULT; > > -- > 2.47.3 >
