@@ -399,6 +399,12 @@ static void free_uffd(struct test_desc *test, struct uffd_desc *pt_uffd,
399
399
free (data_args .copy );
400
400
}
401
401
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
+
402
408
/* Returns false if the test should be skipped. */
403
409
static bool punch_hole_in_backing_store (struct kvm_vm * vm ,
404
410
struct userspace_mem_region * region )
@@ -799,6 +805,22 @@ static void help(char *name)
799
805
.expected_events = { 0 }, \
800
806
}
801
807
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
+
802
824
#define TEST_RO_MEMSLOT (_access , _mmio_handler , _mmio_exits ) \
803
825
{ \
804
826
.name = SCAT3(ro_memslot, _access, _with_af), \
@@ -818,6 +840,59 @@ static void help(char *name)
818
840
.expected_events = { .fail_vcpu_runs = 1 }, \
819
841
}
820
842
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
+
821
896
static struct test_desc tests [] = {
822
897
823
898
/* Check that HW is setting the Access Flag (AF) (sanity checks). */
@@ -892,6 +967,35 @@ static struct test_desc tests[] = {
892
967
TEST_DIRTY_LOG (guest_dc_zva , with_af , guest_check_write_in_dirty_log ),
893
968
TEST_DIRTY_LOG (guest_st_preidx , with_af , guest_check_write_in_dirty_log ),
894
969
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
+
895
999
/*
896
1000
* Try accesses when the data memory region is marked read-only
897
1001
* (with KVM_MEM_READONLY). Writes with a syndrome result in an
@@ -908,6 +1012,57 @@ static struct test_desc tests[] = {
908
1012
TEST_RO_MEMSLOT_NO_SYNDROME (guest_cas ),
909
1013
TEST_RO_MEMSLOT_NO_SYNDROME (guest_st_preidx ),
910
1014
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
+
911
1066
{ 0 }
912
1067
};
913
1068
0 commit comments