@@ -443,6 +443,101 @@ static void test_vm_ftr_id_regs(struct kvm_vcpu *vcpu, bool aarch64_only)
443
443
}
444
444
}
445
445
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
+
446
541
static void test_guest_reg_read (struct kvm_vcpu * vcpu )
447
542
{
448
543
bool done = false;
@@ -581,12 +676,14 @@ int main(void)
581
676
ARRAY_SIZE (ftr_id_aa64isar2_el1 ) + ARRAY_SIZE (ftr_id_aa64pfr0_el1 ) +
582
677
ARRAY_SIZE (ftr_id_aa64pfr1_el1 ) + ARRAY_SIZE (ftr_id_aa64mmfr0_el1 ) +
583
678
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 ;
585
681
586
682
ksft_set_plan (test_cnt );
587
683
588
684
test_vm_ftr_id_regs (vcpu , aarch64_only );
589
685
test_vcpu_ftr_id_regs (vcpu );
686
+ test_user_set_mpam_reg (vcpu );
590
687
591
688
test_guest_reg_read (vcpu );
592
689
0 commit comments