From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 4C4DD3FBB73; Fri, 10 Jul 2026 11:16:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682179; cv=none; b=YvrCmd608pkHvKFvLozXJYTab00YSnmOxSgjdhO33N7/fWx8xeOe3It3dmn4GffZAaol/h3ZeZ7N2dFUQazO376d5mwOEpYl2NNRE8ArBU5jeIyIAp/n/AcY3iYIMg0kn65epOjeRtuoJF139VVH9JyqQqtbLQdKoX6jG6PevMs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682179; c=relaxed/simple; bh=fNgLUnEmlqyfrAV7tVVlH3jDqmlIGrds8QqIzA+zcPw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ZtYXF/X48JfvRnVi2oiRLySfIr/hqmbsCmhdxeV++sJDnJNDslW+gk8fQVXbkYtukF4bsG5R6zyhl8/EQHZTg8QKjo/BGNP8HJJD7ZOdm4yU7rDSVXKSTzrnS3ntb+T9cbOMvp/KkXGuogSi6OKEbUSuJ+3ffwzuxGzx9opfDmY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=oCRVGQbk reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="oCRVGQbk" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsF024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:09 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=A1U9p3xnoBS2jAZ6UnAQTf41UHMysFjf1pjjxobco+c=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682109; v=1; b=oCRVGQbk2lJFPvYDCiIYcmDhY2QoB5j+kQXnVsbuWv987cCUgl7i2HpWFxWoj4xo Czpj/FgXnC5PBzcTKP8RIvTl5RiMT5sCZEmDaw+XgbWmFn035W3GelktZZYaeQ7T kdWnua8L2gbpgR2CWWteNtuHejoivSLGWRF79n6FkfGoMg3yyXk7X/c5MpVrhz5h PBCCb2F3Z0bEce6wNHnSUuErwyhDfUQJUMBTLg3vXDs41GQn6Icf0CrOrajjhT1j pfvs94NvMST8YYjoRWgMvnbxCepQOMFZCscRIPpny2g/N9lKAH19mnwcTrOB58hc 28NpAO2Y1ljEpmevXf1mSw== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:14:55 +0900 Subject: [PATCH v8 01/11] KVM: arm64: Serialize userspace MDCR_EL2 access Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-1-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=2777; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=fNgLUnEmlqyfrAV7tVVlH3jDqmlIGrds8QqIzA+zcPw=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFZM9IrZRGvlMeqLVClzr1HR2uRnwhHyw6qzWNz+z6 v7c+u0dpSwMYlwMsmKKLClFu7k1oms/FSbEt8DMYWUCGcLAxSkAEzFpYvjvcVVnx2nF47oTHnvY /L2kvVD6Re9q+71iTSGfZ7LKTvgnzfA/MudQgPXLZ2rHoqwmf27ezuVkLFZqlpqabLFgduf7bg9 eAA== X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C kvm_arm_set_nr_counters() updates MDCR_EL2.HPMN for every vCPU while holding kvm->arch.config_lock. However, KVM_SET_ONE_REG currently writes MDCR_EL2 through the generic sysreg path without taking the same lock. Concurrent PMU configuration and register restore can therefore race and lose updates to unrelated MDCR_EL2 bits. Add explicit userspace accessors for MDCR_EL2. Serialize them with config_lock so whole-register userspace writes cannot race with HPMN rewrites, reject HPMN values above the configured PMU counter count, and request a PMU reload when HPME changes to match guest trap behavior. Fixes: c8823e51b534 ("KVM: arm64: Fix MDCR_EL2.HPMN reset value") Closes: https://sashiko.dev/#/patchset/20260706-hybrid-v8-0-de459617b59d%40= rsg.ci.i.u-tokyo.ac.jp?part=3D6 Assisted-by: Codex:gpt-5.5 Signed-off-by: Akihiko Odaki --- arch/arm64/kvm/sys_regs.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index d217530359ba..2b2ea33159e9 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2949,6 +2949,42 @@ static bool access_mdcr(struct kvm_vcpu *vcpu, return true; } =20 +static int get_mdcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + u64 *val) +{ + struct kvm *kvm =3D vcpu->kvm; + + guard(mutex)(&kvm->arch.config_lock); + + *val =3D __vcpu_sys_reg(vcpu, MDCR_EL2); + + return 0; +} + +static int set_mdcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + u64 val) +{ + struct kvm *kvm =3D vcpu->kvm; + u64 old, hpmn =3D FIELD_GET(MDCR_EL2_HPMN, val); + + guard(mutex)(&kvm->arch.config_lock); + + if (hpmn > vcpu->kvm->arch.nr_pmu_counters) + return -EINVAL; + + old =3D __vcpu_sys_reg(vcpu, MDCR_EL2); + __vcpu_assign_sys_reg(vcpu, MDCR_EL2, val); + + /* + * Request a reload of the PMU to enable/disable the counters + * affected by HPME. + */ + if ((old ^ val) & MDCR_EL2_HPME) + kvm_make_request(KVM_REQ_RELOAD_PMU, vcpu); + + return 0; +} + static bool access_ras(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) @@ -3652,7 +3688,8 @@ static const struct sys_reg_desc sys_reg_descs[] =3D { EL2_REG_FILTERED(SCTLR2_EL2, access_vm_reg, reset_val, 0, sctlr2_el2_visibility), EL2_REG_VNCR(HCR_EL2, reset_hcr, 0), - EL2_REG(MDCR_EL2, access_mdcr, reset_mdcr, 0), + SYS_REG_USER_FILTER(MDCR_EL2, access_mdcr, reset_mdcr, 0, + get_mdcr, set_mdcr, el2_visibility), EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1), EL2_REG_VNCR(HSTR_EL2, reset_val, 0), EL2_REG_VNCR_FILT(HFGRTR_EL2, fgt_visibility), --=20 2.55.0 From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 055EC3ACA7E; Fri, 10 Jul 2026 11:16:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682180; cv=none; b=HksU3sUkH/pYfrA/qIayuk9dICOKuHJ9H0zVmkvjpo5liPy8TUtJsdNzfMcx0vIw28qCEgy1VSjtFclJr5FSnWMGddqhLVAu16utQ9lNHA7Z1k6Ugun0o0DeLe/AcaJarg4UH+4zlImSWA1xthjQ385o442uIG6GWX3VUA6YM9o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682180; c=relaxed/simple; bh=9j2sLIskvz0/of69Ci4UihDwqz/h43AbZmJiJF/tu+M=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Y1OyZyqhJLZOJ/PXwZVAEr6GJ8rPpTMhWsidKgULABL8voLzAJbe84EMcSIozGkrE66Wb3m6OVzB5R/oitC7i7gB0p9PUVjP9+QITEQoXdZP4p/v5iUlN68jTjRbA9CtEaE0y/agAogDkU3t67RYUZ8TC/k4nun8D5KzLa7IarI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=OFMBIb8J reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="OFMBIb8J" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsG024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:09 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=KyTrdU9HmcQb5NC0B5vuRBCCEn7dxaItsZiYGQoGCjU=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682109; v=1; b=OFMBIb8JieI4oSuqrXGBiBpeYAfFy4MIJ23xe91w02PKiYP6kJ/R8ZXZPXrPrCCn /JCos9aey4/4zJPJnAB9PAJBuUnR12NHylTtpMvyi40D2FGt/Ev2ryYVpRnCFPSl +UJi87NFaQH0n9kDseaLvlQXYJJ2JmAYrgHiqqBsRZlq14dgx4CNL6ip7PJoKZd3 kW4sHliYUYjSaRKrtjhxNkUriGUO8zwNUgk10F9d8LGKvKnCV2WoQ41RxUZV+ONj NHxUdq1AEKvWZfO21DQ0DgPIZfSPhUZiHpXubNT5qomfW2paQkOn42M1v6zCO4c6 p3TbP+Fo9w/7o+D4Ks9+1Q== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:14:56 +0900 Subject: [PATCH v8 02/11] tools headers: Sync bitfield.h with the kernel Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-2-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=13915; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=9j2sLIskvz0/of69Ci4UihDwqz/h43AbZmJiJF/tu+M=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFZO2nIio678bqiZkfs7a3H1ZTtpwt9z7lVc/bLCrW ra9V621o5SFQYyLQVZMkSWlaDe3RnTtp8KE+BaYOaxMIEMYuDgFYCIX8hn+KR/puBv5e23OQ6sd vL/KmHWDD3cvW33s4K6fct6z1U/eZGX4n1C4qLn5k2/oRP2DiYoXLh+bGJu171Jl/paL2YmFHsU XOAE= X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Sync tools/include/linux/bitfield.h with include/linux/bitfield.h changes since commit 590b949597b1 ("tools: Copy bitfield.h from the kernel sources"). Preserve the tools-only linux/kernel.h include for endian helpers; a follow-up selftest uses u64_replace_bits() from the refreshed header. Keep the synced native u*_..._bits() helpers on tools-local u* types, while leaving endian helpers on __le* and __be*. This preserves the tools convention that u64 is uint64_t and avoids printf format warnings in selftests. Add the supporting tools-side pieces required by the newer header: - tools/include/linux/typecheck.h for typecheck_pointer(); - the auto compatibility macro in tools/compiler_types.h, guarded with !defined(__STDC_VERSION__) for pre-C99 tools builds and kept C-only so perf C++ sources keep the C++ auto keyword; - __ffs64() in tools/include/linux/bitops.h for non-constant-mask field helpers. Assisted-by: Codex:gpt-5.5 Signed-off-by: Akihiko Odaki --- tools/include/linux/bitfield.h | 175 ++++++++++++++++++++++++++++++-= ---- tools/include/linux/bitops.h | 19 ++++ tools/include/linux/compiler_types.h | 13 +++ tools/include/linux/typecheck.h | 34 +++++++ 4 files changed, 217 insertions(+), 24 deletions(-) diff --git a/tools/include/linux/bitfield.h b/tools/include/linux/bitfield.h index ddf81f24956b..b9a634b18881 100644 --- a/tools/include/linux/bitfield.h +++ b/tools/include/linux/bitfield.h @@ -8,7 +8,9 @@ #define _LINUX_BITFIELD_H =20 #include +#include #include +#include #include =20 /* @@ -17,9 +19,13 @@ * FIELD_{GET,PREP} macros take as first parameter shifted mask * from which they extract the base mask and shift amount. * Mask must be a compilation time constant. + * field_{get,prep} are variants that take a non-const mask. * * Example: * + * #include + * #include + * * #define REG_FIELD_A GENMASK(6, 0) * #define REG_FIELD_B BIT(7) * #define REG_FIELD_C GENMASK(15, 8) @@ -36,8 +42,7 @@ * FIELD_PREP(REG_FIELD_D, 0x40); * * Modify: - * reg &=3D ~REG_FIELD_C; - * reg |=3D FIELD_PREP(REG_FIELD_C, c); + * FIELD_MODIFY(REG_FIELD_C, ®, c); */ =20 #define __bf_shf(x) (__builtin_ffsll(x) - 1) @@ -58,21 +63,42 @@ =20 #define __bf_cast_unsigned(type, x) ((__unsigned_scalar_typeof(type))(x)) =20 -#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \ +#define __BF_FIELD_CHECK_MASK(_mask, _val, _pfx) \ ({ \ BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \ _pfx "mask is not constant"); \ BUILD_BUG_ON_MSG((_mask) =3D=3D 0, _pfx "mask is zero"); \ BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \ - ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \ + ~((_mask) >> __bf_shf(_mask)) & \ + (0 + (_val)) : 0, \ _pfx "value too large for the field"); \ - BUILD_BUG_ON_MSG(__bf_cast_unsigned(_mask, _mask) > \ - __bf_cast_unsigned(_reg, ~0ull), \ - _pfx "type of reg too small for mask"); \ __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ (1ULL << __bf_shf(_mask))); \ }) =20 +#define __BF_FIELD_CHECK_REG(mask, reg, pfx) \ + BUILD_BUG_ON_MSG(__bf_cast_unsigned(mask, mask) > \ + __bf_cast_unsigned(reg, ~0ull), \ + pfx "type of reg too small for mask") + +#define __BF_FIELD_CHECK(mask, reg, val, pfx) \ + ({ \ + __BF_FIELD_CHECK_MASK(mask, val, pfx); \ + __BF_FIELD_CHECK_REG(mask, reg, pfx); \ + }) + +#define __FIELD_PREP(mask, val, pfx) \ + ({ \ + __BF_FIELD_CHECK_MASK(mask, val, pfx); \ + ((typeof(mask))(val) << __bf_shf(mask)) & (mask); \ + }) + +#define __FIELD_GET(mask, reg, pfx) \ + ({ \ + __BF_FIELD_CHECK_MASK(mask, 0U, pfx); \ + (typeof(mask))(((reg) & (mask)) >> __bf_shf(mask)); \ + }) + /** * FIELD_MAX() - produce the maximum value representable by a field * @_mask: shifted mask defining the field's length and position @@ -109,10 +135,36 @@ */ #define FIELD_PREP(_mask, _val) \ ({ \ - __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \ - ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ + __BF_FIELD_CHECK_REG(_mask, 0ULL, "FIELD_PREP: "); \ + __FIELD_PREP(_mask, _val, "FIELD_PREP: "); \ }) =20 +#define __BF_CHECK_POW2(n) BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) !=3D 0) + +/** + * FIELD_PREP_CONST() - prepare a constant bitfield element + * @_mask: shifted mask defining the field's length and position + * @_val: value to put in the field + * + * FIELD_PREP_CONST() masks and shifts up the value. The result should + * be combined with other fields of the bitfield using logical OR. + * + * Unlike FIELD_PREP() this is a constant expression and can therefore + * be used in initializers. Error checking is less comfortable for this + * version, and non-constant masks cannot be used. + */ +#define FIELD_PREP_CONST(_mask, _val) \ + ( \ + /* mask must be non-zero */ \ + BUILD_BUG_ON_ZERO((_mask) =3D=3D 0) + \ + /* check if value fits */ \ + BUILD_BUG_ON_ZERO(~((_mask) >> __bf_shf(_mask)) & (_val)) + \ + /* check if mask is contiguous */ \ + __BF_CHECK_POW2((_mask) + (1ULL << __bf_shf(_mask))) + \ + /* and create the value */ \ + (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)) \ + ) + /** * FIELD_GET() - extract a bitfield element * @_mask: shifted mask defining the field's length and position @@ -123,8 +175,25 @@ */ #define FIELD_GET(_mask, _reg) \ ({ \ - __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ - (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ + __BF_FIELD_CHECK_REG(_mask, _reg, "FIELD_GET: "); \ + __FIELD_GET(_mask, _reg, "FIELD_GET: "); \ + }) + +/** + * FIELD_MODIFY() - modify a bitfield element + * @_mask: shifted mask defining the field's length and position + * @_reg_p: pointer to the memory that should be updated + * @_val: value to store in the bitfield + * + * FIELD_MODIFY() modifies the set of bits in @_reg_p specified by @_mask, + * by replacing them with the bitfield value passed in as @_val. + */ +#define FIELD_MODIFY(_mask, _reg_p, _val) \ + ({ \ + typecheck_pointer(_reg_p); \ + __BF_FIELD_CHECK(_mask, *(_reg_p), _val, "FIELD_MODIFY: "); \ + *(_reg_p) &=3D ~(_mask); \ + *(_reg_p) |=3D (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)); \ }) =20 extern void __compiletime_error("value doesn't fit into mask") @@ -142,36 +211,94 @@ static __always_inline u64 field_mask(u64 field) return field / field_multiplier(field); } #define field_max(field) ((typeof(field))field_mask(field)) -#define ____MAKE_OP(type,base,to,from) \ -static __always_inline __##type type##_encode_bits(base v, base field) \ +#define ____MAKE_OP(name,type,base,to,from) \ +static __always_inline type __must_check name##_encode_bits(base v, base f= ield) \ { \ if (__builtin_constant_p(v) && (v & ~field_mask(field))) \ __field_overflow(); \ return to((v & field_mask(field)) * field_multiplier(field)); \ } \ -static __always_inline __##type type##_replace_bits(__##type old, \ - base val, base field) \ +static __always_inline type __must_check name##_replace_bits(type old, \ + base val, base field) \ { \ - return (old & ~to(field)) | type##_encode_bits(val, field); \ + return (old & ~to(field)) | name##_encode_bits(val, field); \ } \ -static __always_inline void type##p_replace_bits(__##type *p, \ +static __always_inline void name##p_replace_bits(type *p, \ base val, base field) \ { \ - *p =3D (*p & ~to(field)) | type##_encode_bits(val, field); \ + *p =3D (*p & ~to(field)) | name##_encode_bits(val, field); \ } \ -static __always_inline base type##_get_bits(__##type v, base field) \ +static __always_inline base __must_check name##_get_bits(type v, base fiel= d) \ { \ return (from(v) & field)/field_multiplier(field); \ } -#define __MAKE_OP(size) \ - ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \ - ____MAKE_OP(be##size,u##size,cpu_to_be##size,be##size##_to_cpu) \ - ____MAKE_OP(u##size,u##size,,) -____MAKE_OP(u8,u8,,) +#define __MAKE_OP(size) \ + ____MAKE_OP(le##size,__le##size,u##size,cpu_to_le##size,le##size##_to_cpu= ) \ + ____MAKE_OP(be##size,__be##size,u##size,cpu_to_be##size,be##size##_to_cpu= ) \ + ____MAKE_OP(u##size,u##size,u##size,,) +____MAKE_OP(u8,u8,u8,,) __MAKE_OP(16) __MAKE_OP(32) __MAKE_OP(64) #undef __MAKE_OP #undef ____MAKE_OP =20 +#define __field_prep(mask, val) \ + ({ \ + auto __mask =3D (mask); \ + typeof(__mask) __val =3D (val); \ + unsigned int __shift =3D BITS_PER_TYPE(__mask) <=3D 32 ? \ + __ffs(__mask) : __ffs64(__mask); \ + (__val << __shift) & __mask; \ + }) + +#define __field_get(mask, reg) \ + ({ \ + auto __mask =3D (mask); \ + typeof(__mask) __reg =3D (reg); \ + unsigned int __shift =3D BITS_PER_TYPE(__mask) <=3D 32 ? \ + __ffs(__mask) : __ffs64(__mask); \ + (__reg & __mask) >> __shift; \ + }) + +/** + * field_prep() - prepare a bitfield element + * @mask: shifted mask defining the field's length and position, must be + * non-zero + * @val: value to put in the field + * + * Return: field value masked and shifted to its final destination + * + * field_prep() masks and shifts up the value. The result should be + * combined with other fields of the bitfield using logical OR. + * Unlike FIELD_PREP(), @mask is not limited to a compile-time constant. + * Typical usage patterns are a value stored in a table, or calculated by + * shifting a constant by a variable number of bits. + * If you want to ensure that @mask is a compile-time constant, please use + * FIELD_PREP() directly instead. + */ +#define field_prep(mask, val) \ + (__builtin_constant_p(mask) ? __FIELD_PREP(mask, val, "field_prep: ") \ + : __field_prep(mask, val)) + +/** + * field_get() - extract a bitfield element + * @mask: shifted mask defining the field's length and position, must be + * non-zero + * @reg: value of entire bitfield + * + * Return: extracted field value + * + * field_get() extracts the field specified by @mask from the + * bitfield passed in as @reg by masking and shifting it down. + * Unlike FIELD_GET(), @mask is not limited to a compile-time constant. + * Typical usage patterns are a value stored in a table, or calculated by + * shifting a constant by a variable number of bits. + * If you want to ensure that @mask is a compile-time constant, please use + * FIELD_GET() directly instead. + */ +#define field_get(mask, reg) \ + (__builtin_constant_p(mask) ? __FIELD_GET(mask, reg, "field_get: ") \ + : __field_get(mask, reg)) + #endif diff --git a/tools/include/linux/bitops.h b/tools/include/linux/bitops.h index b4e4cd071f8c..0dfd61a7a35d 100644 --- a/tools/include/linux/bitops.h +++ b/tools/include/linux/bitops.h @@ -100,4 +100,23 @@ static __always_inline __s64 sign_extend64(__u64 value= , int index) return (__s64)(value << shift) >> shift; } =20 +/** + * __ffs64 - find first set bit in a 64 bit word + * @word: The 64 bit word + * + * On 64 bit arches this is a synonym for __ffs + * The result is not defined if no bits are set, so check that @word + * is non-zero before calling this. + */ +static inline __attribute_const__ unsigned int __ffs64(u64 word) +{ +#if BITS_PER_LONG =3D=3D 32 + if (((u32)word) =3D=3D 0UL) + return __ffs((u32)(word >> 32)) + 32; +#elif BITS_PER_LONG !=3D 64 +#error BITS_PER_LONG not 32 or 64 +#endif + return __ffs((unsigned long)word); +} + #endif diff --git a/tools/include/linux/compiler_types.h b/tools/include/linux/com= piler_types.h index b3adbf5682f0..287a1a26cb05 100644 --- a/tools/include/linux/compiler_types.h +++ b/tools/include/linux/compiler_types.h @@ -13,6 +13,19 @@ #define __has_builtin(x) (0) #endif =20 +/* + * C23 introduces "auto" as a standard way to define type-inferred + * variables, but "auto" has been a (useless) keyword even since K&R C, + * so it has always been "namespace reserved." + * + * Until at some future time we require C23 support, we need the gcc + * extension __auto_type, but there is no reason to put that elsewhere + * in the source code. + */ +#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION= __ < 202311L) +# define auto __auto_type +#endif + #include =20 /* Compiler specific macros. */ diff --git a/tools/include/linux/typecheck.h b/tools/include/linux/typechec= k.h new file mode 100644 index 000000000000..46b15e2aaefb --- /dev/null +++ b/tools/include/linux/typecheck.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef TYPECHECK_H_INCLUDED +#define TYPECHECK_H_INCLUDED + +/* + * Check at compile time that something is of a particular type. + * Always evaluates to 1 so you may use it easily in comparisons. + */ +#define typecheck(type,x) \ +({ type __dummy; \ + typeof(x) __dummy2; \ + (void)(&__dummy =3D=3D &__dummy2); \ + 1; \ +}) + +/* + * Check at compile time that 'function' is a certain type, or is a pointer + * to that type (needs to use typedef for the function type.) + */ +#define typecheck_fn(type,function) \ +({ typeof(type) __tmp =3D function; \ + (void)__tmp; \ +}) + +/* + * Check at compile time that something is a pointer type. + */ +#define typecheck_pointer(x) \ +({ typeof(x) __dummy; \ + (void)sizeof(*__dummy); \ + 1; \ +}) + +#endif /* TYPECHECK_H_INCLUDED */ --=20 2.55.0 From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 35E30416CF5; Fri, 10 Jul 2026 11:16:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682187; cv=none; b=PyhHoYiEU3Q3TmOBs4XGwsVW/31RIZ5T3Gnl3zVhcy/n9Ezq06njNR09A/TvIJwh1rGeh3XpD5TkUUTz2RidB2isma1OURjBr+XB73EXvoWfcflwaB46ehMpDYrV+N60RRikNBY8UsOOvNstTJ+AZ7l6s3oF/GkgMAPYbVOUJac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682187; c=relaxed/simple; bh=U9MEpE2Ih98r0rKIS5ukgUhQF9OCUYmg2BREdlUGgos=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=iHO4Fh8/i+ckFMcLx1L9V81BqWo9zaKYSX95DyRjjw8YYYHh74xNojyjSfOeC/rvKMsj5GHphHRspdHKJAqN3ipbYPKbZtzW/xyoh6zJigYknGurGiPZoxp21mTu1Ileaz8R+O6Kz7dmeWTHh0t8bSnW+VtHRUM5jxOv29B4cYY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=mZ/mHjw+ reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="mZ/mHjw+" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsH024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:10 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=uYrOcz7cPsXjyBNdYSNHFBXBQv6JgbTYi8PN49aaXZ8=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682110; v=1; b=mZ/mHjw+q5qmL6SJzncK0NvUHK9WAcp5mzhrd+351BTQ3OTW9tPlk8hESlrpH9eu WvTo7LkX++pgZuuMDnEmALooMjv0hO0A04LoqC/4A3otIkV07uAY+XjdwAoPWgGo yRUSqXk9XRdEfnmK9P3Fq5GSlCllRghQ1G5NsSpAEyEZ6hRnEBSzzBLdG34xVVFt EDKMRxkTq9HDwrSCgmnAOxifIua5gxb1wZW+JboMnZ3aEZM5fulciA4NnS31W//E UV9bw192xIrz4ExCj/R89VqKrh9460iRgoZ38dANsub5tnHciSEnJwPXS5LkDLAi OkRtOUVpJwByY1bh9TdNpA== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:14:57 +0900 Subject: [PATCH v8 03/11] KVM: arm64: selftests: Cover PMU state in MDCR_EL2 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-3-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=4101; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=U9MEpE2Ih98r0rKIS5ukgUhQF9OCUYmg2BREdlUGgos=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFdOoCdslkj9tDK85mGkeprzlWJKYd6tsW/56hf+r2 KNM+uZ2lLIwiHExyIopsqQU7ebWiK79VJgQ3wIzh5UJZAgDF6cATORBAiPD4fz/qRuFXrndFrHc 6Tv74rv96UenzKrcc69SWX9L16LQcwz//Ts3vivq/XrNsfHy8XrPi112U4xuZvXquH6r6vTXVrz DAgA= X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Add MDCR_EL2 coverage to vpmu_counter_access when EL2 is available. For each configured PMCR_EL0.N value, verify that HPMN tracks the configured counter count, HPME can be toggled without disturbing HPMN, and KVM_SET_ONE_REG rejects an out-of-range HPMN without changing MDCR_EL2. Reset the vCPU and verify that HPMN is restored from the configured count. Assisted-by: Codex:gpt-5.5 Signed-off-by: Akihiko Odaki --- .../selftests/kvm/arm64/vpmu_counter_access.c | 76 ++++++++++++++++++= ++++ 1 file changed, 76 insertions(+) diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tool= s/testing/selftests/kvm/arm64/vpmu_counter_access.c index 22223395969e..25203ea117b0 100644 --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c @@ -25,6 +25,14 @@ /* The cycle counter bit position that's common among the PMU registers */ #define ARMV8_PMU_CYCLE_IDX 31 =20 +#ifndef MDCR_EL2_HPMN +#define MDCR_EL2_HPMN GENMASK_ULL(4, 0) +#endif + +#ifndef MDCR_EL2_HPME +#define MDCR_EL2_HPME BIT_ULL(7) +#endif + struct vpmu_vm { struct kvm_vm *vm; struct kvm_vcpu *vcpu; @@ -583,6 +591,73 @@ static void run_pmregs_validity_test(u64 pmcr_n) destroy_vpmu_vm(); } =20 +static void run_mdcr_el2_validity_test(u64 pmcr_n) +{ + struct kvm_vcpu_init init; + struct kvm_vcpu *vcpu; + u64 mdcr, old_mdcr; + int ret; + + pr_debug("MDCR_EL2 test with pmcr_n %lu\n", pmcr_n); + + test_create_vpmu_vm_with_nr_counters(pmcr_n, false); + if (!vm_supports_el2(vpmu_vm.vm)) { + destroy_vpmu_vm(); + return; + } + + vcpu =3D vpmu_vm.vcpu; + + mdcr =3D vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2)); + TEST_ASSERT(FIELD_GET(MDCR_EL2_HPMN, mdcr) =3D=3D pmcr_n, + "MDCR_EL2.HPMN is not updated after PMU_V3_SET_NR_COUNTERS (expected= %lu, got %lu)", + pmcr_n, FIELD_GET(MDCR_EL2_HPMN, mdcr)); + + old_mdcr =3D mdcr; + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2), + old_mdcr ^ MDCR_EL2_HPME); + + mdcr =3D vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2)); + TEST_ASSERT(mdcr =3D=3D (old_mdcr ^ MDCR_EL2_HPME), + "MDCR_EL2 was not properly updated after HPME write (expected 0x%lx,= got 0x%lx)", + old_mdcr ^ MDCR_EL2_HPME, mdcr); + + if (pmcr_n < FIELD_MAX(MDCR_EL2_HPMN)) { + errno =3D 0; + old_mdcr =3D mdcr; + ret =3D __vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2), + u64_replace_bits(mdcr, pmcr_n + 1, MDCR_EL2_HPMN)); + TEST_ASSERT(ret =3D=3D -1 && errno =3D=3D EINVAL, + "Setting MDCR_EL2.HPMN to %lu unexpectedly succeeded", + pmcr_n + 1); + + mdcr =3D vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2)); + TEST_ASSERT(mdcr =3D=3D old_mdcr, + "MDCR_EL2 changed after failed HPMN write (expected 0x%lx, got 0x%l= x)", + old_mdcr, mdcr); + } + + old_mdcr =3D mdcr; + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2), + u64_replace_bits(mdcr, 0, MDCR_EL2_HPMN)); + + mdcr =3D vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2)); + TEST_ASSERT(mdcr =3D=3D u64_replace_bits(old_mdcr, 0, MDCR_EL2_HPMN), + "MDCR_EL2 was not properly updated after HPMN write (expected 0x%lx,= got 0x%lx)", + u64_replace_bits(old_mdcr, 0, MDCR_EL2_HPMN), mdcr); + + kvm_get_default_vcpu_target(vpmu_vm.vm, &init); + init.features[0] |=3D (1 << KVM_ARM_VCPU_PMU_V3); + aarch64_vcpu_setup(vcpu, &init); + + mdcr =3D vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MDCR_EL2)); + TEST_ASSERT(FIELD_GET(MDCR_EL2_HPMN, mdcr) =3D=3D pmcr_n, + "MDCR_EL2.HPMN is not updated after INIT (expected %lu, got %lu)", + pmcr_n, FIELD_GET(MDCR_EL2_HPMN, mdcr)); + + destroy_vpmu_vm(); +} + /* * Create a guest with one vCPU, and attempt to set the PMCR_EL0.N for * the vCPU to @pmcr_n, which is larger than the host value. @@ -634,6 +709,7 @@ int main(void) for (i =3D 0; i <=3D pmcr_n; i++) { run_access_test(i); run_pmregs_validity_test(i); + run_mdcr_el2_validity_test(i); } =20 for (i =3D pmcr_n + 1; i < ARMV8_PMU_MAX_COUNTERS; i++) --=20 2.55.0 From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 665A2409635; Fri, 10 Jul 2026 11:16:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682179; cv=none; b=n3ZXbK9iCQF+4ChcARd85dY9fn5pn19IOPI80DdUCqQF2ed/vf/qKNEPWdVVk+OEjx/+F/K7DhBSLM3jotPJddkee+ce65BIsCkJC5m+2ixRZ112fQP39YmqG7cFC/IXE2USGAlsO/1GJeAPQM7RCNhoXH0Zhy1FKNAOHEcu30g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682179; c=relaxed/simple; bh=hp0lEkOwUA4Gek6D7M1hRbpbu/V7WYaGYBv95FZV7oc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kpGJRlg0FhU17wI/O81U9HkleroexA/J0rmBUFEplRh3uTaPY3AUpfqohjlUzUH0XiF793INihtEYDRk5Gr1IQFt8L3baHMWLa16vnIRzAaQYd+sOxE/9KCgdJlvCDFkA5jmAer6OuN5ejuW33UiKIfN+ssIgFw5rKBr/eSS/jA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=cypq5tmg reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="cypq5tmg" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsI024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:10 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=pJjKbNakwtm0jMT04UBxbp6wN2PKOAbYt/K0ZhCrjUc=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682110; v=1; b=cypq5tmgi8sW1J1vY+7FX5yhIamwUYgJ8fnr/uY3GitaU8yixH4poE4ECyVNednC CpQJaOhbEVn4aCzaqk4zNVeEHkOmedKuH0fSuSDr184wCx92thrc4vMugRvyuFr/ w8Pk/BRGggqeeSD6cdoTNEIVR4xONf3EhlvO2hr0lZ4x3AbbdZ3AR9Gpp5dVOsZn nx/HgECEJtwZ4tx3Y7tefssdGAB7Em5FNfC5H5YOeudZ0PnlWw8WZM2gW9dE1nx1 mAlH8CoRhbOuyt7CpOxC2wkjp/tpBX8nHzJlWUiS0FJzoOX+9w9/lkgEEDrwjo4U U6Ky2Ar/ayLG5jEEZiGl4A== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:14:58 +0900 Subject: [PATCH v8 04/11] arm64: errata: Require Apple IMPDEF PMUv3 traps on all CPUs Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-4-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=1261; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=hp0lEkOwUA4Gek6D7M1hRbpbu/V7WYaGYBv95FZV7oc=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFbMHm2WVY578mzc1ruRV9qK3tZ7tuz6LBAXcKpZ5c PX4uvJbHaUsDGJcDLJiiiwpRbu5NaJrPxUmxLfAzGFlAhnCwMUpABOJtmVk+DWtN10kdo3lwx0B f+4c3f7++GrhIzwq9ez/du/89cbvGzMjQ8OutReeTvjbPzeOpbnvdNtddZ9Em+enI33lObbyFwY bsgAA X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C KVM relies on ARM64_WORKAROUND_PMUV3_IMPDEF_TRAPS as a system-wide precondition for PMUv3 emulation on affected Apple CPUs. A local CPU erratum is too weak for that: once the workaround is enabled, a late CPU that misses it may still be onlined. Make the workaround an all-early-CPU capability instead. The matcher is still local because it depends on MIDR_EL1, but the capability is only advertised if all early CPUs match, and late CPUs that miss it are rejected once the capability is enabled. Assisted-by: Codex:gpt-5.5 Signed-off-by: Akihiko Odaki --- arch/arm64/kernel/cpu_errata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 476a37c82108..14ce49d693c4 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -964,7 +964,7 @@ const struct arm64_cpu_capabilities arm64_errata[] =3D { { .desc =3D "Apple IMPDEF PMUv3 Traps", .capability =3D ARM64_WORKAROUND_PMUV3_IMPDEF_TRAPS, - .type =3D ARM64_CPUCAP_LOCAL_CPU_ERRATUM, + .type =3D ARM64_CPUCAP_EARLY_LOCAL_CPU_FEATURE, .matches =3D has_impdef_pmuv3, .cpu_enable =3D cpu_enable_impdef_pmuv3_traps, }, --=20 2.55.0 From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 6C9FE40E8F9; Fri, 10 Jul 2026 11:16:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682180; cv=none; b=N1O60SamAhAFPMo686gYHZN4Yv7NoN20T7QoL3Kb4njc9cVxweBR4WulRuWyT/G0txmyiFnSTQQmhBAemTIkfI2Zylq0rCcSVUI4fyCPUGR8F0yfeYtvmmWDdQJ9Wgdcc5ArDU5ahyzPTxak5VqYb6lzxlFd9H2Fm0uBTG3mXoE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682180; c=relaxed/simple; bh=1sI7HiNd1TcaXudxyKbChwXuvxFZuP/SefPTji/Ketk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Svt0d27HbJ9AlONHZ0QaLxgllnvA9jqBW4rmEHbS0EksOUrMWRd0PKS2wdtu+t1VgL94SwMrIubObyrPruddbbLj+x/cvQkrcaS/dURpqAQgER/MS1HRue9gA7TtLWvZopIHU3qkpEPo3eqOe0kxdFzSaS30jEa8MCd1VB1tIlA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=YF7wA/hx reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="YF7wA/hx" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsJ024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:10 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=JuirHxy2JdcdOWMIyjetVaMm5INIuwHNGdnNKrdLT4k=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682110; v=1; b=YF7wA/hxobu26go9W+0X6qeajGIxufeutjM/XKC6Fj0OKeRZ++6yfnLkbNwTQwoa TN0hXICa8KtUg+Rt0WDP8V3bxT3Dx48bu/ub3HpwNbYyVJpUc8JtPwVlQXcIBESs PrhqKjJtF/i5YucfX0XiE6ZujYXfJapozDYv27dWOUSirL+nGwmIjmAvLdJV8fbr RamAqUWIMVHZV5oTvvvlLMpByr07Y/0Ai5xfehpIpoAJ4NGPDfoOfKNn1+rgNByx /kgoQps9mlV7RSwDV3Nza+r1c3LmVxAkhs0/mzDSYtHdZCMgIxqbaiUFw2db0HC7 mX6Q5vU1UW0MXnD7PZwbtw== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:14:59 +0900 Subject: [PATCH v8 05/11] KVM: arm64: Don't clear vcpu->cpu in kvm_arch_vcpu_put() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-5-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=2455; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=M8lM3x/ufgUWZRiJ1lSqB1wM8VCxi9Kmy0/qLfUXi4A=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFfOf/WuY+N2dX9fcMMm29rz3OP/4/YST0Smnf3wOt VxnXHyno5SFQYyLQVZMkSWlaDe3RnTtp8KE+BaYOaxMIEMYuDgFYCIzVzL8T8nW5bLyupylpbby ac1Fn9tPvv1LWOazrfqBw/ISkYhgZkaG56dXXj+w5WKCr3Qfc+DyzsP/JR8t7chP4d/ocfOHzoq jDAA= X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C From: Oliver Upton commit e9b152cb957c ("arm/arm64: kvm: Set vcpu->cpu to -1 on vcpu_put") reset vcpu->cpu in order for the VGIC to determine if there was any vCPU running at the time of access. The VGIC has gone through an entire rewrite since then, and with commit 7d450e282171 ("KVM: arm/arm64: vgic-new: Add userland access to VGIC dist registers") the user accessors just grab all vCPU mutexes instead. Drop this remaining vestige such that kvm_arch_vcpu_load() can properly detect a CPU migration. While at it, rework kvm_reset_vcpu() to do a much more pedantic check that the provided vCPU is actually what's running on the present CPU. Signed-off-by: Oliver Upton Signed-off-by: Akihiko Odaki --- arch/arm64/kvm/arm.c | 1 - arch/arm64/kvm/reset.c | 16 +++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 29f48f2c63ec..58d0783f254d 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -734,7 +734,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_vmid_clear_active(); =20 vcpu_clear_on_unsupported_cpu(vcpu); - vcpu->cpu =3D -1; } =20 static void __kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index b963fd975aac..6bfb21f00444 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -190,7 +190,8 @@ static void kvm_vcpu_reset_sve(struct kvm_vcpu *vcpu) void kvm_reset_vcpu(struct kvm_vcpu *vcpu) { struct vcpu_reset_state reset_state; - bool loaded; + struct kvm_vcpu *running; + bool loaded =3D false; u32 pstate; =20 spin_lock(&vcpu->arch.mp_state_lock); @@ -198,10 +199,16 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu) vcpu->arch.reset_state.reset =3D false; spin_unlock(&vcpu->arch.mp_state_lock); =20 - preempt_disable(); - loaded =3D (vcpu->cpu !=3D -1); - if (loaded) + guard(preempt)(); + + running =3D kvm_get_running_vcpu(); + if (running) { + if (KVM_BUG_ON(running !=3D vcpu, vcpu->kvm)) + return; + + loaded =3D true; kvm_arch_vcpu_put(vcpu); + } =20 if (!kvm_arm_vcpu_sve_finalized(vcpu)) { if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_SVE)) @@ -269,7 +276,6 @@ void kvm_reset_vcpu(struct kvm_vcpu *vcpu) =20 if (loaded) kvm_arch_vcpu_load(vcpu, smp_processor_id()); - preempt_enable(); } =20 u32 kvm_get_pa_bits(struct kvm *kvm) --=20 2.55.0 From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 E5826409635; Fri, 10 Jul 2026 11:21:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682481; cv=none; b=umP4IVjru2gjuYwgpbFHMUTvpVDxCt7zOYeExXxz0OENHLnw3Ar2hgCJ0cR/hqJnfxktw+e7Aia1+18aWv/UzZxMx4IpAz09Ls+RzrkcGwRIcXukySWL4Sk0erjPvqFlFFkxLAz2Mxb+Fr11Dd1OKXWGDuFjEQmutLw/pS2fNWE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682481; c=relaxed/simple; bh=czv2g+GuK7rCFgQGkd6MIB0mjD9by6RlwHlZIF8LF0c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mhY7pfwQrpTKqpkfnSyLGBOm3K8lksnCfiHpkVwZHE1KCp41LEsxE7b8FCjdwg9/7AvKQkCDeO+YYtR9P4MLrCwAK6RdzdfODgtAtRbh5w1ZLFTwpwPoOAFShktL+IKQJUo1whRcifNdzXHeD0Ek87nHlCtwMTN2isriWX8XYLk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=BmBSxaV5 reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="BmBSxaV5" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsK024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:10 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=/U1Gw8hevVKM95vpLUwyV9E1e21wXByHb45PT6PY3mg=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682111; v=1; b=BmBSxaV5UzA5XSQgoXX+yskzpEDYEdnJVOJCUGr7Vj6yuiAVgqYdpfo4PGcmSeJU 36G+MlsCngo6FfOpQnygDfWtjBiFQRxVRAyjnNfJXWmhHhEe+fZIRwbEFcY44LtD bBcWH+7Nn39MtS0L5FvOwjLd+oWCszp4GUOxnDFmFBFrBfS9NKkIBukTkwA54GMk TjfJbkaDEPuJMcKuM/57MDenyvlV4rg1PX16Qtp36+5n1rU2sCtiLCO7kCKHQs4Q gLLG23K3+h1lMGCy4LiESBHSlPEDn0WqM/RtKnKuDmJRlTo5o8GOMLKgxWWEW4xb X978avdK1iVwN9AaLYjW9A== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:15:00 +0900 Subject: [PATCH v8 06/11] KVM: arm64: PMU: Protect the list of PMUs with RCU Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-6-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=2695; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=czv2g+GuK7rCFgQGkd6MIB0mjD9by6RlwHlZIF8LF0c=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFYvZE3/Fnj+xkjfxXb7y0uqEaZLfrmt5cTpYTGxcP 1X+m2FYRykLgxgXg6yYIktK0W5ujejaT4UJ8S0wc1iZQIYwcHEKwESe8zEybDC6URB7+35BYrHJ m0ajY/G+qf3NUxjMJVn2yt1h/Mazh+Gf6XuX1ReuTHULt99+79gevgXu+fev7wz+uTBJ+9cBhX4 rBgA= X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Convert the list of PMUs to a RCU-protected list that has primitives to avoid read-side contention. Assisted-by: Codex:gpt-5.5 Signed-off-by: Akihiko Odaki --- arch/arm64/kvm/pmu-emul.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index c816db5d6761..68fce960ba69 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -7,9 +7,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -17,6 +17,10 @@ =20 #define PERF_ATTR_CFG1_COUNTER_64BIT BIT(0) =20 +/* + * arm_pmus is append-only. kvm_supports_guest_pmuv3() feeds persistent + * VM state, so a true result must remain valid after the check. + */ static LIST_HEAD(arm_pmus); static DEFINE_MUTEX(arm_pmus_lock); =20 @@ -26,7 +30,6 @@ static bool kvm_pmu_counter_is_enabled(struct kvm_pmc *pm= c); =20 bool kvm_supports_guest_pmuv3(void) { - guard(mutex)(&arm_pmus_lock); return !list_empty(&arm_pmus); } =20 @@ -802,7 +805,7 @@ void kvm_host_pmu_init(struct arm_pmu *pmu) return; =20 entry->arm_pmu =3D pmu; - list_add_tail(&entry->entry, &arm_pmus); + list_add_tail_rcu(&entry->entry, &arm_pmus); } =20 static struct arm_pmu *kvm_pmu_probe_armpmu(void) @@ -811,7 +814,7 @@ static struct arm_pmu *kvm_pmu_probe_armpmu(void) struct arm_pmu *pmu; int cpu; =20 - guard(mutex)(&arm_pmus_lock); + guard(rcu)(); =20 /* * It is safe to use a stale cpu to iterate the list of PMUs so long as @@ -831,7 +834,7 @@ static struct arm_pmu *kvm_pmu_probe_armpmu(void) * carried here. */ cpu =3D raw_smp_processor_id(); - list_for_each_entry(entry, &arm_pmus, entry) { + list_for_each_entry_rcu(entry, &arm_pmus, entry) { pmu =3D entry->arm_pmu; =20 if (cpumask_test_cpu(cpu, &pmu->supported_cpus)) @@ -1092,9 +1095,9 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vc= pu, int pmu_id) int ret =3D -ENXIO; =20 lockdep_assert_held(&kvm->arch.config_lock); - mutex_lock(&arm_pmus_lock); + guard(rcu)(); =20 - list_for_each_entry(entry, &arm_pmus, entry) { + list_for_each_entry_rcu(entry, &arm_pmus, entry) { arm_pmu =3D entry->arm_pmu; if (arm_pmu->pmu.type =3D=3D pmu_id) { if (kvm_vm_has_ran_once(kvm) || @@ -1110,7 +1113,6 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vc= pu, int pmu_id) } } =20 - mutex_unlock(&arm_pmus_lock); return ret; } =20 --=20 2.55.0 From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 C72033A451E; Fri, 10 Jul 2026 11:16:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682179; cv=none; b=mYVJGFLNuq1MrTcakDhBPwOMIp41ifvlAPqf5O4m7XJnf/11TwmyFkn5LVxB0fMz00WcJF0+Msw4ghd/nSrX2ZxwsYQ4z/LbZAU6rPfPXeQMaRPpbhZD/ZlbKaD/l8jNx+rrWPSJUfR+0KY1CRCZ3gK6L4F4qdqcYyzakwvUzjw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682179; c=relaxed/simple; bh=GcmCes6lQAiKzkcGE+JER7EEugEN/SgS0n7mt6P7COA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Ic9yhJ9Y/7LNvL2j863+9lh4mpmbNEjOSN2EPO0o0PmIgpqwt0ETGRDzKJmkK6rFb1qWmIp5A67ya6spVQdHhPPRfhrzfiJeh7e6NlxHn6swkEwJqVr9Az51b7QHqTR01r/9uZUi+8Xv1d0VfmEGL/zpfiXYqFdNQzp6aV8VFWI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=JLT8WZJt reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="JLT8WZJt" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsL024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:11 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=HxASWJordbwbK0dfh3jueBnYsD6Vv4drYFkhabaJ2Rc=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682111; v=1; b=JLT8WZJtnfeQSeysxTLOQv/IXLP7DcdbdUjW4OoAjvT4T9QU43XTaks92DVo4AH8 pVRBO1OUBCY9+7ldEgHCNEkz0D3UQxywyHV5JWmA4b3VUqwnNX7DaBhgTDDzB7A6 7z7lAd1QSP63gD4twKdcwt7lXNTCXCiJPAiKIma59MNehFLYZxGBBpHpYXIcWyq1 MYOOjnJ1hpmN0/Thgx/MPwK9RAYpjw5h7pdM4fd+3X/NbuzxipYq/tvzDALFYjPR rfCt5IgbblbGYpT4EPCP7BTI7wsAKXBx5aUZyC3bHa4O/f/Q230Ha1RcE50cBysI dWfH7/p6807zzdxFesKpRg== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:15:01 +0900 Subject: [PATCH v8 07/11] KVM: arm64: PMU: Pass the pPMU to kvm_map_pmu_event() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-7-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=1455; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=GcmCes6lQAiKzkcGE+JER7EEugEN/SgS0n7mt6P7COA=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFYs6gwv31I7O9j67mbfs16Z5uUYnUvquVQUxn1p1v X3OiYv3O0pZGMS4GGTFFFlSinZza0TXfipMiG+BmcPKBDKEgYtTACbi9pfhn+lrkXeBwpfPpO25 3BBslG79XuhN+/dHnInJPiWnFRR5NzIy/Jt8fMvhiBT1oPuVdhsXbin7I6vw0+zTWq3P/5fXTTV 3ZQYA X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Replace the VM argument with the pPMU used for event creation. The current caller still passes the VM's default pPMU, but this removes the implicit lookup from kvm_map_pmu_event() so later changes can map events against the pPMU selected for an individual vCPU. Signed-off-by: Akihiko Odaki --- arch/arm64/kvm/pmu-emul.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index 68fce960ba69..1d03d0cb62f3 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -665,10 +665,8 @@ static bool kvm_pmc_counts_at_el2(struct kvm_pmc *pmc) return kvm_pmc_read_evtreg(pmc) & ARMV8_PMU_INCLUDE_EL2; } =20 -static int kvm_map_pmu_event(struct kvm *kvm, unsigned int eventsel) +static int kvm_map_pmu_event(struct arm_pmu *pmu, unsigned int eventsel) { - struct arm_pmu *pmu =3D kvm->arch.arm_pmu; - /* * The CPU PMU likely isn't PMUv3; let the driver provide a mapping * for the guest's PMUv3 event ID. @@ -720,7 +718,7 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *p= mc) * Don't create an event if we're running on hardware that requires * PMUv3 event translation and we couldn't find a valid mapping. */ - eventsel =3D kvm_map_pmu_event(vcpu->kvm, eventsel); + eventsel =3D kvm_map_pmu_event(vcpu->kvm->arch.arm_pmu, eventsel); if (eventsel < 0) return; =20 --=20 2.55.0 From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 B36B3416D11; Fri, 10 Jul 2026 11:21:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682475; cv=none; b=SpMQrSDhIkPneSSvtH4uQq76jyhmFkpGOhiHgvmrkaxrPcewLJ0sGkJmezdJkgUhaVgUYzP953WVl8ximbOy8FAT+LVqLfotsatk/n4JdEx5+Ez18rEgv+yQnmoEbEOBgTzbqFL80qrAyRtzNRCJ3qw/MsBrnS+urjKClJ7lYlI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682475; c=relaxed/simple; bh=8hhDq85vcHcF/9BQ2Qz8axGKuQb8hlF+J1dMzI4UNmY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KMKSvXxLQNiWpDuU7/qX96FO88WQtmNPr3vKBj4cQdACD7nV60TE1AG9c+Fd3NvFlnl2GxRgQ2hdF0P0yVbpmGiIqOPjtNwpmRtAwfCloSzMF5U0WcG8OEKJ41Lj3//s8+EmWMTKPFd6zEBBf4n9RtSCxXvaBPykAHjMfdPe7wo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=Sn1So8LC reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="Sn1So8LC" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsM024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:11 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=JO1RytCw7CQxlD6804FsBIdj143RrsQgoAnMa93zRJU=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682112; v=1; b=Sn1So8LCm6eWjVT03slVIzGiyZKxQj59xS4Rhcvk2+0PpBg1xfn2gXjacJRyu4lJ xwOeEmNdZfDO88q38SO9mBsTObZhdMm9DQ0eVjUjybBT0s+1lB/CAtGJtX7HqCSN jWxD3PhFxHOYPyz5nwOibOQCmxb4pll3fwekDkMm9ABfdXZXMiWQ0Whesc0OsQGO KaAHg6hmZhe1xLzzkjeVY+qM6s6AvmL/68NVxCpwTcxrHzMP41OXErA4Xq+GFV4i M7gv16In+ylUzyBTz3dl9jyf28ARCO9dF6WqO2fFkO7yR0RtNs6ELfChYUPYfCZA CFymPnJwTvS4XrHRVHITfw== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:15:02 +0900 Subject: [PATCH v8 08/11] KVM: arm64: PMU: Pass the target CPU to kvm_pmu_probe_armpmu() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-8-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=4094; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=8hhDq85vcHcF/9BQ2Qz8axGKuQb8hlF+J1dMzI4UNmY=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFctzlZG1FnqW6+Q/dl6r396ypmleA5Mem9UTBr9rz D9qrz/oKGVhEONikBVTZEkp2s2tEV37qTAhvgVmDisTyBAGLk4BmIhXNcP/gLNFnXNNbJUPLN/9 7m7Fq8bgbaaHBXXlarbsz3T7ZzH3LcN/R3PBwwe0ZvjzuR65cs/j7C6OMJULjfZyLTWWGezX/3x lAgA= X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C kvm_pmu_probe_armpmu() currently samples the current CPU internally, which ties the helper to default PMU selection. Move that policy to kvm_arm_set_default_pmu() by passing raw_smp_processor_id() from the caller, and make the helper search for the pPMU covering an explicit CPU. Move the helper above kvm_pmu_create_perf_event() so later code can reuse it when creating PMU events for a VCPU's current pCPU. This preserves the existing default PMU selection behavior while preparing fixed-counters-only mode to select a pPMU at runtime. Signed-off-by: Akihiko Odaki --- arch/arm64/kvm/pmu-emul.c | 72 +++++++++++++++++++++++--------------------= ---- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index 1d03d0cb62f3..1dd8aa6a027d 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -677,6 +677,23 @@ static int kvm_map_pmu_event(struct arm_pmu *pmu, unsi= gned int eventsel) return eventsel; } =20 +static struct arm_pmu *kvm_pmu_probe_armpmu(int cpu) +{ + struct arm_pmu_entry *entry; + struct arm_pmu *pmu; + + guard(rcu)(); + + list_for_each_entry_rcu(entry, &arm_pmus, entry) { + pmu =3D entry->arm_pmu; + + if (cpumask_test_cpu(cpu, &pmu->supported_cpus)) + return pmu; + } + + return NULL; +} + /** * kvm_pmu_create_perf_event - create a perf event for a counter * @pmc: Counter context @@ -806,42 +823,6 @@ void kvm_host_pmu_init(struct arm_pmu *pmu) list_add_tail_rcu(&entry->entry, &arm_pmus); } =20 -static struct arm_pmu *kvm_pmu_probe_armpmu(void) -{ - struct arm_pmu_entry *entry; - struct arm_pmu *pmu; - int cpu; - - guard(rcu)(); - - /* - * It is safe to use a stale cpu to iterate the list of PMUs so long as - * the same value is used for the entirety of the loop. Given this, and - * the fact that no percpu data is used for the lookup there is no need - * to disable preemption. - * - * It is still necessary to get a valid cpu, though, to probe for the - * default PMU instance as userspace is not required to specify a PMU - * type. In order to uphold the preexisting behavior KVM selects the - * PMU instance for the core during vcpu init. A dependent use - * case would be a user with disdain of all things big.LITTLE that - * affines the VMM to a particular cluster of cores. - * - * In any case, userspace should just do the sane thing and use the UAPI - * to select a PMU type directly. But, be wary of the baggage being - * carried here. - */ - cpu =3D raw_smp_processor_id(); - list_for_each_entry_rcu(entry, &arm_pmus, entry) { - pmu =3D entry->arm_pmu; - - if (cpumask_test_cpu(cpu, &pmu->supported_cpus)) - return pmu; - } - - return NULL; -} - static u64 __compute_pmceid(struct arm_pmu *pmu, bool pmceid1) { u32 hi[2], lo[2]; @@ -1076,7 +1057,24 @@ static void kvm_arm_set_pmu(struct kvm *kvm, struct = arm_pmu *arm_pmu) */ int kvm_arm_set_default_pmu(struct kvm *kvm) { - struct arm_pmu *arm_pmu =3D kvm_pmu_probe_armpmu(); + /* + * It is safe to use a stale cpu to iterate the list of PMUs so long as + * the same value is used for the entirety of the loop. Given this, and + * the fact that no percpu data is used for the lookup there is no need + * to disable preemption. + * + * It is still necessary to get a valid cpu, though, to probe for the + * default PMU instance as userspace is not required to specify a PMU + * type. In order to uphold the preexisting behavior KVM selects the + * PMU instance for the core during vcpu init. A dependent use + * case would be a user with disdain of all things big.LITTLE that + * affines the VMM to a particular cluster of cores. + * + * In any case, userspace should just do the sane thing and use the UAPI + * to select a PMU type directly. But, be wary of the baggage being + * carried here. + */ + struct arm_pmu *arm_pmu =3D kvm_pmu_probe_armpmu(raw_smp_processor_id()); =20 if (!arm_pmu) return -ENODEV; --=20 2.55.0 From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 1C8B0416CE4; Fri, 10 Jul 2026 11:16:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682188; cv=none; b=jT7H+tfmlHH/LMEJ8le0Mkflc0T7kD0vdKnj8DQUxSQDD9NDP1kLij8SXGEN6JXClZdund2M5knBkr7/XWG+PmO7A6ImXbVurdbt8pm9b3pAJDbUboE8y2Sju5Z1TQUPhAA+d13aIgKYTdmyaEW63/EQuVVJiQrJkOgSmQhqeBM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682188; c=relaxed/simple; bh=1xofsopO2LYUhV98oaA7uLf7eeShoy+dvPyeps8ZL/w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=o4H8qB7bRyRREZMso1iDPWKzaZNWUS2L3cziHpkk0trVowIPni6uPkQFAWomVP+hIuJfThWe9T7fJSBnQ0b8lGJQwy4U1qTl3JKG5pSoil6+Hu31YnHi5yRgre5BX7rBMqgrZmA+xik7TojpdaJbjTgeRAkKidgnIjWp0DmiiLs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=s8KhwOEQ reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="s8KhwOEQ" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsN024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:12 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=noT/QqAliZBhFyawFYslzQgo6v2k6ipjVMsOMMsynIw=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682112; v=1; b=s8KhwOEQ0TjZ0sa5iX9TriaWVWFZ7j48jRfLsphEyI5FuZn9G+Fldfwg/DG9H0vd prIJOloH+Qfq9puU6SYOdH/SOcCwfKwQOLL7FQvRm+zTh2Jc9f+UoOavoEBh6+s7 Siu3ll6DOafoctznF7SlNHORlqwKImPeRcUhudMQlokhomGW0nAdGljxvfCz8Ph0 fH9ct3+NFK0nyJM4NO/m4rA0Ccn7qibUFreMKG3Mv2OzYSxyXGA7X6mNez6T9pHl 5YxoTRNXNA9oIVD98uj/afd9c1QFbDDEBosrMMf2JJTNE8AWc4crPY6qbTVaSv37 BMd+OKYIDaFgYLLL3DDMGA== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:15:03 +0900 Subject: [PATCH v8 09/11] KVM: arm64: PMU: Implement fixed-counters-only emulation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-9-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=8614; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=1xofsopO2LYUhV98oaA7uLf7eeShoy+dvPyeps8ZL/w=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFSuvbQqHmZNzbGWmNpRlqCx59PJh3etFfyrm6cV2b ZOMFF7bUcrCIMbFICumyJJStJtbI7r2U2FCfAvMHFYmkCEMXJwCMJHmHQz/YyoO3md3ejGF/c7p uVb+ikqnDq17esvb6ExJpZnZzXcv+Rh+s9yN1Ty+zW76jr97oou1dzutvyxxyJ7/w911D2p418+ 1ZgMA X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Add internal state for PMUv3 emulation without programmable event counters. When fixed-counters-only mode is active, KVM reports no programmable counters and hides PMCEID, avoiding event-counter state whose behavior can depend on the selected hardware PMU. The cycle counter still uses a host perf event. Unlike the normal PMU path, fixed-counters-only mode may create that event from the hardware PMU attached to the VCPU's current pCPU. If the VCPU later loads on a pCPU that is not covered by the existing event's PMU, request a PMU reload so the cycle counter can be recreated against the new pCPU's PMU. Keep this affinity check limited to fixed-counters-only VMs; the normal programmable-counter mode continues to use the VM-wide PMU and does not need per-load reload decisions. Add a separate internal flag for explicit userspace PMU selection. The UAPI wiring added later will use it to keep explicit PMU selection and fixed-counters-only mode mutually exclusive while still allowing fixed-counters-only mode to replace the default PMU selected during KVM_ARM_VCPU_INIT. The UAPI wiring that sets the fixed-counters-only flag and records explicit PMU selection is added later in the series. Assisted-by: Codex:gpt-5.5 Signed-off-by: Akihiko Odaki --- arch/arm64/include/asm/kvm_host.h | 4 +++ arch/arm64/kvm/arm.c | 2 ++ arch/arm64/kvm/pmu-emul.c | 69 ++++++++++++++++++++++++++++++++++-= ---- include/kvm/arm_pmu.h | 2 ++ 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm= _host.h index 0c39d9db7d57..aa07b05b8231 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -353,6 +353,10 @@ struct kvm_arch { #define KVM_ARCH_FLAG_WRITABLE_IMP_ID_REGS 10 /* Unhandled SEAs are taken to userspace */ #define KVM_ARCH_FLAG_EXIT_SEA 11 + /* PMUv3 is emulated with an explicitly specified hardware PMU */ +#define KVM_ARCH_FLAG_PMU_V3_EXPLICIT 12 + /* PMUv3 is emulated without progammable event counters */ +#define KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY 13 unsigned long flags; =20 /* VM-wide vCPU feature set */ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 58d0783f254d..b21bd8cf13c9 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -638,6 +638,7 @@ static bool kvm_vcpu_should_clear_twe(struct kvm_vcpu *= vcpu) void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { struct kvm_s2_mmu *mmu; + int last_cpu =3D vcpu->cpu; int *last_ran; =20 if (is_protected_kvm_enabled()) @@ -687,6 +688,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (has_vhe()) kvm_vcpu_load_vhe(vcpu); kvm_arch_vcpu_load_fp(vcpu); + kvm_vcpu_load_pmu(vcpu, last_cpu); kvm_vcpu_pmu_restore_guest(vcpu); if (kvm_arm_is_pvtime_enabled(&vcpu->arch)) kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu); diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index 1dd8aa6a027d..1aa115aee781 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -83,6 +83,11 @@ u64 kvm_pmu_evtyper_mask(struct kvm *kvm) return mask; } =20 +static bool kvm_pmu_fixed_counters_only(struct kvm *kvm) +{ + return test_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &kvm->arch.flag= s); +} + /** * kvm_pmc_is_64bit - determine if counter is 64bit * @pmc: counter context @@ -330,7 +335,12 @@ u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *= vcpu) =20 static void kvm_pmc_enable_perf_event(struct kvm_pmc *pmc) { - if (!pmc->perf_event) { + struct kvm_vcpu *vcpu =3D kvm_pmc_to_vcpu(pmc); + + if (!pmc->perf_event || + (kvm_pmu_fixed_counters_only(vcpu->kvm) && + !cpumask_test_cpu(READ_ONCE(vcpu->cpu), + &to_arm_pmu(pmc->perf_event->pmu)->supported_cpus))) { kvm_pmu_create_perf_event(pmc); return; } @@ -694,14 +704,10 @@ static struct arm_pmu *kvm_pmu_probe_armpmu(int cpu) return NULL; } =20 -/** - * kvm_pmu_create_perf_event - create a perf event for a counter - * @pmc: Counter context - */ -static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc) +static void kvm_pmu_create_perf_event_with_pmu(struct kvm_pmc *pmc, + struct arm_pmu *arm_pmu) { struct kvm_vcpu *vcpu =3D kvm_pmc_to_vcpu(pmc); - struct arm_pmu *arm_pmu =3D vcpu->kvm->arch.arm_pmu; struct perf_event *event; struct perf_event_attr attr; int eventsel; @@ -735,7 +741,7 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *p= mc) * Don't create an event if we're running on hardware that requires * PMUv3 event translation and we couldn't find a valid mapping. */ - eventsel =3D kvm_map_pmu_event(vcpu->kvm->arch.arm_pmu, eventsel); + eventsel =3D kvm_map_pmu_event(arm_pmu, eventsel); if (eventsel < 0) return; =20 @@ -780,6 +786,29 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *= pmc) pmc->perf_event =3D event; } =20 +/** + * kvm_pmu_create_perf_event - create a perf event for a counter + * @pmc: Counter context + */ +static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc) +{ + struct kvm_vcpu *vcpu =3D kvm_pmc_to_vcpu(pmc); + struct arm_pmu *arm_pmu =3D vcpu->kvm->arch.arm_pmu; + + if (kvm_pmu_fixed_counters_only(vcpu->kvm)) { + do { + arm_pmu =3D kvm_pmu_probe_armpmu(READ_ONCE(vcpu->cpu)); + + if (WARN_ON_ONCE(!arm_pmu)) + return; + + kvm_pmu_create_perf_event_with_pmu(pmc, arm_pmu); + } while (!cpumask_test_cpu(READ_ONCE(vcpu->cpu), &arm_pmu->supported_cpu= s)); + } else { + kvm_pmu_create_perf_event_with_pmu(pmc, arm_pmu); + } +} + /** * kvm_pmu_set_counter_event_type - set selected counter to monitor some e= vent * @vcpu: The vcpu pointer @@ -813,6 +842,15 @@ void kvm_host_pmu_init(struct arm_pmu *pmu) if (!pmuv3_implemented(kvm_arm_pmu_get_pmuver_limit())) return; =20 + /* + * IMPDEF PMUv3 traps are non-architectural, and KVM cannot assume a + * uniform PMUv3-compatible arm_pmu is available on all CPUs. + */ + if (cpus_have_final_cap(ARM64_WORKAROUND_PMUV3_IMPDEF_TRAPS)) { + kvm_info("Non-architectural PMU, tainting kernel\n"); + add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK); + } + guard(mutex)(&arm_pmus_lock); =20 entry =3D kmalloc_obj(*entry); @@ -865,6 +903,9 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmce= id1) u64 val, mask =3D 0; int base, i, nr_events; =20 + if (kvm_pmu_fixed_counters_only(vcpu->kvm)) + return 0; + if (!pmceid1) { val =3D compute_pmceid0(cpu_pmu); base =3D 0; @@ -892,6 +933,15 @@ u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmc= eid1) return val & mask; } =20 +void kvm_vcpu_load_pmu(struct kvm_vcpu *vcpu, int last_cpu) +{ + if (!kvm_pmu_fixed_counters_only(vcpu->kvm) || vcpu->cpu =3D=3D last_cpu = || last_cpu =3D=3D -1) + return; + + if (kvm_pmu_probe_armpmu(vcpu->cpu) !=3D kvm_pmu_probe_armpmu(last_cpu)) + kvm_make_request(KVM_REQ_RELOAD_PMU, vcpu); +} + void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu) { u64 mask =3D kvm_pmu_implemented_counter_mask(vcpu); @@ -1003,6 +1053,9 @@ u8 kvm_arm_pmu_get_max_counters(struct kvm *kvm) { struct arm_pmu *arm_pmu =3D kvm->arch.arm_pmu; =20 + if (kvm_pmu_fixed_counters_only(kvm)) + return 0; + /* * PMUv3 requires that all event counters are capable of counting any * event, though the same may not be true of non-PMUv3 hardware. diff --git a/include/kvm/arm_pmu.h b/include/kvm/arm_pmu.h index 0a36a3d5c894..9720fbd0eeb4 100644 --- a/include/kvm/arm_pmu.h +++ b/include/kvm/arm_pmu.h @@ -59,6 +59,7 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u6= 4 val); void kvm_pmu_handle_pmcr(struct kvm_vcpu *vcpu, u64 val); void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data, u64 select_idx); +void kvm_vcpu_load_pmu(struct kvm_vcpu *vcpu, int last_cpu); void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu); int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); @@ -164,6 +165,7 @@ static inline u64 kvm_pmu_get_pmceid(struct kvm_vcpu *v= cpu, bool pmceid1) static inline void kvm_pmu_update_vcpu_events(struct kvm_vcpu *vcpu) {} static inline void kvm_vcpu_pmu_restore_guest(struct kvm_vcpu *vcpu) {} static inline void kvm_vcpu_pmu_restore_host(struct kvm_vcpu *vcpu) {} +static inline void kvm_vcpu_load_pmu(struct kvm_vcpu *vcpu, int last_cpu) = {} static inline void kvm_vcpu_reload_pmu(struct kvm_vcpu *vcpu) {} static inline u8 kvm_arm_pmu_get_pmuver_limit(void) { --=20 2.55.0 From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 B049341CB45; Fri, 10 Jul 2026 11:16:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682187; cv=none; b=PYp4PYpXLk00CdEuBLWpatd2gIsp1QbrLugiE+PAetMk2kwXRPh0Q8hEGfUFuRRUromOdaeB7aw9mCaRMPyVa9bdQiuIbOaEwhzel0kgc4C3dMZQo7TjN73jUdHavEZg5tPp6+2fPwSqJzLOQQnjQxSV05Rtco+0+ejIEUU9pjw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682187; c=relaxed/simple; bh=B8A4xQQyLQ7mNnYi90UFTZuklYoUvw5NjW2J0+zyWPA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VY7TM4sib+ytwVz7SVXosNcx5k2kNFpjeV8EFes/tqWWDFxfgrkqVQXeD8qrvHkMqDyXLlNtDtu6aIeYILSs6b5VSKFpgrKQyPhdb/p4sVUyEhlGptgzYx6UmsdAyfUuLcsbdb6OVk1UxCHIqQ8dGx/ch9kX57L4xhsUgeGO/Kg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=fIdNJgdb reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="fIdNJgdb" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsO024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:12 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=aTzvEUM9dIbO+u64aR1WJjKxebhXeOp9W1OXFa1SeEQ=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682112; v=1; b=fIdNJgdbJqRmcVCD9PDEdU5iedNZtR9OBN1P8Yos9TK1fOomIoOzL+f83H/C5ApE fclGC4ab8eUZ5d/WzHlj5STUx1WEHZMbIPQ3n16pJV17tt6MAoNx0UFqpsx4v0l0 ig1s3j/YbQlxLs6PBLEvnrORd35J1Fd42wkZyb9mxxYPpgTYL5UrORro/Hw2I6Qk LJl/xlf46rRHEGKdup5s5TyCidyE+t4xgAVOmX1xQ/TVT548FA/2iYTk8PeVLkd2 2DwXinHAeOl3N2xUIj47qSMJnpx97XAk60ifzL45DFPbZ2SqeIZcjw8RFHWuIpEQ Y0SHroqEjfrdMhbtP0nk6A== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:15:04 +0900 Subject: [PATCH v8 10/11] KVM: arm64: PMU: Introduce FIXED_COUNTERS_ONLY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-10-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=6574; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=B8A4xQQyLQ7mNnYi90UFTZuklYoUvw5NjW2J0+zyWPA=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFWvzDy2W97h2Xmpt045dpNSwYJ9L32Xpor+n+V7u2 rK4zySho5SFQYyLQVZMkSWlaDe3RnTtp8KE+BaYOaxMIEMYuDgFYCLqWYwMf0sDZnCf9BN6OmO7 0HGznXsU9BdMFNq+nSdJ+M7CU/vmbWH4p3VBLtfwg13O1L5fC7jVdh6pMdHW9RYufqTSzLLi3JN 8DgA= X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Introduce the KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY attribute to create a "fixed-counters-only" PMU. Much like KVM_ARM_VCPU_PMU_V3_IRQ and other read-write attributes, this attribute provides a getter that facilitates kernel and userspace debugging/testing. Signed-off-by: Akihiko Odaki --- Documentation/virt/kvm/devices/vcpu.rst | 30 ++++++++++++++++++++++++++---- arch/arm64/include/uapi/asm/kvm.h | 1 + arch/arm64/kvm/pmu-emul.c | 26 +++++++++++++++++++++++++- 3 files changed, 52 insertions(+), 5 deletions(-) diff --git a/Documentation/virt/kvm/devices/vcpu.rst b/Documentation/virt/k= vm/devices/vcpu.rst index 5e3805820010..b7ac4a545ffb 100644 --- a/Documentation/virt/kvm/devices/vcpu.rst +++ b/Documentation/virt/kvm/devices/vcpu.rst @@ -71,7 +71,8 @@ irqchip. -ENODEV PMUv3 not supported or GIC not initialized -ENXIO PMUv3 not properly configured or in-kernel irqchip not configured as required prior to calling this attribute - -EBUSY PMUv3 already initialized or a VCPU has already run + -EBUSY PMUv3 already initialized, a VCPU has already run or + FIXED_COUNTERS_ONLY has already been set -EINVAL Invalid filter range =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 @@ -113,14 +114,14 @@ using event 0x11 (CPU_CYCLES). =20 :Returns: =20 - =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D -EBUSY PMUv3 already initialized, a VCPU has already run or - an event filter has already been set + an event filter or FIXED_COUNTERS_ONLY has already been = set -EFAULT Error accessing the PMU identifier -ENXIO PMU not found -ENODEV PMUv3 not supported or GIC not initialized -ENOMEM Could not allocate memory - =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 Request that the VCPU uses the specified hardware PMU when creating guest = events for the purpose of PMU emulation. The PMU identifier can be read from the = "type" @@ -162,6 +163,27 @@ explicitly selected, or the number of counters is out = of range for the selected PMU. Selecting a new PMU cancels the effect of setting this attribute. =20 +1.6 ATTRIBUTE: KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY +------------------------------------------------------ + +:Parameters: no additional parameter in kvm_device_attr.addr + +:Returns: + + =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D + -EBUSY PMUv3 already initialized, a VCPU has already run, + an event filter has already been set or + a hardware PMU has already been specified + -ENXIO Attempted to get before setting + -ENODEV Attempted to set while PMUv3 not supported + =3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D + +If set, KVM emulates PMUv3 without programmable event counters. + +When this attribute is enabled, the vCPU can run on any physical CPU +that has a PMU, regardless of the underlying implementation. This +attribute is VM-scoped. + 2. GROUP: KVM_ARM_VCPU_TIMER_CTRL =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D =20 diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/as= m/kvm.h index 1c13bfa2d38a..39a1a1e412e6 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -437,6 +437,7 @@ enum { #define KVM_ARM_VCPU_PMU_V3_FILTER 2 #define KVM_ARM_VCPU_PMU_V3_SET_PMU 3 #define KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS 4 +#define KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY 5 #define KVM_ARM_VCPU_TIMER_CTRL 1 #define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0 #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1 diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index 1aa115aee781..89d63e5fffec 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -1150,11 +1150,13 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *= vcpu, int pmu_id) arm_pmu =3D entry->arm_pmu; if (arm_pmu->pmu.type =3D=3D pmu_id) { if (kvm_vm_has_ran_once(kvm) || + kvm_pmu_fixed_counters_only(kvm) || (kvm->arch.pmu_filter && kvm->arch.arm_pmu !=3D arm_pmu)) { ret =3D -EBUSY; break; } =20 + set_bit(KVM_ARCH_FLAG_PMU_V3_EXPLICIT, &kvm->arch.flags); kvm_arm_set_pmu(kvm, arm_pmu); cpumask_copy(kvm->arch.supported_cpus, &arm_pmu->supported_cpus); ret =3D 0; @@ -1165,6 +1167,22 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *v= cpu, int pmu_id) return ret; } =20 +static int kvm_arm_pmu_v3_set_pmu_fixed_counters_only(struct kvm_vcpu *vcp= u) +{ + struct kvm *kvm =3D vcpu->kvm; + + lockdep_assert_held(&kvm->arch.config_lock); + + if (kvm_vm_has_ran_once(kvm) || kvm->arch.pmu_filter || + test_bit(KVM_ARCH_FLAG_PMU_V3_EXPLICIT, &kvm->arch.flags)) + return -EBUSY; + + set_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &kvm->arch.flags); + kvm_arm_set_nr_counters(kvm, 0); + + return 0; +} + static int kvm_arm_pmu_v3_set_nr_counters(struct kvm_vcpu *vcpu, unsigned = int n) { struct kvm *kvm =3D vcpu->kvm; @@ -1239,7 +1257,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, st= ruct kvm_device_attr *attr) filter.action !=3D KVM_PMU_EVENT_DENY)) return -EINVAL; =20 - if (kvm_vm_has_ran_once(kvm)) + if (kvm_vm_has_ran_once(kvm) || kvm_pmu_fixed_counters_only(kvm)) return -EBUSY; =20 if (!kvm->arch.pmu_filter) { @@ -1284,6 +1302,8 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, st= ruct kvm_device_attr *attr) =20 return kvm_arm_pmu_v3_set_nr_counters(vcpu, n); } + case KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY: + return kvm_arm_pmu_v3_set_pmu_fixed_counters_only(vcpu); case KVM_ARM_VCPU_PMU_V3_INIT: return kvm_arm_pmu_v3_init(vcpu); } @@ -1310,6 +1330,9 @@ int kvm_arm_pmu_v3_get_attr(struct kvm_vcpu *vcpu, st= ruct kvm_device_attr *attr) irq =3D vcpu->arch.pmu.irq_num; return put_user(irq, uaddr); } + case KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY: + if (kvm_pmu_fixed_counters_only(vcpu->kvm)) + return 0; } =20 return -ENXIO; @@ -1323,6 +1346,7 @@ int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu, st= ruct kvm_device_attr *attr) case KVM_ARM_VCPU_PMU_V3_FILTER: case KVM_ARM_VCPU_PMU_V3_SET_PMU: case KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS: + case KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY: if (kvm_vcpu_has_pmu(vcpu)) return 0; } --=20 2.55.0 From nobody Sat Jul 11 16:40:37 2026 Received: from www3579.sakura.ne.jp (www3579.sakura.ne.jp [49.212.243.89]) (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 D684A41CB47; Fri, 10 Jul 2026 11:16:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=49.212.243.89 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682187; cv=none; b=iJcxXLrRxP27u4PqhdL03QofHenLF3BWq9hE9wvk4Nlmf4h0L/7VvQOwQ2YtzrvLnUoPAdu+YJMWsN9JjpVn1LJ+klm9YV3G+ou9nrtQBMODtPsLmFZH5zytvEeSRy05OxS5iWSB112ivwVT35Em6wnqfZzdr8UBHMODsnQtPAE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783682187; c=relaxed/simple; bh=ClenLVo1HfC3c2qutSiJAiIJgDmv0pNMBjk1Ifz9Yn4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EqqFniwGshNWQw3Nbkk3fEuhhGdxaokKSM7/jU+pA7vJuLe2d/0a5hf7orI5AUtrWzuqIzCdEhaBwNizYoz9ZnuVg2eEIobiLI8z+RqEXwT57iHNxSQqkNoWxtN1zEUjlV2I06fxu79H6TJkbhYxc9x+FOjFWufVn4zENxoANJY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp; dkim=fail (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b=CvwKh4Ip reason="key not found in DNS"; arc=none smtp.client-ip=49.212.243.89 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=rsg.ci.i.u-tokyo.ac.jp Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=rsg.ci.i.u-tokyo.ac.jp header.i=@rsg.ci.i.u-tokyo.ac.jp header.b="CvwKh4Ip" Received: from h183.csg.ci.i.u-tokyo.ac.jp (h183.csg.ci.i.u-tokyo.ac.jp [133.11.54.183]) (authenticated bits=0) by www3579.sakura.ne.jp (8.16.1/8.16.1) with ESMTPSA id 66ABEvsP024946 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Fri, 10 Jul 2026 20:15:12 +0900 (JST) (envelope-from odaki@rsg.ci.i.u-tokyo.ac.jp) DKIM-Signature: a=rsa-sha256; bh=dwGiJcX5Q9n0mzQCquwEv91287srodjDPF2c59V0lmM=; c=relaxed/relaxed; d=rsg.ci.i.u-tokyo.ac.jp; h=From:Message-Id:To:Subject:Date; s=rs20250326; t=1783682112; v=1; b=CvwKh4IpQbrpPyfAuedNUh2tKNxgSsDSHwuoJsqK7O7VNeQ3cyUXifdWoDnD+Vzr /16+6ZYDloY/nWd+xn50uswovRJy/CIjQRL4UBVb+y8S1kjCMl7bB+J+RLTUWd1x 7idXjRYkvYyCn/Z6fkCUKN942AWUvU/8f+y05DjgwSyvl1Ho5m7RNWaV8fp5DTGr QaRrrqrIcTCkmu0csUMS/Ub+BjXk5ACfyepG8E9ty+D7gvkbkuXD2X0LFKai1U+8 vQXxhRMnkGAZFxcp1GJLDF3v0LrUmFMRMOUqLcSlguQncgaZX+xPI0GsbjhWiHta 8+3qzNI9aAatxgea1YeZWQ== From: Akihiko Odaki Date: Fri, 10 Jul 2026 20:15:05 +0900 Subject: [PATCH v8 11/11] KVM: arm64: selftests: Test PMU_V3_FIXED_COUNTERS_ONLY Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260710-hybrid-v8-11-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> References: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> In-Reply-To: <20260710-hybrid-v8-0-621409f3a592@rsg.ci.i.u-tokyo.ac.jp> To: Marc Zyngier , Oliver Upton , Joey Gouly , Suzuki K Poulose , Zenghui Yu , Catalin Marinas , Will Deacon , Kees Cook , "Gustavo A. R. Silva" , Paolo Bonzini , Jonathan Corbet , Shuah Khan , Shuah Khan , Yury Norov , Rasmus Villemoes Cc: linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev, linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org, devel@daynix.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Akihiko Odaki X-Mailer: b4 0.16-dev-925f5 X-Developer-Signature: v=1; a=openpgp-sha256; l=9452; i=odaki@rsg.ci.i.u-tokyo.ac.jp; h=from:subject:message-id; bh=ClenLVo1HfC3c2qutSiJAiIJgDmv0pNMBjk1Ifz9Yn4=; b=owGbwMvMwCWmMbc20y1CyJDxtFoSQ1bAFZtvgn3qtQFmaWENiX6qyR9jX++dVTDv0omClk9xl qUBX152lLIwiHExyIopsqQU7ebWiK79VJgQ3wIzh5UJZAgDF6cATGTrcoZ/ag8M+Fxi2Vf+u3Ai 9FcI8+IZnHl3xJ7pnfqxyHmvEvP0Woa/svd1q4/8KWgTbSy4YJof+t0qaM1R022901iVNHqMBHb zAAA= X-Developer-Key: i=odaki@rsg.ci.i.u-tokyo.ac.jp; a=openpgp; fpr=AEDC03C9AF734F2EC26A7BFFA4BAEAA73536753C Assert the following: - FIXED_COUNTERS_ONLY is unset at initialization. - FIXED_COUNTERS_ONLY can be set. - Setting an event filter when FIXED_COUNTERS_ONLY has already been set results in EBUSY. - Setting FIXED_COUNTERS_ONLY when an event filter has already been set results in EBUSY. - Setting FIXED_COUNTERS_ONLY when a VCPU has already run results in EBUSY. Assisted-by: Codex:gpt-5.5 Signed-off-by: Akihiko Odaki --- .../selftests/kvm/arm64/vpmu_counter_access.c | 161 +++++++++++++++++= ---- 1 file changed, 131 insertions(+), 30 deletions(-) diff --git a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c b/tool= s/testing/selftests/kvm/arm64/vpmu_counter_access.c index 25203ea117b0..67f66a4f041b 100644 --- a/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c +++ b/tools/testing/selftests/kvm/arm64/vpmu_counter_access.c @@ -411,12 +411,7 @@ static void create_vpmu_vm(void *guest_code) { struct kvm_vcpu_init init; u8 pmuver, ec; - u64 dfr0, irq =3D 23; - struct kvm_device_attr irq_attr =3D { - .group =3D KVM_ARM_VCPU_PMU_V3_CTRL, - .attr =3D KVM_ARM_VCPU_PMU_V3_IRQ, - .addr =3D (u64)&irq, - }; + u64 dfr0; =20 /* The test creates the vpmu_vm multiple times. Ensure a clean state */ memset(&vpmu_vm, 0, sizeof(vpmu_vm)); @@ -442,8 +437,6 @@ static void create_vpmu_vm(void *guest_code) TEST_ASSERT(pmuver !=3D ID_AA64DFR0_EL1_PMUVer_IMP_DEF && pmuver >=3D ID_AA64DFR0_EL1_PMUVer_IMP, "Unexpected PMUVER (0x%x) on the vCPU with PMUv3", pmuver); - - vcpu_ioctl(vpmu_vm.vcpu, KVM_SET_DEVICE_ATTR, &irq_attr); } =20 static void destroy_vpmu_vm(void) @@ -469,15 +462,30 @@ static void run_vcpu(struct kvm_vcpu *vcpu, u64 pmcr_= n) } } =20 -static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters,= bool expect_fail) +static void guest_code_done(void) +{ + GUEST_DONE(); +} + +static void test_create_vpmu_vm_with_nr_counters(unsigned int nr_counters, + bool fixed_counters_only, + bool expect_fail) { struct kvm_vcpu *vcpu; unsigned int prev; int ret; + u64 irq =3D 23; =20 create_vpmu_vm(guest_code); vcpu =3D vpmu_vm.vcpu; =20 + if (fixed_counters_only) + vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL); + + vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_IRQ, &irq); + prev =3D get_pmcr_n(vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_PMCR_EL0))); =20 ret =3D __vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, @@ -497,15 +505,15 @@ static void test_create_vpmu_vm_with_nr_counters(unsi= gned int nr_counters, bool * Create a guest with one vCPU, set the PMCR_EL0.N for the vCPU to @pmcr_= n, * and run the test. */ -static void run_access_test(u64 pmcr_n) +static void run_access_test(u64 pmcr_n, bool fixed_counters_only) { u64 sp; struct kvm_vcpu *vcpu; struct kvm_vcpu_init init; =20 - pr_debug("Test with pmcr_n %lu\n", pmcr_n); + pr_debug("Test with pmcr_n %lu, fixed_counters_only %d\n", pmcr_n, fixed_= counters_only); =20 - test_create_vpmu_vm_with_nr_counters(pmcr_n, false); + test_create_vpmu_vm_with_nr_counters(pmcr_n, fixed_counters_only, false); vcpu =3D vpmu_vm.vcpu; =20 /* Save the initial sp to restore them later to run the guest again */ @@ -539,14 +547,14 @@ static struct pmreg_sets validity_check_reg_sets[] = =3D { * Create a VM, and check if KVM handles the userspace accesses of * the PMU register sets in @validity_check_reg_sets[] correctly. */ -static void run_pmregs_validity_test(u64 pmcr_n) +static void run_pmregs_validity_test(u64 pmcr_n, bool fixed_counters_only) { int i; struct kvm_vcpu *vcpu; u64 set_reg_id, clr_reg_id, reg_val; u64 valid_counters_mask, max_counters_mask; =20 - test_create_vpmu_vm_with_nr_counters(pmcr_n, false); + test_create_vpmu_vm_with_nr_counters(pmcr_n, fixed_counters_only, false); vcpu =3D vpmu_vm.vcpu; =20 valid_counters_mask =3D get_counters_mask(pmcr_n); @@ -591,16 +599,17 @@ static void run_pmregs_validity_test(u64 pmcr_n) destroy_vpmu_vm(); } =20 -static void run_mdcr_el2_validity_test(u64 pmcr_n) +static void run_mdcr_el2_validity_test(u64 pmcr_n, bool fixed_counters_onl= y) { struct kvm_vcpu_init init; struct kvm_vcpu *vcpu; u64 mdcr, old_mdcr; int ret; =20 - pr_debug("MDCR_EL2 test with pmcr_n %lu\n", pmcr_n); + pr_debug("MDCR_EL2 test with pmcr_n %lu, fixed_counters_only %d\n", + pmcr_n, fixed_counters_only); =20 - test_create_vpmu_vm_with_nr_counters(pmcr_n, false); + test_create_vpmu_vm_with_nr_counters(pmcr_n, fixed_counters_only, false); if (!vm_supports_el2(vpmu_vm.vm)) { destroy_vpmu_vm(); return; @@ -663,11 +672,11 @@ static void run_mdcr_el2_validity_test(u64 pmcr_n) * the vCPU to @pmcr_n, which is larger than the host value. * The attempt should fail as @pmcr_n is too big to set for the vCPU. */ -static void run_error_test(u64 pmcr_n) +static void run_error_test(u64 pmcr_n, bool fixed_counters_only) { pr_debug("Error test with pmcr_n %lu (larger than the host)\n", pmcr_n); =20 - test_create_vpmu_vm_with_nr_counters(pmcr_n, true); + test_create_vpmu_vm_with_nr_counters(pmcr_n, fixed_counters_only, true); destroy_vpmu_vm(); } =20 @@ -697,23 +706,115 @@ static bool kvm_supports_nr_counters_attr(void) return supported; } =20 -int main(void) +static void test_config(u64 pmcr_n, bool fixed_counters_only) { - u64 i, pmcr_n; - - TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3)); - TEST_REQUIRE(kvm_supports_vgic_v3()); - TEST_REQUIRE(kvm_supports_nr_counters_attr()); + u64 i; =20 - pmcr_n =3D get_pmcr_n_limit(); for (i =3D 0; i <=3D pmcr_n; i++) { - run_access_test(i); - run_pmregs_validity_test(i); - run_mdcr_el2_validity_test(i); + run_access_test(i, fixed_counters_only); + run_pmregs_validity_test(i, fixed_counters_only); + run_mdcr_el2_validity_test(i, fixed_counters_only); } =20 for (i =3D pmcr_n + 1; i < ARMV8_PMU_MAX_COUNTERS; i++) - run_error_test(i); + run_error_test(i, fixed_counters_only); +} + +static void test_fixed_counters_only(void) +{ + struct kvm_pmu_event_filter filter =3D { .nevents =3D 0 }; + struct kvm_vm *vm; + struct kvm_vcpu *running_vcpu; + struct kvm_vcpu *stopped_vcpu; + struct kvm_vcpu_init init; + int ret; + u64 irq =3D 23; + + create_vpmu_vm(guest_code); + ret =3D __vcpu_has_device_attr(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY); + if (ret) { + TEST_ASSERT(ret =3D=3D -1 && errno =3D=3D ENXIO, + KVM_IOCTL_ERROR(KVM_HAS_DEVICE_ATTR, ret)); + destroy_vpmu_vm(); + return; + } + + /* Assert that FIXED_COUNTERS_ONLY is unset at initialization. */ + ret =3D __vcpu_device_attr_get(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL); + TEST_ASSERT(ret =3D=3D -1 && errno =3D=3D ENXIO, + KVM_IOCTL_ERROR(KVM_GET_DEVICE_ATTR, ret)); + + /* Assert that setting FIXED_COUNTERS_ONLY succeeds. */ + vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL); + + /* Assert that FIXED_COUNTERS_ONLY is set. */ + vcpu_device_attr_get(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL); + + /* + * Setting an event filter when FIXED_COUNTERS_ONLY has already been set + * results in EBUSY. + */ + ret =3D __vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_FILTER, &filter); + TEST_ASSERT(ret =3D=3D -1 && errno =3D=3D EBUSY, + KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret)); + + destroy_vpmu_vm(); + + create_vpmu_vm(guest_code); + + /* + * Assert that setting FIXED_COUNTERS_ONLY when an event filter has + * already been set results in EBUSY. + */ + vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_FILTER, &filter); + + ret =3D __vcpu_device_attr_set(vpmu_vm.vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL); + TEST_ASSERT(ret =3D=3D -1 && errno =3D=3D EBUSY, + KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret)); + + destroy_vpmu_vm(); + + /* + * Assert that setting FIXED_COUNTERS_ONLY when a VCPU has already run + * results in EBUSY. + */ + vm =3D vm_create(2); + vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init); + init.features[0] |=3D (1 << KVM_ARM_VCPU_PMU_V3); + running_vcpu =3D aarch64_vcpu_add(vm, 0, &init, guest_code_done); + stopped_vcpu =3D aarch64_vcpu_add(vm, 1, &init, guest_code_done); + kvm_arch_vm_finalize_vcpus(vm); + vcpu_device_attr_set(running_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_IRQ, &irq); + vcpu_device_attr_set(running_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_INIT, NULL); + vcpu_run(running_vcpu); + + ret =3D __vcpu_device_attr_set(stopped_vcpu, KVM_ARM_VCPU_PMU_V3_CTRL, + KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY, NULL); + TEST_ASSERT(ret =3D=3D -1 && errno =3D=3D EBUSY, + KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret)); + + kvm_vm_free(vm); + + test_config(0, true); +} + +int main(void) +{ + TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_PMU_V3)); + TEST_REQUIRE(kvm_supports_vgic_v3()); + TEST_REQUIRE(kvm_supports_nr_counters_attr()); + + test_config(get_pmcr_n_limit(), false); + test_fixed_counters_only(); =20 return 0; } --=20 2.55.0