@@ -443,6 +443,101 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only)
443443 }
444444}
445445
446+ #define MPAM_IDREG_TEST 6
447+ static void test_user_set_mpam_reg (struct kvm_vcpu * vcpu )
448+ {
449+ uint64_t masks [KVM_ARM_FEATURE_ID_RANGE_SIZE ];
450+ struct reg_mask_range range = {
451+ .addr = (__u64 )masks ,
452+ };
453+ uint64_t val ;
454+ int idx , err ;
455+
456+ /*
457+ * If ID_AA64PFR0.MPAM is _not_ officially modifiable and is zero,
458+ * check that if it can be set to 1, (i.e. it is supported by the
459+ * hardware), that it can't be set to other values.
460+ */
461+
462+ /* Get writable masks for feature ID registers */
463+ memset (range .reserved , 0 , sizeof (range .reserved ));
464+ vm_ioctl (vcpu -> vm , KVM_ARM_GET_REG_WRITABLE_MASKS , & range );
465+
466+ /* Writeable? Nothing to test! */
467+ idx = encoding_to_range_idx (SYS_ID_AA64PFR0_EL1 );
468+ if ((masks [idx ] & ID_AA64PFR0_EL1_MPAM_MASK ) == ID_AA64PFR0_EL1_MPAM_MASK ) {
469+ ksft_test_result_skip ("ID_AA64PFR0_EL1.MPAM is officially writable, nothing to test\n" );
470+ return ;
471+ }
472+
473+ /* Get the id register value */
474+ vcpu_get_reg (vcpu , KVM_ARM64_SYS_REG (SYS_ID_AA64PFR0_EL1 ), & val );
475+
476+ /* Try to set MPAM=0. This should always be possible. */
477+ val &= ~ID_AA64PFR0_EL1_MPAM_MASK ;
478+ val |= FIELD_PREP (ID_AA64PFR0_EL1_MPAM_MASK , 0 );
479+ err = __vcpu_set_reg (vcpu , KVM_ARM64_SYS_REG (SYS_ID_AA64PFR0_EL1 ), val );
480+ if (err )
481+ ksft_test_result_fail ("ID_AA64PFR0_EL1.MPAM=0 was not accepted\n" );
482+ else
483+ ksft_test_result_pass ("ID_AA64PFR0_EL1.MPAM=0 worked\n" );
484+
485+ /* Try to set MPAM=1 */
486+ val &= ~ID_AA64PFR0_EL1_MPAM_MASK ;
487+ val |= FIELD_PREP (ID_AA64PFR0_EL1_MPAM_MASK , 1 );
488+ err = __vcpu_set_reg (vcpu , KVM_ARM64_SYS_REG (SYS_ID_AA64PFR0_EL1 ), val );
489+ if (err )
490+ ksft_test_result_skip ("ID_AA64PFR0_EL1.MPAM is not writable, nothing to test\n" );
491+ else
492+ ksft_test_result_pass ("ID_AA64PFR0_EL1.MPAM=1 was writable\n" );
493+
494+ /* Try to set MPAM=2 */
495+ val &= ~ID_AA64PFR0_EL1_MPAM_MASK ;
496+ val |= FIELD_PREP (ID_AA64PFR0_EL1_MPAM_MASK , 2 );
497+ err = __vcpu_set_reg (vcpu , KVM_ARM64_SYS_REG (SYS_ID_AA64PFR0_EL1 ), val );
498+ if (err )
499+ ksft_test_result_pass ("ID_AA64PFR0_EL1.MPAM not arbitrarily modifiable\n" );
500+ else
501+ ksft_test_result_fail ("ID_AA64PFR0_EL1.MPAM value should not be ignored\n" );
502+
503+ /* And again for ID_AA64PFR1_EL1.MPAM_frac */
504+ idx = encoding_to_range_idx (SYS_ID_AA64PFR1_EL1 );
505+ if ((masks [idx ] & ID_AA64PFR1_EL1_MPAM_frac_MASK ) == ID_AA64PFR1_EL1_MPAM_frac_MASK ) {
506+ ksft_test_result_skip ("ID_AA64PFR1_EL1.MPAM_frac is officially writable, nothing to test\n" );
507+ return ;
508+ }
509+
510+ /* Get the id register value */
511+ vcpu_get_reg (vcpu , KVM_ARM64_SYS_REG (SYS_ID_AA64PFR1_EL1 ), & val );
512+
513+ /* Try to set MPAM_frac=0. This should always be possible. */
514+ val &= ~ID_AA64PFR1_EL1_MPAM_frac_MASK ;
515+ val |= FIELD_PREP (ID_AA64PFR1_EL1_MPAM_frac_MASK , 0 );
516+ err = __vcpu_set_reg (vcpu , KVM_ARM64_SYS_REG (SYS_ID_AA64PFR1_EL1 ), val );
517+ if (err )
518+ ksft_test_result_fail ("ID_AA64PFR0_EL1.MPAM_frac=0 was not accepted\n" );
519+ else
520+ ksft_test_result_pass ("ID_AA64PFR0_EL1.MPAM_frac=0 worked\n" );
521+
522+ /* Try to set MPAM_frac=1 */
523+ val &= ~ID_AA64PFR1_EL1_MPAM_frac_MASK ;
524+ val |= FIELD_PREP (ID_AA64PFR1_EL1_MPAM_frac_MASK , 1 );
525+ err = __vcpu_set_reg (vcpu , KVM_ARM64_SYS_REG (SYS_ID_AA64PFR1_EL1 ), val );
526+ if (err )
527+ ksft_test_result_skip ("ID_AA64PFR1_EL1.MPAM_frac is not writable, nothing to test\n" );
528+ else
529+ ksft_test_result_pass ("ID_AA64PFR0_EL1.MPAM_frac=1 was writable\n" );
530+
531+ /* Try to set MPAM_frac=2 */
532+ val &= ~ID_AA64PFR1_EL1_MPAM_frac_MASK ;
533+ val |= FIELD_PREP (ID_AA64PFR1_EL1_MPAM_frac_MASK , 2 );
534+ err = __vcpu_set_reg (vcpu , KVM_ARM64_SYS_REG (SYS_ID_AA64PFR1_EL1 ), val );
535+ if (err )
536+ ksft_test_result_pass ("ID_AA64PFR1_EL1.MPAM_frac not arbitrarily modifiable\n" );
537+ else
538+ ksft_test_result_fail ("ID_AA64PFR1_EL1.MPAM_frac value should not be ignored\n" );
539+ }
540+
446541static void test_guest_reg_read (struct kvm_vcpu * vcpu )
447542{
448543 bool done = false;
@@ -581,12 +676,14 @@ int main(void)
581676 ARRAY_SIZE (ftr_id_aa64isar2_el1 ) + ARRAY_SIZE (ftr_id_aa64pfr0_el1 ) +
582677 ARRAY_SIZE (ftr_id_aa64pfr1_el1 ) + ARRAY_SIZE (ftr_id_aa64mmfr0_el1 ) +
583678 ARRAY_SIZE (ftr_id_aa64mmfr1_el1 ) + ARRAY_SIZE (ftr_id_aa64mmfr2_el1 ) +
584- ARRAY_SIZE (ftr_id_aa64zfr0_el1 ) - ARRAY_SIZE (test_regs ) + 2 ;
679+ ARRAY_SIZE (ftr_id_aa64zfr0_el1 ) - ARRAY_SIZE (test_regs ) + 2 +
680+ MPAM_IDREG_TEST ;
585681
586682 ksft_set_plan (test_cnt );
587683
588684 test_vm_ftr_id_regs (vcpu , aarch64_only );
589685 test_vcpu_ftr_id_regs (vcpu );
686+ test_user_set_mpam_reg (vcpu );
590687
591688 test_guest_reg_read (vcpu );
592689
0 commit comments