From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 60F15233941; Sat, 23 May 2026 08:44:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779525865; cv=none; b=UGduzEu6PFGM9EC7Qvj6ITVNFHEkcb8iCCs1Nde1A+9k93W/AjN0mGjH1HdEI0n2Il9Mmx2P5Cu5BnJJ79tsUoYKEmiLjYKmqVlW9uziqheyNkFlo7UQ1QOBJ8B4Sf5erk1DCLbnvaBa8uncCZikFKOcrBmGBbc3509Cce2n0DE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779525865; c=relaxed/simple; bh=80gmJzfafW5v0pD4rSYeqGkisuxd/UsImo1RzYeZcLo=; h=Date:Message-ID:From:To:Cc:Subject:In-Reply-To:References: MIME-Version:Content-Type; b=Cv/l+1JpywosXTBUCvtZYbPcLr6ut7AHfIRQwc3Y2QFRzuunM8kx9NgoXyCNZH9MlSJg4U4Agucdrtpnd/GfI9XDmVOledB0x7mQm46tSsVtXNnbIXmBLKHrAYUrPamCb9ejeP6DMfOSydLZ25uG1IGLF5X9hu5t1Ox2nJsZrzk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=h5lJQaoX; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="h5lJQaoX" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D40821F00A3A; Sat, 23 May 2026 08:44:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1779525863; bh=Wjd5EPtpM354Dd7ZDs5Vo2HEh22G1p5pQw/m/3w/sQY=; h=Date:From:To:Cc:Subject:In-Reply-To:References; b=h5lJQaoX6ktuOV9HMIQg+/BaKYiIGAlXy94RLLCWuZglA/2mPOJXIEBs+iMJXrJVd 0/fGFGs4huMFIOh2mwzI/lKWng4pW6mqAH1UR0AF3kxXzJFzAtGqM1ZkgwGW5vTVQZ N9JGxX0Sb2mXb+y60ZfQJIgZzIBmK+/U9H5/cAgDRpntmBFUnlnNqZD54uZcQ+LgB1 zTKkOPK1KM3cewEDhp6FhQ5+x/fgFYc/TUjLfbNGYJcfcM1s71jtpEyPTRXLbOkeSd BL7rWa3ubIkAKjNm9Tz0bk3VRXK0MpQ2F7Zi96gvGyah7w78zoZebbW6nXHe053Pq5 CAp8Fy346D4dA== Received: from sofa.misterjones.org ([185.219.108.64] helo=lobster-girl.misterjones.org) by disco-boy.misterjones.org with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1wQhy1-00000005VBn-2DfZ; Sat, 23 May 2026 08:44:21 +0000 Date: Sat, 23 May 2026 09:47:38 +0100 Message-ID: <87h5nya4wl.wl-maz@kernel.org> From: Marc Zyngier To: Mark Brown Cc: Oliver Upton , Joey Gouly , Steffen Eiden , Suzuki K Poulose , Catalin Marinas , Will Deacon , Mark Rutland , linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org Subject: Re: [PATCH] KVM: arm64: Preserve all guest ZCR_EL2.LEN values In-Reply-To: <20260522-kvm-arm64-fix-zcr-len-nv-v1-1-ec254e9078cf@kernel.org> References: <20260522-kvm-arm64-fix-zcr-len-nv-v1-1-ec254e9078cf@kernel.org> User-Agent: Wanderlust/2.15.9 (Almost Unreal) SEMI-EPG/1.14.7 (Harue) FLIM-LB/1.14.9 (=?UTF-8?B?R29qxY0=?=) APEL-LB/10.8 EasyPG/1.0.0 Emacs/30.1 (aarch64-unknown-linux-gnu) MULE/6.0 (HANACHIRUSATO) Precedence: bulk X-Mailing-List: kvmarm@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Content-Type: text/plain; charset=US-ASCII X-SA-Exim-Connect-IP: 185.219.108.64 X-SA-Exim-Rcpt-To: broonie@kernel.org, oupton@kernel.org, joey.gouly@arm.com, seiden@linux.ibm.com, suzuki.poulose@arm.com, catalin.marinas@arm.com, will@kernel.org, mark.rutland@arm.com, linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org X-SA-Exim-Mail-From: maz@kernel.org X-SA-Exim-Scanned: No (on disco-boy.misterjones.org); SAEximRunCond expanded to false On Fri, 22 May 2026 19:00:04 +0100, Mark Brown wrote: > > Since b3d29a823099 ("KVM: arm64: nv: Handle ZCR_EL2 traps") when guests > write to ZCR_EL2 we have clamped the value of ZCR_EL2.LEN to be at most > that configuring the maximum guest VL. That's not strictly true. This is only clamped when accessed as ZCR_EL2. A VHE guest will happily use the ZCR_EL1 accessor for the same register, and not see the truncation. This has ripple effects down the line, where the full value will be used at load time. > This is not the behaviour the > architecture documents for ZCR_EL2.LEN, the expectation is that all bits > will be read as written. Further, writing values larger than the largest > available vector length is part of the documented procedure for enumerating > the supported vector lengths so we expect to see this happen in practice. > > The reasoning for the current behaviour is not specifically articulated, my > best guess is that it is intended to ensure that the guest can not see an > effective VL greater than the maximum that has been configured. This can > instead be achieved by configuring ZCR_EL2 when loading guest state: > > - When running at EL0 or EL1 configure ZCR_EL2.LEN to the minimum of the > guest ZCR_EL2.LEN and vcpu_sve_max_vq(vcpu)-1. This is not EL0 or EL1. This is when in a nested context (i.e. running a L2 guest), as EL0 exists for L1 as well. > - When running at EL2 configure the maximum VL for the guest in > ZCR_EL2.LEN like we do for non-nested guests and load the guest > ZCR_EL2 into ZCR_EL1. > > This will ensure that the guest sees both the ZCR_EL2.LEN value which it > wrote and the effective VL that resulting from the values it has configured > in ZCR_ELx.LEN. > > Currently all other bits in ZCR_EL2 are either RES0 or RAZ/WI, values > written are sanitised based on this. Only for the direct writes to ZCR_EL2, as they are trapping. I don't see any sanitisation for writes using the ZCR_EL1 accessor, which is the common case. This needs fixing at the same time. > > Fixes: b3d29a823099 ("KVM: arm64: nv: Handle ZCR_EL2 traps") > Signed-off-by: Mark Brown Given the nature of the bug, this needs a Cc: stable. > --- > arch/arm64/kvm/hyp/include/hyp/switch.h | 8 ++++---- > arch/arm64/kvm/sys_regs.c | 6 +----- > 2 files changed, 5 insertions(+), 9 deletions(-) > > diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h > index bf0eb5e43427..fd277cb70967 100644 > --- a/arch/arm64/kvm/hyp/include/hyp/switch.h > +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h > @@ -501,11 +501,11 @@ static inline void fpsimd_lazy_switch_to_guest(struct kvm_vcpu *vcpu) > return; > > if (vcpu_has_sve(vcpu)) { > + zcr_el2 = vcpu_sve_max_vq(vcpu) - 1; > + > /* A guest hypervisor may restrict the effective max VL. */ > - if (is_nested_ctxt(vcpu)) > - zcr_el2 = __vcpu_sys_reg(vcpu, ZCR_EL2); > - else > - zcr_el2 = vcpu_sve_max_vq(vcpu) - 1; > + if (is_nested_ctxt(vcpu) && !is_hyp_ctxt(vcpu)) > + zcr_el2 = min(zcr_el2, __vcpu_sys_reg(vcpu, ZCR_EL2)); Why the change in the condition guarding this? Given the definition of is_nested_ctxt(), this seems unnecessary. > > write_sysreg_el2(zcr_el2, SYS_ZCR); > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index 148fc3400ea8..c4d3bbae2d14 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -2862,8 +2862,6 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu, > struct sys_reg_params *p, > const struct sys_reg_desc *r) > { > - unsigned int vq; > - > if (guest_hyp_sve_traps_enabled(vcpu)) { > kvm_inject_nested_sve_trap(vcpu); > return false; > @@ -2874,9 +2872,7 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu, > return true; > } > > - vq = SYS_FIELD_GET(ZCR_ELx, LEN, p->regval) + 1; > - vq = min(vq, vcpu_sve_max_vq(vcpu)); > - __vcpu_assign_sys_reg(vcpu, ZCR_EL2, vq - 1); > + __vcpu_assign_sys_reg(vcpu, ZCR_EL2, p->regval & ZCR_ELx_LEN); Once you have added the full ZCR_EL2 sanitisation, this masking can go. > return true; > } Thanks, M. -- Jazz isn't dead. It just smells funny.