|
15 | 15 | #include "test_util.h"
|
16 | 16 | #include <linux/bitfield.h>
|
17 | 17 |
|
| 18 | +bool have_cap_arm_mte; |
| 19 | + |
18 | 20 | enum ftr_type {
|
19 | 21 | FTR_EXACT, /* Use a predefined safe value */
|
20 | 22 | FTR_LOWER_SAFE, /* Smaller value is safe */
|
@@ -543,6 +545,70 @@ static void test_user_set_mpam_reg(struct kvm_vcpu *vcpu)
|
543 | 545 | ksft_test_result_fail("ID_AA64PFR1_EL1.MPAM_frac value should not be ignored\n");
|
544 | 546 | }
|
545 | 547 |
|
| 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 | + |
546 | 612 | static void test_guest_reg_read(struct kvm_vcpu *vcpu)
|
547 | 613 | {
|
548 | 614 | bool done = false;
|
@@ -673,6 +739,14 @@ static void test_reset_preserves_id_regs(struct kvm_vcpu *vcpu)
|
673 | 739 | ksft_test_result_pass("%s\n", __func__);
|
674 | 740 | }
|
675 | 741 |
|
| 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 | + |
676 | 750 | int main(void)
|
677 | 751 | {
|
678 | 752 | struct kvm_vcpu *vcpu;
|
@@ -701,14 +775,15 @@ int main(void)
|
701 | 775 | ARRAY_SIZE(ftr_id_aa64pfr1_el1) + ARRAY_SIZE(ftr_id_aa64mmfr0_el1) +
|
702 | 776 | ARRAY_SIZE(ftr_id_aa64mmfr1_el1) + ARRAY_SIZE(ftr_id_aa64mmfr2_el1) +
|
703 | 777 | ARRAY_SIZE(ftr_id_aa64zfr0_el1) - ARRAY_SIZE(test_regs) + 3 +
|
704 |
| - MPAM_IDREG_TEST; |
| 778 | + MPAM_IDREG_TEST + MTE_IDREG_TEST; |
705 | 779 |
|
706 | 780 | ksft_set_plan(test_cnt);
|
707 | 781 |
|
708 | 782 | test_vm_ftr_id_regs(vcpu, aarch64_only);
|
709 | 783 | test_vcpu_ftr_id_regs(vcpu);
|
710 | 784 | test_vcpu_non_ftr_id_regs(vcpu);
|
711 | 785 | test_user_set_mpam_reg(vcpu);
|
| 786 | + test_user_set_mte_reg(vcpu); |
712 | 787 |
|
713 | 788 | test_guest_reg_read(vcpu);
|
714 | 789 |
|
|
0 commit comments