@@ -41,6 +41,8 @@ static uint64_t *guest_test_memory = (uint64_t *)TEST_GVA;
41
41
#define CHECK_FN_NR 10
42
42
43
43
static struct event_cnt {
44
+ int mmio_exits ;
45
+ int fail_vcpu_runs ;
44
46
int uffd_faults ;
45
47
/* uffd_faults is incremented from multiple threads. */
46
48
pthread_mutex_t uffd_faults_mutex ;
@@ -57,6 +59,8 @@ struct test_desc {
57
59
uffd_handler_t uffd_data_handler ;
58
60
void (* dabt_handler )(struct ex_regs * regs );
59
61
void (* iabt_handler )(struct ex_regs * regs );
62
+ void (* mmio_handler )(struct kvm_vm * vm , struct kvm_run * run );
63
+ void (* fail_vcpu_run_handler )(int ret );
60
64
uint32_t pt_memslot_flags ;
61
65
uint32_t data_memslot_flags ;
62
66
bool skip ;
@@ -415,6 +419,31 @@ static bool punch_hole_in_backing_store(struct kvm_vm *vm,
415
419
return true;
416
420
}
417
421
422
+ static void mmio_on_test_gpa_handler (struct kvm_vm * vm , struct kvm_run * run )
423
+ {
424
+ struct userspace_mem_region * region ;
425
+ void * hva ;
426
+
427
+ region = vm_get_mem_region (vm , MEM_REGION_TEST_DATA );
428
+ hva = (void * )region -> region .userspace_addr ;
429
+
430
+ ASSERT_EQ (run -> mmio .phys_addr , region -> region .guest_phys_addr );
431
+
432
+ memcpy (hva , run -> mmio .data , run -> mmio .len );
433
+ events .mmio_exits += 1 ;
434
+ }
435
+
436
+ static void mmio_no_handler (struct kvm_vm * vm , struct kvm_run * run )
437
+ {
438
+ uint64_t data ;
439
+
440
+ memcpy (& data , run -> mmio .data , sizeof (data ));
441
+ pr_debug ("addr=%lld len=%d w=%d data=%lx\n" ,
442
+ run -> mmio .phys_addr , run -> mmio .len ,
443
+ run -> mmio .is_write , data );
444
+ TEST_FAIL ("There was no MMIO exit expected." );
445
+ }
446
+
418
447
static bool check_write_in_dirty_log (struct kvm_vm * vm ,
419
448
struct userspace_mem_region * region ,
420
449
uint64_t host_pg_nr )
@@ -463,6 +492,18 @@ static bool handle_cmd(struct kvm_vm *vm, int cmd)
463
492
return continue_test ;
464
493
}
465
494
495
+ void fail_vcpu_run_no_handler (int ret )
496
+ {
497
+ TEST_FAIL ("Unexpected vcpu run failure\n" );
498
+ }
499
+
500
+ void fail_vcpu_run_mmio_no_syndrome_handler (int ret )
501
+ {
502
+ TEST_ASSERT (errno == ENOSYS ,
503
+ "The mmio handler should have returned not implemented." );
504
+ events .fail_vcpu_runs += 1 ;
505
+ }
506
+
466
507
typedef uint32_t aarch64_insn_t ;
467
508
extern aarch64_insn_t __exec_test [2 ];
468
509
@@ -564,9 +605,20 @@ static void setup_memslots(struct kvm_vm *vm, struct test_params *p)
564
605
vm -> memslots [MEM_REGION_TEST_DATA ] = TEST_DATA_MEMSLOT ;
565
606
}
566
607
608
+ static void setup_default_handlers (struct test_desc * test )
609
+ {
610
+ if (!test -> mmio_handler )
611
+ test -> mmio_handler = mmio_no_handler ;
612
+
613
+ if (!test -> fail_vcpu_run_handler )
614
+ test -> fail_vcpu_run_handler = fail_vcpu_run_no_handler ;
615
+ }
616
+
567
617
static void check_event_counts (struct test_desc * test )
568
618
{
569
619
ASSERT_EQ (test -> expected_events .uffd_faults , events .uffd_faults );
620
+ ASSERT_EQ (test -> expected_events .mmio_exits , events .mmio_exits );
621
+ ASSERT_EQ (test -> expected_events .fail_vcpu_runs , events .fail_vcpu_runs );
570
622
}
571
623
572
624
static void print_test_banner (enum vm_guest_mode mode , struct test_params * p )
@@ -591,10 +643,18 @@ static void reset_event_counts(void)
591
643
static void vcpu_run_loop (struct kvm_vm * vm , struct kvm_vcpu * vcpu ,
592
644
struct test_desc * test )
593
645
{
646
+ struct kvm_run * run ;
594
647
struct ucall uc ;
648
+ int ret ;
649
+
650
+ run = vcpu -> run ;
595
651
596
652
for (;;) {
597
- vcpu_run (vcpu );
653
+ ret = _vcpu_run (vcpu );
654
+ if (ret ) {
655
+ test -> fail_vcpu_run_handler (ret );
656
+ goto done ;
657
+ }
598
658
599
659
switch (get_ucall (vcpu , & uc )) {
600
660
case UCALL_SYNC :
@@ -608,6 +668,10 @@ static void vcpu_run_loop(struct kvm_vm *vm, struct kvm_vcpu *vcpu,
608
668
break ;
609
669
case UCALL_DONE :
610
670
goto done ;
671
+ case UCALL_NONE :
672
+ if (run -> exit_reason == KVM_EXIT_MMIO )
673
+ test -> mmio_handler (vm , run );
674
+ break ;
611
675
default :
612
676
TEST_FAIL ("Unknown ucall %lu" , uc .cmd );
613
677
}
@@ -647,6 +711,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
647
711
load_exec_code_for_test (vm );
648
712
setup_uffd (vm , p , & pt_uffd , & data_uffd );
649
713
setup_abort_handlers (vm , vcpu , test );
714
+ setup_default_handlers (test );
650
715
vcpu_args_set (vcpu , 1 , test );
651
716
652
717
vcpu_run_loop (vm , vcpu , test );
@@ -734,6 +799,25 @@ static void help(char *name)
734
799
.expected_events = { 0 }, \
735
800
}
736
801
802
+ #define TEST_RO_MEMSLOT (_access , _mmio_handler , _mmio_exits ) \
803
+ { \
804
+ .name = SCAT3(ro_memslot, _access, _with_af), \
805
+ .data_memslot_flags = KVM_MEM_READONLY, \
806
+ .guest_prepare = { _PREPARE(_access) }, \
807
+ .guest_test = _access, \
808
+ .mmio_handler = _mmio_handler, \
809
+ .expected_events = { .mmio_exits = _mmio_exits }, \
810
+ }
811
+
812
+ #define TEST_RO_MEMSLOT_NO_SYNDROME (_access ) \
813
+ { \
814
+ .name = SCAT2(ro_memslot_no_syndrome, _access), \
815
+ .data_memslot_flags = KVM_MEM_READONLY, \
816
+ .guest_test = _access, \
817
+ .fail_vcpu_run_handler = fail_vcpu_run_mmio_no_syndrome_handler, \
818
+ .expected_events = { .fail_vcpu_runs = 1 }, \
819
+ }
820
+
737
821
static struct test_desc tests [] = {
738
822
739
823
/* Check that HW is setting the Access Flag (AF) (sanity checks). */
@@ -808,6 +892,22 @@ static struct test_desc tests[] = {
808
892
TEST_DIRTY_LOG (guest_dc_zva , with_af , guest_check_write_in_dirty_log ),
809
893
TEST_DIRTY_LOG (guest_st_preidx , with_af , guest_check_write_in_dirty_log ),
810
894
895
+ /*
896
+ * Try accesses when the data memory region is marked read-only
897
+ * (with KVM_MEM_READONLY). Writes with a syndrome result in an
898
+ * MMIO exit, writes with no syndrome (e.g., CAS) result in a
899
+ * failed vcpu run, and reads/execs with and without syndroms do
900
+ * not fault.
901
+ */
902
+ TEST_RO_MEMSLOT (guest_read64 , 0 , 0 ),
903
+ TEST_RO_MEMSLOT (guest_ld_preidx , 0 , 0 ),
904
+ TEST_RO_MEMSLOT (guest_at , 0 , 0 ),
905
+ TEST_RO_MEMSLOT (guest_exec , 0 , 0 ),
906
+ TEST_RO_MEMSLOT (guest_write64 , mmio_on_test_gpa_handler , 1 ),
907
+ TEST_RO_MEMSLOT_NO_SYNDROME (guest_dc_zva ),
908
+ TEST_RO_MEMSLOT_NO_SYNDROME (guest_cas ),
909
+ TEST_RO_MEMSLOT_NO_SYNDROME (guest_st_preidx ),
910
+
811
911
{ 0 }
812
912
};
813
913
0 commit comments