* [PATCH v5 0/5] KVM: selftests: arm64: Improve diagnostics from set_id_regs
@ 2026-03-17 20:10 Mark Brown
2026-03-17 20:10 ` [PATCH v5 1/5] KVM: selftests: arm64: Report set_id_reg reads of test registers as tests Mark Brown
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Mark Brown @ 2026-03-17 20:10 UTC (permalink / raw)
To: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Paolo Bonzini,
Shuah Khan, Oliver Upton
Cc: Ben Horgan, linux-arm-kernel, kvmarm, kvm, linux-kselftest,
linux-kernel, Mark Brown
While debugging issues related to aarch64 only systems I ran into
speedbumps due to the lack of detail in the results reported when the
guest register read and reset value preservation tests were run, they
generated an immediately fatal assert without indicating which register
was being tested. Update these tests to report a result per register,
making it much easier to see what the problem being reported is.
A similar, though less severe, issue exists with the validation of the
individual bitfields in registers due to the use of immediately fatal
asserts. Update those asserts to be standard kselftest reports.
Finally we have a fix for spurious errors on some NV systems.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
Changes in v5:
- Rebase onto v7.0-rc1.
- Link to v4: https://patch.msgid.link/20260106-kvm-arm64-set-id-regs-aarch64-v4-0-c7ef4551afb3@kernel.org
Changes in v4:
- Correct check for 32 bit ID registers.
- Link to v3: https://patch.msgid.link/20251219-kvm-arm64-set-id-regs-aarch64-v3-0-bfa474ec3218@kernel.org
Changes in v3:
- Rebase onto v6.19-rc1.
- Link to v2: https://patch.msgid.link/20251114-kvm-arm64-set-id-regs-aarch64-v2-0-672f214f41bf@kernel.org
Changes in v2:
- Add a fix for spurious failures with 64 bit only guests.
- Link to v1: https://patch.msgid.link/20251030-kvm-arm64-set-id-regs-aarch64-v1-0-96fe0d2b178e@kernel.org
---
Mark Brown (5):
KVM: selftests: arm64: Report set_id_reg reads of test registers as tests
KVM: selftests: arm64: Report register reset tests individually
KVM: selftests: arm64: Make set_id_regs bitfield validatity checks non-fatal
KVM: selftests: arm64: Skip all 32 bit IDs when set_id_regs is aarch64 only
KVM: selftests: arm64: Use is_aarch32_id_reg() in test_vm_ftr_id_regs()
tools/testing/selftests/kvm/arm64/set_id_regs.c | 159 ++++++++++++++++++------
1 file changed, 119 insertions(+), 40 deletions(-)
---
base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
change-id: 20251028-kvm-arm64-set-id-regs-aarch64-ebb77969401c
Best regards,
--
Mark Brown <broonie@kernel.org>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v5 1/5] KVM: selftests: arm64: Report set_id_reg reads of test registers as tests
2026-03-17 20:10 [PATCH v5 0/5] KVM: selftests: arm64: Improve diagnostics from set_id_regs Mark Brown
@ 2026-03-17 20:10 ` Mark Brown
2026-03-17 20:10 ` [PATCH v5 2/5] KVM: selftests: arm64: Report register reset tests individually Mark Brown
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Mark Brown @ 2026-03-17 20:10 UTC (permalink / raw)
To: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Paolo Bonzini,
Shuah Khan, Oliver Upton
Cc: Ben Horgan, linux-arm-kernel, kvmarm, kvm, linux-kselftest,
linux-kernel, Mark Brown
Currently when we run guest code to validate that the values we wrote to
the registers are seen by the guest we assert that these values match using
a KVM selftests level assert, resulting in unclear diagnostics if the test
fails. Replace this assert with reporting a kselftest test per register.
In order to support getting the names of the registers we repaint the array
of ID_ registers to store the names and open code the rest.
Reviewed-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
tools/testing/selftests/kvm/arm64/set_id_regs.c | 74 +++++++++++++++++++------
1 file changed, 57 insertions(+), 17 deletions(-)
diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 73de5be58bab..75f23371d97d 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -40,6 +40,7 @@ struct reg_ftr_bits {
};
struct test_feature_reg {
+ const char *name;
uint32_t reg;
const struct reg_ftr_bits *ftr_bits;
};
@@ -217,24 +218,25 @@ static const struct reg_ftr_bits ftr_id_aa64zfr0_el1[] = {
#define TEST_REG(id, table) \
{ \
- .reg = id, \
+ .name = #id, \
+ .reg = SYS_ ## id, \
.ftr_bits = &((table)[0]), \
}
static struct test_feature_reg test_regs[] = {
- TEST_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0_el1),
- TEST_REG(SYS_ID_DFR0_EL1, ftr_id_dfr0_el1),
- TEST_REG(SYS_ID_AA64ISAR0_EL1, ftr_id_aa64isar0_el1),
- TEST_REG(SYS_ID_AA64ISAR1_EL1, ftr_id_aa64isar1_el1),
- TEST_REG(SYS_ID_AA64ISAR2_EL1, ftr_id_aa64isar2_el1),
- TEST_REG(SYS_ID_AA64ISAR3_EL1, ftr_id_aa64isar3_el1),
- TEST_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0_el1),
- TEST_REG(SYS_ID_AA64PFR1_EL1, ftr_id_aa64pfr1_el1),
- TEST_REG(SYS_ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0_el1),
- TEST_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1_el1),
- TEST_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2_el1),
- TEST_REG(SYS_ID_AA64MMFR3_EL1, ftr_id_aa64mmfr3_el1),
- TEST_REG(SYS_ID_AA64ZFR0_EL1, ftr_id_aa64zfr0_el1),
+ TEST_REG(ID_AA64DFR0_EL1, ftr_id_aa64dfr0_el1),
+ TEST_REG(ID_DFR0_EL1, ftr_id_dfr0_el1),
+ TEST_REG(ID_AA64ISAR0_EL1, ftr_id_aa64isar0_el1),
+ TEST_REG(ID_AA64ISAR1_EL1, ftr_id_aa64isar1_el1),
+ TEST_REG(ID_AA64ISAR2_EL1, ftr_id_aa64isar2_el1),
+ TEST_REG(ID_AA64ISAR3_EL1, ftr_id_aa64isar3_el1),
+ TEST_REG(ID_AA64PFR0_EL1, ftr_id_aa64pfr0_el1),
+ TEST_REG(ID_AA64PFR1_EL1, ftr_id_aa64pfr1_el1),
+ TEST_REG(ID_AA64MMFR0_EL1, ftr_id_aa64mmfr0_el1),
+ TEST_REG(ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1_el1),
+ TEST_REG(ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2_el1),
+ TEST_REG(ID_AA64MMFR3_EL1, ftr_id_aa64mmfr3_el1),
+ TEST_REG(ID_AA64ZFR0_EL1, ftr_id_aa64zfr0_el1),
};
#define GUEST_REG_SYNC(id) GUEST_SYNC_ARGS(0, id, read_sysreg_s(id), 0, 0);
@@ -264,6 +266,34 @@ static void guest_code(void)
GUEST_DONE();
}
+#define GUEST_READ_TEST (ARRAY_SIZE(test_regs) + 6)
+
+static const char *get_reg_name(u64 id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_regs); i++)
+ if (test_regs[i].reg == id)
+ return test_regs[i].name;
+
+ switch (id) {
+ case SYS_MPIDR_EL1:
+ return "MPIDR_EL1";
+ case SYS_CLIDR_EL1:
+ return "CLIDR_EL1";
+ case SYS_CTR_EL0:
+ return "CTR_EL0";
+ case SYS_MIDR_EL1:
+ return "MIDR_EL1";
+ case SYS_REVIDR_EL1:
+ return "REVIDR_EL1";
+ case SYS_AIDR_EL1:
+ return "AIDR_EL1";
+ default:
+ TEST_FAIL("Unknown register");
+ }
+}
+
/* Return a safe value to a given ftr_bits an ftr value */
uint64_t get_safe_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr)
{
@@ -638,6 +668,8 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu)
{
bool done = false;
struct ucall uc;
+ uint64_t reg_id, expected_val, guest_val;
+ bool match;
while (!done) {
vcpu_run(vcpu);
@@ -648,8 +680,16 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu)
break;
case UCALL_SYNC:
/* Make sure the written values are seen by guest */
- TEST_ASSERT_EQ(test_reg_vals[encoding_to_range_idx(uc.args[2])],
- uc.args[3]);
+ reg_id = uc.args[2];
+ guest_val = uc.args[3];
+ expected_val = test_reg_vals[encoding_to_range_idx(reg_id)];
+ match = expected_val == guest_val;
+ if (!match)
+ ksft_print_msg("%lx != %lx\n",
+ expected_val, guest_val);
+ ksft_test_result(match,
+ "%s value seen in guest\n",
+ get_reg_name(reg_id));
break;
case UCALL_DONE:
done = true;
@@ -789,7 +829,7 @@ int main(void)
ksft_print_header();
- test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST;
+ test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST + GUEST_READ_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++;
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 2/5] KVM: selftests: arm64: Report register reset tests individually
2026-03-17 20:10 [PATCH v5 0/5] KVM: selftests: arm64: Improve diagnostics from set_id_regs Mark Brown
2026-03-17 20:10 ` [PATCH v5 1/5] KVM: selftests: arm64: Report set_id_reg reads of test registers as tests Mark Brown
@ 2026-03-17 20:10 ` Mark Brown
2026-03-17 20:10 ` [PATCH v5 3/5] KVM: selftests: arm64: Make set_id_regs bitfield validatity checks non-fatal Mark Brown
` (2 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Mark Brown @ 2026-03-17 20:10 UTC (permalink / raw)
To: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Paolo Bonzini,
Shuah Khan, Oliver Upton
Cc: Ben Horgan, linux-arm-kernel, kvmarm, kvm, linux-kselftest,
linux-kernel, Mark Brown
set_id_regs tests that registers have their values preserved over reset.
Currently it reports all registers in a single test with an instantly fatal
assert which isn't great for diagnostics, it's hard to tell which register
failed or if it's just one register. Change this to report each register as
a separate test so that it's clear from the program output which registers
have problems.
Reviewed-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
tools/testing/selftests/kvm/arm64/set_id_regs.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 75f23371d97d..1072ee125b05 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -778,11 +778,18 @@ static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encodin
{
size_t idx = encoding_to_range_idx(encoding);
uint64_t observed;
+ bool pass;
observed = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(encoding));
- TEST_ASSERT_EQ(test_reg_vals[idx], observed);
+ pass = test_reg_vals[idx] == observed;
+ if (!pass)
+ ksft_print_msg("%lx != %lx\n", test_reg_vals[idx], observed);
+ ksft_test_result(pass, "%s unchanged by reset\n",
+ get_reg_name(encoding));
}
+#define ID_REG_RESET_UNCHANGED_TEST (ARRAY_SIZE(test_regs) + 6)
+
static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
{
/*
@@ -800,8 +807,6 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
test_assert_id_reg_unchanged(vcpu, SYS_MIDR_EL1);
test_assert_id_reg_unchanged(vcpu, SYS_REVIDR_EL1);
test_assert_id_reg_unchanged(vcpu, SYS_AIDR_EL1);
-
- ksft_test_result_pass("%s\n", __func__);
}
int main(void)
@@ -829,7 +834,8 @@ int main(void)
ksft_print_header();
- test_cnt = 3 + MPAM_IDREG_TEST + MTE_IDREG_TEST + GUEST_READ_TEST;
+ test_cnt = 2 + MPAM_IDREG_TEST + MTE_IDREG_TEST + GUEST_READ_TEST +
+ ID_REG_RESET_UNCHANGED_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++;
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 3/5] KVM: selftests: arm64: Make set_id_regs bitfield validatity checks non-fatal
2026-03-17 20:10 [PATCH v5 0/5] KVM: selftests: arm64: Improve diagnostics from set_id_regs Mark Brown
2026-03-17 20:10 ` [PATCH v5 1/5] KVM: selftests: arm64: Report set_id_reg reads of test registers as tests Mark Brown
2026-03-17 20:10 ` [PATCH v5 2/5] KVM: selftests: arm64: Report register reset tests individually Mark Brown
@ 2026-03-17 20:10 ` Mark Brown
2026-03-17 20:10 ` [PATCH v5 4/5] KVM: selftests: arm64: Skip all 32 bit IDs when set_id_regs is aarch64 only Mark Brown
2026-03-17 20:10 ` [PATCH v5 5/5] KVM: selftests: arm64: Use is_aarch32_id_reg() in test_vm_ftr_id_regs() Mark Brown
4 siblings, 0 replies; 8+ messages in thread
From: Mark Brown @ 2026-03-17 20:10 UTC (permalink / raw)
To: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Paolo Bonzini,
Shuah Khan, Oliver Upton
Cc: Ben Horgan, linux-arm-kernel, kvmarm, kvm, linux-kselftest,
linux-kernel, Mark Brown
Currently when set_id_regs encounters a problem checking validation of
writes to feature registers it uses an immediately fatal assert to report
the problem. This is not idiomatic for kselftest, and it is also not great
for usability. The affected bitfield is not clearly reported and further
tests do not have their results reported.
Switch to using standard kselftest result reporting for the two asserts
we do, these are non-fatal asserts so allow the program to continue and the
test names include the affected field.
Reviewed-by: Ben Horgan <ben.horgan@arm.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
---
tools/testing/selftests/kvm/arm64/set_id_regs.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 1072ee125b05..60e7f0c1bc26 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -408,6 +408,7 @@ static uint64_t test_reg_set_success(struct kvm_vcpu *vcpu, uint64_t reg,
uint8_t shift = ftr_bits->shift;
uint64_t mask = ftr_bits->mask;
uint64_t val, new_val, ftr;
+ bool match;
val = vcpu_get_reg(vcpu, reg);
ftr = (val & mask) >> shift;
@@ -420,7 +421,10 @@ static uint64_t test_reg_set_success(struct kvm_vcpu *vcpu, uint64_t reg,
vcpu_set_reg(vcpu, reg, val);
new_val = vcpu_get_reg(vcpu, reg);
- TEST_ASSERT_EQ(new_val, val);
+ match = new_val == val;
+ if (!match)
+ ksft_print_msg("%lx != %lx\n", new_val, val);
+ ksft_test_result(match, "%s valid write succeeded\n", ftr_bits->name);
return new_val;
}
@@ -432,6 +436,7 @@ static void test_reg_set_fail(struct kvm_vcpu *vcpu, uint64_t reg,
uint64_t mask = ftr_bits->mask;
uint64_t val, old_val, ftr;
int r;
+ bool match;
val = vcpu_get_reg(vcpu, reg);
ftr = (val & mask) >> shift;
@@ -448,7 +453,10 @@ static void test_reg_set_fail(struct kvm_vcpu *vcpu, uint64_t reg,
"Unexpected KVM_SET_ONE_REG error: r=%d, errno=%d", r, errno);
val = vcpu_get_reg(vcpu, reg);
- TEST_ASSERT_EQ(val, old_val);
+ match = val == old_val;
+ if (!match)
+ ksft_print_msg("%lx != %lx\n", val, old_val);
+ ksft_test_result(match, "%s invalid write rejected\n", ftr_bits->name);
}
static uint64_t test_reg_vals[KVM_ARM_FEATURE_ID_RANGE_SIZE];
@@ -488,7 +496,11 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only)
for (int j = 0; ftr_bits[j].type != FTR_END; j++) {
/* Skip aarch32 reg on aarch64 only system, since they are RAZ/WI. */
if (aarch64_only && sys_reg_CRm(reg_id) < 4) {
- ksft_test_result_skip("%s on AARCH64 only system\n",
+ ksft_print_msg("%s on AARCH64 only system\n",
+ ftr_bits[j].name);
+ ksft_test_result_skip("%s invalid write rejected\n",
+ ftr_bits[j].name);
+ ksft_test_result_skip("%s valid write succeeded\n",
ftr_bits[j].name);
continue;
}
@@ -500,8 +512,6 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only)
test_reg_vals[idx] = test_reg_set_success(vcpu, reg,
&ftr_bits[j]);
-
- ksft_test_result_pass("%s\n", ftr_bits[j].name);
}
}
}
@@ -838,7 +848,7 @@ int main(void)
ID_REG_RESET_UNCHANGED_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++;
+ test_cnt += 2;
ksft_set_plan(test_cnt);
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 4/5] KVM: selftests: arm64: Skip all 32 bit IDs when set_id_regs is aarch64 only
2026-03-17 20:10 [PATCH v5 0/5] KVM: selftests: arm64: Improve diagnostics from set_id_regs Mark Brown
` (2 preceding siblings ...)
2026-03-17 20:10 ` [PATCH v5 3/5] KVM: selftests: arm64: Make set_id_regs bitfield validatity checks non-fatal Mark Brown
@ 2026-03-17 20:10 ` Mark Brown
2026-03-24 16:47 ` Marc Zyngier
2026-03-17 20:10 ` [PATCH v5 5/5] KVM: selftests: arm64: Use is_aarch32_id_reg() in test_vm_ftr_id_regs() Mark Brown
4 siblings, 1 reply; 8+ messages in thread
From: Mark Brown @ 2026-03-17 20:10 UTC (permalink / raw)
To: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Paolo Bonzini,
Shuah Khan, Oliver Upton
Cc: Ben Horgan, linux-arm-kernel, kvmarm, kvm, linux-kselftest,
linux-kernel, Mark Brown
On an aarch64 only system the 32 bit ID registers have UNDEFINED values.
As a result set_id_regs skips tests for setting fields in these registers
when testing an aarch64 only guest. This has the side effect of meaning
that we don't record an expected value for these registers, meaning that
when the subsequent tests for values being visible in guests and preserved
over reset check the value they can spuriously fail. This can be seen by
running on an emulated system with both NV and 32 bit enabled, NV will
result in the guests created by the test program being 64 bit only but
the 32 bit ID registers will have values.
Also skip those tests that use the values set in the field setting tests
for aarch64 only guests in order to avoid these spurious failures.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
tools/testing/selftests/kvm/arm64/set_id_regs.c | 49 ++++++++++++++++++-------
1 file changed, 36 insertions(+), 13 deletions(-)
diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c
index 60e7f0c1bc26..127defebb35a 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -294,6 +294,13 @@ static const char *get_reg_name(u64 id)
}
}
+static inline bool is_aarch32_id_reg(u64 id)
+{
+ return (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 &&
+ sys_reg_CRn(id) == 0 && sys_reg_CRm(id) >= 1 &&
+ sys_reg_CRm(id) <= 3);
+}
+
/* Return a safe value to a given ftr_bits an ftr value */
uint64_t get_safe_value(const struct reg_ftr_bits *ftr_bits, uint64_t ftr)
{
@@ -674,7 +681,7 @@ static void test_user_set_mte_reg(struct kvm_vcpu *vcpu)
ksft_test_result_pass("ID_AA64PFR1_EL1.MTE_frac no longer 0xF\n");
}
-static void test_guest_reg_read(struct kvm_vcpu *vcpu)
+static void test_guest_reg_read(struct kvm_vcpu *vcpu, bool aarch64_only)
{
bool done = false;
struct ucall uc;
@@ -693,6 +700,13 @@ static void test_guest_reg_read(struct kvm_vcpu *vcpu)
reg_id = uc.args[2];
guest_val = uc.args[3];
expected_val = test_reg_vals[encoding_to_range_idx(reg_id)];
+
+ if (aarch64_only && is_aarch32_id_reg(reg_id)) {
+ ksft_test_result_skip("%s value seen in guest\n",
+ get_reg_name(reg_id));
+ break;
+ }
+
match = expected_val == guest_val;
if (!match)
ksft_print_msg("%lx != %lx\n",
@@ -784,12 +798,19 @@ static void test_vcpu_non_ftr_id_regs(struct kvm_vcpu *vcpu)
ksft_test_result_pass("%s\n", __func__);
}
-static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encoding)
+static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encoding,
+ bool aarch64_only)
{
size_t idx = encoding_to_range_idx(encoding);
uint64_t observed;
bool pass;
+ if (aarch64_only && is_aarch32_id_reg(encoding)) {
+ ksft_test_result_skip("%s unchanged by reset\n",
+ get_reg_name(encoding));
+ return;
+ }
+
observed = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(encoding));
pass = test_reg_vals[idx] == observed;
if (!pass)
@@ -800,7 +821,8 @@ static void test_assert_id_reg_unchanged(struct kvm_vcpu *vcpu, uint32_t encodin
#define ID_REG_RESET_UNCHANGED_TEST (ARRAY_SIZE(test_regs) + 6)
-static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
+static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu,
+ bool aarch64_only)
{
/*
* Calls KVM_ARM_VCPU_INIT behind the scenes, which will do an
@@ -809,14 +831,15 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
aarch64_vcpu_setup(vcpu, NULL);
for (int i = 0; i < ARRAY_SIZE(test_regs); i++)
- test_assert_id_reg_unchanged(vcpu, test_regs[i].reg);
-
- test_assert_id_reg_unchanged(vcpu, SYS_MPIDR_EL1);
- test_assert_id_reg_unchanged(vcpu, SYS_CLIDR_EL1);
- test_assert_id_reg_unchanged(vcpu, SYS_CTR_EL0);
- test_assert_id_reg_unchanged(vcpu, SYS_MIDR_EL1);
- test_assert_id_reg_unchanged(vcpu, SYS_REVIDR_EL1);
- test_assert_id_reg_unchanged(vcpu, SYS_AIDR_EL1);
+ test_assert_id_reg_unchanged(vcpu, test_regs[i].reg,
+ aarch64_only);
+
+ test_assert_id_reg_unchanged(vcpu, SYS_MPIDR_EL1, aarch64_only);
+ test_assert_id_reg_unchanged(vcpu, SYS_CLIDR_EL1, aarch64_only);
+ test_assert_id_reg_unchanged(vcpu, SYS_CTR_EL0, aarch64_only);
+ test_assert_id_reg_unchanged(vcpu, SYS_MIDR_EL1, aarch64_only);
+ test_assert_id_reg_unchanged(vcpu, SYS_REVIDR_EL1, aarch64_only);
+ test_assert_id_reg_unchanged(vcpu, SYS_AIDR_EL1, aarch64_only);
}
int main(void)
@@ -858,9 +881,9 @@ int main(void)
test_user_set_mpam_reg(vcpu);
test_user_set_mte_reg(vcpu);
- test_guest_reg_read(vcpu);
+ test_guest_reg_read(vcpu, aarch64_only);
- test_reset_preserves_id_regs(vcpu);
+ test_reset_preserves_id_regs(vcpu, aarch64_only);
kvm_vm_free(vm);
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v5 5/5] KVM: selftests: arm64: Use is_aarch32_id_reg() in test_vm_ftr_id_regs()
2026-03-17 20:10 [PATCH v5 0/5] KVM: selftests: arm64: Improve diagnostics from set_id_regs Mark Brown
` (3 preceding siblings ...)
2026-03-17 20:10 ` [PATCH v5 4/5] KVM: selftests: arm64: Skip all 32 bit IDs when set_id_regs is aarch64 only Mark Brown
@ 2026-03-17 20:10 ` Mark Brown
4 siblings, 0 replies; 8+ messages in thread
From: Mark Brown @ 2026-03-17 20:10 UTC (permalink / raw)
To: Marc Zyngier, Joey Gouly, Suzuki K Poulose, Paolo Bonzini,
Shuah Khan, Oliver Upton
Cc: Ben Horgan, linux-arm-kernel, kvmarm, kvm, linux-kselftest,
linux-kernel, Mark Brown
test_vm_ftr_id_regs() uses a simplified check for 32 bit ID registers since
it knows it will only run on ID registers. For clarity update this to use
the newly added is_aarch32_id_reg(), there should be no functional change.
Signed-off-by: Mark Brown <broonie@kernel.org>
---
tools/testing/selftests/kvm/arm64/set_id_regs.c | 2 +-
1 file changed, 1 insertion(+), 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 127defebb35a..50e9e9b6a365 100644
--- a/tools/testing/selftests/kvm/arm64/set_id_regs.c
+++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c
@@ -502,7 +502,7 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only)
for (int j = 0; ftr_bits[j].type != FTR_END; j++) {
/* Skip aarch32 reg on aarch64 only system, since they are RAZ/WI. */
- if (aarch64_only && sys_reg_CRm(reg_id) < 4) {
+ if (aarch64_only && is_aarch32_id_reg(reg_id)) {
ksft_print_msg("%s on AARCH64 only system\n",
ftr_bits[j].name);
ksft_test_result_skip("%s invalid write rejected\n",
--
2.47.3
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v5 4/5] KVM: selftests: arm64: Skip all 32 bit IDs when set_id_regs is aarch64 only
2026-03-17 20:10 ` [PATCH v5 4/5] KVM: selftests: arm64: Skip all 32 bit IDs when set_id_regs is aarch64 only Mark Brown
@ 2026-03-24 16:47 ` Marc Zyngier
2026-03-24 17:39 ` Mark Brown
0 siblings, 1 reply; 8+ messages in thread
From: Marc Zyngier @ 2026-03-24 16:47 UTC (permalink / raw)
To: Mark Brown
Cc: Joey Gouly, Suzuki K Poulose, Paolo Bonzini, Shuah Khan,
Oliver Upton, Ben Horgan, linux-arm-kernel, kvmarm, kvm,
linux-kselftest, linux-kernel
On Tue, 17 Mar 2026 20:10:37 +0000,
Mark Brown <broonie@kernel.org> wrote:
>
> On an aarch64 only system the 32 bit ID registers have UNDEFINED values.
> As a result set_id_regs skips tests for setting fields in these registers
> when testing an aarch64 only guest. This has the side effect of meaning
> that we don't record an expected value for these registers, meaning that
> when the subsequent tests for values being visible in guests and preserved
> over reset check the value they can spuriously fail. This can be seen by
> running on an emulated system with both NV and 32 bit enabled, NV will
> result in the guests created by the test program being 64 bit only but
> the 32 bit ID registers will have values.
I don't think papering over this problem is the right thing to do.
If the issue is that you have HW that has both NV and AArch32, then
KVM needs to be fixed to make the 32bit IDregs RAZ when NV is present
because that's not a configuration we support.
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v5 4/5] KVM: selftests: arm64: Skip all 32 bit IDs when set_id_regs is aarch64 only
2026-03-24 16:47 ` Marc Zyngier
@ 2026-03-24 17:39 ` Mark Brown
0 siblings, 0 replies; 8+ messages in thread
From: Mark Brown @ 2026-03-24 17:39 UTC (permalink / raw)
To: Marc Zyngier
Cc: Joey Gouly, Suzuki K Poulose, Paolo Bonzini, Shuah Khan,
Oliver Upton, Ben Horgan, linux-arm-kernel, kvmarm, kvm,
linux-kselftest, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 1711 bytes --]
On Tue, Mar 24, 2026 at 04:47:15PM +0000, Marc Zyngier wrote:
> Mark Brown <broonie@kernel.org> wrote:
> > On an aarch64 only system the 32 bit ID registers have UNDEFINED values.
> > As a result set_id_regs skips tests for setting fields in these registers
> > when testing an aarch64 only guest. This has the side effect of meaning
> > that we don't record an expected value for these registers, meaning that
> > when the subsequent tests for values being visible in guests and preserved
> > over reset check the value they can spuriously fail. This can be seen by
> > running on an emulated system with both NV and 32 bit enabled, NV will
> > result in the guests created by the test program being 64 bit only but
> > the 32 bit ID registers will have values.
> I don't think papering over this problem is the right thing to do.
> If the issue is that you have HW that has both NV and AArch32, then
> KVM needs to be fixed to make the 32bit IDregs RAZ when NV is present
> because that's not a configuration we support.
Yes, I'm seeing this in practice - it hits by default with qemu which is
rather more readily accessible than actual hardware with NV at this
point and I was concerned that since these registers are explicitly
UNKNOWN (sorry, a mistake in the commit log above there) rather than RAZ
if FEAT_AA32 is not implemented there might be gotchas. I do see that
there's some forcing for the case where the host doesn't support
FEAT_AA32, I figured there must be some reason why it wasn't done based
on the guest configuration.
I'll add something to kvm_finalize_sys_regs(), it'll still need updates
in set_id_regs since that'd make the 32 bit ID registers change value
when the guest is run.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-03-24 17:39 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-17 20:10 [PATCH v5 0/5] KVM: selftests: arm64: Improve diagnostics from set_id_regs Mark Brown
2026-03-17 20:10 ` [PATCH v5 1/5] KVM: selftests: arm64: Report set_id_reg reads of test registers as tests Mark Brown
2026-03-17 20:10 ` [PATCH v5 2/5] KVM: selftests: arm64: Report register reset tests individually Mark Brown
2026-03-17 20:10 ` [PATCH v5 3/5] KVM: selftests: arm64: Make set_id_regs bitfield validatity checks non-fatal Mark Brown
2026-03-17 20:10 ` [PATCH v5 4/5] KVM: selftests: arm64: Skip all 32 bit IDs when set_id_regs is aarch64 only Mark Brown
2026-03-24 16:47 ` Marc Zyngier
2026-03-24 17:39 ` Mark Brown
2026-03-17 20:10 ` [PATCH v5 5/5] KVM: selftests: arm64: Use is_aarch32_id_reg() in test_vm_ftr_id_regs() Mark Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox