Skip to content

Commit 6901886

Browse files
benhor01Marc Zyngier
authored andcommitted
KVM: selftests: Confirm exposing MTE_frac does not break migration
When MTE is supported but MTE_ASYMM is not (ID_AA64PFR1_EL1.MTE == 2) ID_AA64PFR1_EL1.MTE_frac == 0xF indicates MTE_ASYNC is unsupported and MTE_frac == 0 indicates it is supported. As MTE_frac was previously unconditionally read as 0 from the guest and user-space, check that using SET_ONE_REG to set it to 0 succeeds but does not change MTE_frac from unsupported (0xF) to supported (0). This is required as values originating from KVM from user-space must be accepted to avoid breaking migration. Also, to allow this MTE field to be tested, enable KVM_ARM_CAP_MTE for the set_id_regs test. No effect on existing tests is expected. Signed-off-by: Ben Horgan <ben.horgan@arm.com> Link: https://lore.kernel.org/r/20250512114112.359087-4-ben.horgan@arm.com Signed-off-by: Marc Zyngier <maz@kernel.org>
1 parent fe21ff5 commit 6901886

File tree

1 file changed

+76
-1
lines changed

1 file changed

+76
-1
lines changed

tools/testing/selftests/kvm/arm64/set_id_regs.c

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "test_util.h"
1616
#include <linux/bitfield.h>
1717

18+
bool have_cap_arm_mte;
19+
1820
enum ftr_type {
1921
FTR_EXACT, /* Use a predefined safe value */
2022
FTR_LOWER_SAFE, /* Smaller value is safe */
@@ -543,6 +545,70 @@ static void test_user_set_mpam_reg(struct kvm_vcpu *vcpu)
543545
ksft_test_result_fail("ID_AA64PFR1_EL1.MPAM_frac value should not be ignored\n");
544546
}
545547

548+
#define MTE_IDREG_TEST 1
549+
static void test_user_set_mte_reg(struct kvm_vcpu *vcpu)
550+
{
551+
uint64_t masks[KVM_ARM_FEATURE_ID_RANGE_SIZE];
552+
struct reg_mask_range range = {
553+
.addr = (__u64)masks,
554+
};
555+
uint64_t val;
556+
uint64_t mte;
557+
uint64_t mte_frac;
558+
int idx, err;
559+
560+
if (!have_cap_arm_mte) {
561+
ksft_test_result_skip("MTE capability not supported, nothing to test\n");
562+
return;
563+
}
564+
565+
/* Get writable masks for feature ID registers */
566+
memset(range.reserved, 0, sizeof(range.reserved));
567+
vm_ioctl(vcpu->vm, KVM_ARM_GET_REG_WRITABLE_MASKS, &range);
568+
569+
idx = encoding_to_range_idx(SYS_ID_AA64PFR1_EL1);
570+
if ((masks[idx] & ID_AA64PFR1_EL1_MTE_frac_MASK) == ID_AA64PFR1_EL1_MTE_frac_MASK) {
571+
ksft_test_result_skip("ID_AA64PFR1_EL1.MTE_frac is officially writable, nothing to test\n");
572+
return;
573+
}
574+
575+
/*
576+
* When MTE is supported but MTE_ASYMM is not (ID_AA64PFR1_EL1.MTE == 2)
577+
* ID_AA64PFR1_EL1.MTE_frac == 0xF indicates MTE_ASYNC is unsupported
578+
* and MTE_frac == 0 indicates it is supported.
579+
*
580+
* As MTE_frac was previously unconditionally read as 0, check
581+
* that the set to 0 succeeds but does not change MTE_frac
582+
* from unsupported (0xF) to supported (0).
583+
*
584+
*/
585+
val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1));
586+
587+
mte = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE), val);
588+
mte_frac = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac), val);
589+
if (mte != ID_AA64PFR1_EL1_MTE_MTE2 ||
590+
mte_frac != ID_AA64PFR1_EL1_MTE_frac_NI) {
591+
ksft_test_result_skip("MTE_ASYNC or MTE_ASYMM are supported, nothing to test\n");
592+
return;
593+
}
594+
595+
/* Try to set MTE_frac=0. */
596+
val &= ~ID_AA64PFR1_EL1_MTE_frac_MASK;
597+
val |= FIELD_PREP(ID_AA64PFR1_EL1_MTE_frac_MASK, 0);
598+
err = __vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1), val);
599+
if (err) {
600+
ksft_test_result_fail("ID_AA64PFR1_EL1.MTE_frac=0 was not accepted\n");
601+
return;
602+
}
603+
604+
val = vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64PFR1_EL1));
605+
mte_frac = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE_frac), val);
606+
if (mte_frac == ID_AA64PFR1_EL1_MTE_frac_NI)
607+
ksft_test_result_pass("ID_AA64PFR1_EL1.MTE_frac=0 accepted and still 0xF\n");
608+
else
609+
ksft_test_result_pass("ID_AA64PFR1_EL1.MTE_frac no longer 0xF\n");
610+
}
611+
546612
static void test_guest_reg_read(struct kvm_vcpu *vcpu)
547613
{
548614
bool done = false;
@@ -673,6 +739,14 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
673739
ksft_test_result_pass("%s\n", __func__);
674740
}
675741

742+
void kvm_arch_vm_post_create(struct kvm_vm *vm)
743+
{
744+
if (vm_check_cap(vm, KVM_CAP_ARM_MTE)) {
745+
vm_enable_cap(vm, KVM_CAP_ARM_MTE, 0);
746+
have_cap_arm_mte = true;
747+
}
748+
}
749+
676750
int main(void)
677751
{
678752
struct kvm_vcpu *vcpu;
@@ -701,14 +775,15 @@ int main(void)
701775
ARRAY_SIZE(ftr_id_aa64pfr1_el1) + ARRAY_SIZE(ftr_id_aa64mmfr0_el1) +
702776
ARRAY_SIZE(ftr_id_aa64mmfr1_el1) + ARRAY_SIZE(ftr_id_aa64mmfr2_el1) +
703777
ARRAY_SIZE(ftr_id_aa64zfr0_el1) - ARRAY_SIZE(test_regs) + 3 +
704-
MPAM_IDREG_TEST;
778+
MPAM_IDREG_TEST + MTE_IDREG_TEST;
705779

706780
ksft_set_plan(test_cnt);
707781

708782
test_vm_ftr_id_regs(vcpu, aarch64_only);
709783
test_vcpu_ftr_id_regs(vcpu);
710784
test_vcpu_non_ftr_id_regs(vcpu);
711785
test_user_set_mpam_reg(vcpu);
786+
test_user_set_mte_reg(vcpu);
712787

713788
test_guest_reg_read(vcpu);
714789

0 commit comments

Comments
 (0)