@@ -399,6 +399,12 @@ static void free_uffd(struct test_desc *test, struct uffd_desc *pt_uffd,
399399 free (data_args .copy );
400400}
401401
402+ static int uffd_no_handler (int mode , int uffd , struct uffd_msg * msg )
403+ {
404+ TEST_FAIL ("There was no UFFD fault expected." );
405+ return -1 ;
406+ }
407+
402408/* Returns false if the test should be skipped. */
403409static bool punch_hole_in_backing_store (struct kvm_vm * vm ,
404410 struct userspace_mem_region * region )
@@ -799,6 +805,22 @@ static void help(char *name)
799805 .expected_events = { 0 }, \
800806}
801807
808+ #define TEST_UFFD_AND_DIRTY_LOG (_access , _with_af , _uffd_data_handler , \
809+ _uffd_faults , _test_check ) \
810+ { \
811+ .name = SCAT3(uffd_and_dirty_log, _access, _with_af), \
812+ .data_memslot_flags = KVM_MEM_LOG_DIRTY_PAGES, \
813+ .pt_memslot_flags = KVM_MEM_LOG_DIRTY_PAGES, \
814+ .guest_prepare = { _PREPARE(_with_af), \
815+ _PREPARE(_access) }, \
816+ .guest_test = _access, \
817+ .mem_mark_cmd = CMD_HOLE_DATA | CMD_HOLE_PT, \
818+ .guest_test_check = { _CHECK(_with_af), _test_check }, \
819+ .uffd_data_handler = _uffd_data_handler, \
820+ .uffd_pt_handler = uffd_pt_write_handler, \
821+ .expected_events = { .uffd_faults = _uffd_faults, }, \
822+ }
823+
802824#define TEST_RO_MEMSLOT (_access , _mmio_handler , _mmio_exits ) \
803825{ \
804826 .name = SCAT3(ro_memslot, _access, _with_af), \
@@ -818,6 +840,59 @@ static void help(char *name)
818840 .expected_events = { .fail_vcpu_runs = 1 }, \
819841}
820842
843+ #define TEST_RO_MEMSLOT_AND_DIRTY_LOG (_access , _mmio_handler , _mmio_exits , \
844+ _test_check ) \
845+ { \
846+ .name = SCAT3(ro_memslot, _access, _with_af), \
847+ .data_memslot_flags = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES, \
848+ .pt_memslot_flags = KVM_MEM_LOG_DIRTY_PAGES, \
849+ .guest_prepare = { _PREPARE(_access) }, \
850+ .guest_test = _access, \
851+ .guest_test_check = { _test_check }, \
852+ .mmio_handler = _mmio_handler, \
853+ .expected_events = { .mmio_exits = _mmio_exits}, \
854+ }
855+
856+ #define TEST_RO_MEMSLOT_NO_SYNDROME_AND_DIRTY_LOG (_access , _test_check ) \
857+ { \
858+ .name = SCAT2(ro_memslot_no_syn_and_dlog, _access), \
859+ .data_memslot_flags = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES, \
860+ .pt_memslot_flags = KVM_MEM_LOG_DIRTY_PAGES, \
861+ .guest_test = _access, \
862+ .guest_test_check = { _test_check }, \
863+ .fail_vcpu_run_handler = fail_vcpu_run_mmio_no_syndrome_handler, \
864+ .expected_events = { .fail_vcpu_runs = 1 }, \
865+ }
866+
867+ #define TEST_RO_MEMSLOT_AND_UFFD (_access , _mmio_handler , _mmio_exits , \
868+ _uffd_data_handler , _uffd_faults ) \
869+ { \
870+ .name = SCAT2(ro_memslot_uffd, _access), \
871+ .data_memslot_flags = KVM_MEM_READONLY, \
872+ .mem_mark_cmd = CMD_HOLE_DATA | CMD_HOLE_PT, \
873+ .guest_prepare = { _PREPARE(_access) }, \
874+ .guest_test = _access, \
875+ .uffd_data_handler = _uffd_data_handler, \
876+ .uffd_pt_handler = uffd_pt_write_handler, \
877+ .mmio_handler = _mmio_handler, \
878+ .expected_events = { .mmio_exits = _mmio_exits, \
879+ .uffd_faults = _uffd_faults }, \
880+ }
881+
882+ #define TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD (_access , _uffd_data_handler , \
883+ _uffd_faults ) \
884+ { \
885+ .name = SCAT2(ro_memslot_no_syndrome, _access), \
886+ .data_memslot_flags = KVM_MEM_READONLY, \
887+ .mem_mark_cmd = CMD_HOLE_DATA | CMD_HOLE_PT, \
888+ .guest_test = _access, \
889+ .uffd_data_handler = _uffd_data_handler, \
890+ .uffd_pt_handler = uffd_pt_write_handler, \
891+ .fail_vcpu_run_handler = fail_vcpu_run_mmio_no_syndrome_handler, \
892+ .expected_events = { .fail_vcpu_runs = 1, \
893+ .uffd_faults = _uffd_faults }, \
894+ }
895+
821896static struct test_desc tests [] = {
822897
823898 /* Check that HW is setting the Access Flag (AF) (sanity checks). */
@@ -892,6 +967,35 @@ static struct test_desc tests[] = {
892967 TEST_DIRTY_LOG (guest_dc_zva , with_af , guest_check_write_in_dirty_log ),
893968 TEST_DIRTY_LOG (guest_st_preidx , with_af , guest_check_write_in_dirty_log ),
894969
970+ /*
971+ * Access when the data and PT memory regions are both marked for
972+ * dirty logging and UFFD at the same time. The expected result is
973+ * that writes should mark the dirty log and trigger a userfaultfd
974+ * write fault. Reads/execs should result in a read userfaultfd
975+ * fault, and nothing in the dirty log. Any S1PTW should result in
976+ * a write in the dirty log and a userfaultfd write.
977+ */
978+ TEST_UFFD_AND_DIRTY_LOG (guest_read64 , with_af , uffd_data_read_handler , 2 ,
979+ guest_check_no_write_in_dirty_log ),
980+ /* no_af should also lead to a PT write. */
981+ TEST_UFFD_AND_DIRTY_LOG (guest_read64 , no_af , uffd_data_read_handler , 2 ,
982+ guest_check_no_write_in_dirty_log ),
983+ TEST_UFFD_AND_DIRTY_LOG (guest_ld_preidx , with_af , uffd_data_read_handler ,
984+ 2 , guest_check_no_write_in_dirty_log ),
985+ TEST_UFFD_AND_DIRTY_LOG (guest_at , with_af , 0 , 1 ,
986+ guest_check_no_write_in_dirty_log ),
987+ TEST_UFFD_AND_DIRTY_LOG (guest_exec , with_af , uffd_data_read_handler , 2 ,
988+ guest_check_no_write_in_dirty_log ),
989+ TEST_UFFD_AND_DIRTY_LOG (guest_write64 , with_af , uffd_data_write_handler ,
990+ 2 , guest_check_write_in_dirty_log ),
991+ TEST_UFFD_AND_DIRTY_LOG (guest_cas , with_af , uffd_data_read_handler , 2 ,
992+ guest_check_write_in_dirty_log ),
993+ TEST_UFFD_AND_DIRTY_LOG (guest_dc_zva , with_af , uffd_data_write_handler ,
994+ 2 , guest_check_write_in_dirty_log ),
995+ TEST_UFFD_AND_DIRTY_LOG (guest_st_preidx , with_af ,
996+ uffd_data_write_handler , 2 ,
997+ guest_check_write_in_dirty_log ),
998+
895999 /*
8961000 * Try accesses when the data memory region is marked read-only
8971001 * (with KVM_MEM_READONLY). Writes with a syndrome result in an
@@ -908,6 +1012,57 @@ static struct test_desc tests[] = {
9081012 TEST_RO_MEMSLOT_NO_SYNDROME (guest_cas ),
9091013 TEST_RO_MEMSLOT_NO_SYNDROME (guest_st_preidx ),
9101014
1015+ /*
1016+ * Access when both the data region is both read-only and marked
1017+ * for dirty logging at the same time. The expected result is that
1018+ * for writes there should be no write in the dirty log. The
1019+ * readonly handling is the same as if the memslot was not marked
1020+ * for dirty logging: writes with a syndrome result in an MMIO
1021+ * exit, and writes with no syndrome result in a failed vcpu run.
1022+ */
1023+ TEST_RO_MEMSLOT_AND_DIRTY_LOG (guest_read64 , 0 , 0 ,
1024+ guest_check_no_write_in_dirty_log ),
1025+ TEST_RO_MEMSLOT_AND_DIRTY_LOG (guest_ld_preidx , 0 , 0 ,
1026+ guest_check_no_write_in_dirty_log ),
1027+ TEST_RO_MEMSLOT_AND_DIRTY_LOG (guest_at , 0 , 0 ,
1028+ guest_check_no_write_in_dirty_log ),
1029+ TEST_RO_MEMSLOT_AND_DIRTY_LOG (guest_exec , 0 , 0 ,
1030+ guest_check_no_write_in_dirty_log ),
1031+ TEST_RO_MEMSLOT_AND_DIRTY_LOG (guest_write64 , mmio_on_test_gpa_handler ,
1032+ 1 , guest_check_no_write_in_dirty_log ),
1033+ TEST_RO_MEMSLOT_NO_SYNDROME_AND_DIRTY_LOG (guest_dc_zva ,
1034+ guest_check_no_write_in_dirty_log ),
1035+ TEST_RO_MEMSLOT_NO_SYNDROME_AND_DIRTY_LOG (guest_cas ,
1036+ guest_check_no_write_in_dirty_log ),
1037+ TEST_RO_MEMSLOT_NO_SYNDROME_AND_DIRTY_LOG (guest_st_preidx ,
1038+ guest_check_no_write_in_dirty_log ),
1039+
1040+ /*
1041+ * Access when the data region is both read-only and punched with
1042+ * holes tracked with userfaultfd. The expected result is the
1043+ * union of both userfaultfd and read-only behaviors. For example,
1044+ * write accesses result in a userfaultfd write fault and an MMIO
1045+ * exit. Writes with no syndrome result in a failed vcpu run and
1046+ * no userfaultfd write fault. Reads result in userfaultfd getting
1047+ * triggered.
1048+ */
1049+ TEST_RO_MEMSLOT_AND_UFFD (guest_read64 , 0 , 0 ,
1050+ uffd_data_read_handler , 2 ),
1051+ TEST_RO_MEMSLOT_AND_UFFD (guest_ld_preidx , 0 , 0 ,
1052+ uffd_data_read_handler , 2 ),
1053+ TEST_RO_MEMSLOT_AND_UFFD (guest_at , 0 , 0 ,
1054+ uffd_no_handler , 1 ),
1055+ TEST_RO_MEMSLOT_AND_UFFD (guest_exec , 0 , 0 ,
1056+ uffd_data_read_handler , 2 ),
1057+ TEST_RO_MEMSLOT_AND_UFFD (guest_write64 , mmio_on_test_gpa_handler , 1 ,
1058+ uffd_data_write_handler , 2 ),
1059+ TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD (guest_cas ,
1060+ uffd_data_read_handler , 2 ),
1061+ TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD (guest_dc_zva ,
1062+ uffd_no_handler , 1 ),
1063+ TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD (guest_st_preidx ,
1064+ uffd_no_handler , 1 ),
1065+
9111066 { 0 }
9121067};
9131068
0 commit comments