[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CA+EHjTyovGEkb6svw-=wR=DF52j-wWTawJ5a19EuvSt4i9Re2Q@mail.gmail.com>
Date: Mon, 12 Jan 2026 18:35:00 +0000
From: Fuad Tabba <tabba@...gle.com>
To: Mark Brown <broonie@...nel.org>
Cc: Marc Zyngier <maz@...nel.org>, Joey Gouly <joey.gouly@....com>,
Catalin Marinas <catalin.marinas@....com>, Suzuki K Poulose <suzuki.poulose@....com>,
Will Deacon <will@...nel.org>, Paolo Bonzini <pbonzini@...hat.com>, Jonathan Corbet <corbet@....net>,
Shuah Khan <shuah@...nel.org>, Oliver Upton <oupton@...nel.org>, Dave Martin <Dave.Martin@....com>,
Mark Rutland <mark.rutland@....com>, Ben Horgan <ben.horgan@....com>,
linux-arm-kernel@...ts.infradead.org, kvmarm@...ts.linux.dev,
linux-kernel@...r.kernel.org, kvm@...r.kernel.org, linux-doc@...r.kernel.org,
linux-kselftest@...r.kernel.org, Peter Maydell <peter.maydell@...aro.org>,
Eric Auger <eric.auger@...hat.com>
Subject: Re: [PATCH v9 20/30] KVM: arm64: Support userspace access to
streaming mode Z and P registers
On Tue, 23 Dec 2025 at 01:23, Mark Brown <broonie@...nel.org> 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 <broonie@...nel.org>
> ---
> 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
>
Powered by blists - more mailing lists