All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Lorenzo Stoakes (ARM)" <ljs@kernel.org>
To: Mark Brown <broonie@kernel.org>
Cc: Marc Zyngier <maz@kernel.org>, Oliver Upton <oupton@kernel.org>,
	 Joey Gouly <joey.gouly@arm.com>,
	Steffen Eiden <seiden@linux.ibm.com>,
	 Suzuki K Poulose <suzuki.poulose@arm.com>,
	Zenghui Yu <yuzenghui@huawei.com>,
	 Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will@kernel.org>, Fuad Tabba <fuad.tabba@linux.dev>,
	 Peter Maydell <peter.maydell@linaro.org>,
	linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
	 linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 3/3] KVM: arm64: selftests: Check ID regs are immutable after a failed run
Date: Mon, 28 Sep 2026 15:46:51 +0100	[thread overview]
Message-ID: <arp7mig_PrD9Jbc7@gremlin> (raw)
In-Reply-To: <20260901-kvm-arm64-idreg-final-v3-3-a0ffa06fa872@kernel.org>

On Tue, Sep 01, 2026 at 07:18:50PM +0100, Mark Brown wrote:
> From: Fuad Tabba <fuad.tabba@linux.dev>
>
> Add a set_id_regs case covering ID register immutability when a vCPU's
> first KVM_RUN fails after finalization but before
> KVM_ARCH_FLAG_HAS_RAN_ONCE is set. The test provokes such a failure with
> a PMUv3-enabled vCPU whose PMU is left uninitialized, then checks that
> KVM_SET_ONE_REG on the feature and implementation ID registers, and
> KVM_CREATE_DEVICE for a vGIC, are all rejected with -EBUSY.
>
> Assisted-by: Antigravity:gemini-3.1-pro

NIT: we changed the rules for the Assisted-by tag, it only needs to be
'Assisted-by: LLM' now. Not a huge big deal but FYI :>)

https://docs.kernel.org/process/coding-assistants.html

> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> Signed-off-by: Mark Brown <broonie@kernel.org>
> Link: https://patch.msgid.link/20260805064740.3013538-1-fuad.tabba@linux.dev

LGTM so:

Acked-by: Lorenzo Stoakes (ARM) <ljs@kernel.org>

> ---
>  tools/testing/selftests/kvm/arm64/set_id_regs.c | 106 +++++++++++++++++++++++-
>  1 file changed, 105 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
> index 7429a1055df5..10849d21c0dd 100644
> --- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
> +++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
> @@ -13,6 +13,7 @@
>  #include "kvm_util.h"
>  #include "processor.h"
>  #include "test_util.h"
> +#include "vgic.h"
>  #include <linux/bitfield.h>
>
>  enum ftr_type {
> @@ -803,6 +804,107 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
>  	ksft_test_result_pass("%s\n", __func__);
>  }
>
> +/*
> + * ID registers must stay immutable even when a vCPU's first KVM_RUN fails
> + * after finalization but before KVM_ARCH_FLAG_HAS_RAN_ONCE is set.
> + */
> +static void test_idreg_frozen_after_failed_run(void)
> +{
> +	static const u32 imp_id_regs[] = {
> +		SYS_MIDR_EL1,
> +		SYS_REVIDR_EL1,
> +		SYS_AIDR_EL1,
> +	};
> +	struct kvm_vcpu_init init;
> +	struct kvm_vcpu *vcpu;
> +	struct kvm_vm *vm;
> +	int r;
> +
> +	if (!kvm_has_cap(KVM_CAP_ARM_PMU_V3)) {
> +		ksft_print_msg("PMUv3 unsupported, cannot fail the first run\n");
> +		ksft_test_result_skip("%s\n", __func__);
> +		return;
> +	}
> +
> +	/* Skip the default vGIC so the KVM_CREATE_DEVICE gate is reachable. */
> +	test_disable_default_vgic();
> +
> +	vm = vm_create(1);
> +	vm_enable_cap(vm, KVM_CAP_ARM_WRITABLE_IMP_ID_REGS, 0);
> +	kvm_get_default_vcpu_target(vm, &init);
> +	init.features[0] |= (1 << KVM_ARM_VCPU_PMU_V3);
> +	vcpu = aarch64_vcpu_add(vm, 0, &init, guest_code);
> +	kvm_arch_vm_finalize_vcpus(vm);
> +
> +	/*
> +	 * A PMUv3 vCPU left without PMU init is rejected by
> +	 * kvm_arm_pmu_v3_enable(), which runs after sysreg finalization.
> +	 */
> +	r = _vcpu_run(vcpu);
> +	TEST_ASSERT(r < 0 && errno == EINVAL,
> +		    "first KVM_RUN should fail post-finalization: r=%d errno=%d",
> +		    r, errno);

Ah nice determinate way of triggering the issue.

> +
> +	/*
> +	 * Feature ID registers: use values that would have been accepted before
> +	 * finalization, so that a rejection means the registers are final
> +	 * rather than the value being invalid.
> +	 */
> +	for (int i = 0; i < ARRAY_SIZE(test_regs); i++) {
> +		const struct reg_ftr_bits *ftr_bits = test_regs[i].ftr_bits;
> +		u64 reg = KVM_ARM64_SYS_REG(test_regs[i].reg);
> +		u64 val = vcpu_get_reg(vcpu, reg);
> +
> +		for (int j = 0; ftr_bits[j].type != FTR_END; j++) {
> +			u64 ftr = (val & ftr_bits[j].mask) >> ftr_bits[j].shift;
> +			u64 safe = get_safe_value(&ftr_bits[j], ftr);
> +			u64 new_val;
> +
> +			if (safe == ftr)
> +				continue;
> +
> +			new_val = (val & ~ftr_bits[j].mask) |
> +				  (safe << ftr_bits[j].shift);
> +
> +			r = __vcpu_set_reg(vcpu, reg, new_val);
> +			TEST_ASSERT(r < 0 && errno == EBUSY,
> +				    "%s write after failed first run: r=%d errno=%d",
> +				    ftr_bits[j].name, r, errno);
> +			TEST_ASSERT_EQ(vcpu_get_reg(vcpu, reg), val);
> +		}
> +
> +		/* A write matching the finalized value is still accepted. */
> +		vcpu_set_reg(vcpu, reg, val);
> +	}
> +
> +	/*
> +	 * The VM-wide implementation ID registers are gated separately. Bit 0
> +	 * is within the writable mask of all three, so flipping it is a change
> +	 * KVM would otherwise accept.
> +	 */

Nice.

> +	for (int i = 0; i < ARRAY_SIZE(imp_id_regs); i++) {
> +		u64 reg = KVM_ARM64_SYS_REG(imp_id_regs[i]);
> +		u64 val = vcpu_get_reg(vcpu, reg);
> +
> +		r = __vcpu_set_reg(vcpu, reg, val ^ 1);

Ah literally a flip.

> +		TEST_ASSERT(r < 0 && errno == EBUSY,
> +			    "implementation ID reg write after failed first run: r=%d errno=%d",
> +			    r, errno);
> +		TEST_ASSERT_EQ(vcpu_get_reg(vcpu, reg), val);
> +	}
> +
> +	/* Creating an in-kernel irqchip would change the ID registers too. */
> +	if (kvm_supports_vgic_v3()) {
> +		r = __kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3);
> +		TEST_ASSERT(r < 0 && errno == EBUSY,
> +			    "vGIC creation after failed first run: r=%d errno=%d",
> +			    r, errno);

I guess in general it's making sure - where there should now be finalisation on
reg setting that this is actually enforced?

> +	}
> +
> +	kvm_vm_free(vm);
> +	ksft_test_result_pass("%s\n", __func__);
> +}
> +
>  int main(void)
>  {
>  	struct kvm_vcpu *vcpu;
> @@ -828,7 +930,7 @@ int main(void)
>
>  	ksft_print_header();
>
> -	test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST;
> +	test_cnt = 4 + MPAM_IDREG_TEST + MTE_IDREG_TEST;
>  	for (i = 0; i < ARRAY_SIZE(test_regs); i++)
>  		for (j = 0; test_regs[i].ftr_bits[j].type != FTR_END; j++)
>  			test_cnt++;
> @@ -847,5 +949,7 @@ int main(void)
>
>  	kvm_vm_free(vm);
>
> +	test_idreg_frozen_after_failed_run();
> +
>  	ksft_finished();
>  }
>
> --
> 2.47.3
>
>

--
Cheers, Lorenzo


  reply	other threads:[~2026-09-28 14:47 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-01 18:18 [PATCH v3 0/3] KVM: arm64: ID register finalisation fixes Mark Brown
2026-09-01 18:18 ` [PATCH v3 1/3] KVM: arm64: Finalize guest-wide sysregs prior to per-vCPU sysregs Mark Brown
2026-09-01 18:43   ` sashiko-bot
2026-09-28 13:26   ` Lorenzo Stoakes (ARM)
2026-09-01 18:18 ` [PATCH v3 2/3] KVM: arm64: Block ID register changes after we rely on the values Mark Brown
2026-09-28 14:36   ` Lorenzo Stoakes (ARM)
2026-09-28 16:22     ` Mark Brown
2026-09-01 18:18 ` [PATCH v3 3/3] KVM: arm64: selftests: Check ID regs are immutable after a failed run Mark Brown
2026-09-28 14:46   ` Lorenzo Stoakes (ARM) [this message]
2026-09-28 16:31     ` Mark Brown
2026-09-29  9:57       ` Lorenzo Stoakes (ARM)
2026-09-28 16:56     ` Fuad Tabba
2026-09-29  9:57       ` Lorenzo Stoakes (ARM)
2026-09-28 14:52 ` [PATCH v3 0/3] KVM: arm64: ID register finalisation fixes Lorenzo Stoakes (ARM)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=arp7mig_PrD9Jbc7@gremlin \
    --to=ljs@kernel.org \
    --cc=broonie@kernel.org \
    --cc=catalin.marinas@arm.com \
    --cc=fuad.tabba@linux.dev \
    --cc=joey.gouly@arm.com \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maz@kernel.org \
    --cc=oupton@kernel.org \
    --cc=peter.maydell@linaro.org \
    --cc=seiden@linux.ibm.com \
    --cc=suzuki.poulose@arm.com \
    --cc=will@kernel.org \
    --cc=yuzenghui@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.