Skip to content

Commit ff2b550

Browse files
Ricardo KollerMarc Zyngier
authored andcommitted
KVM: selftests: aarch64: Add mix of tests into page_fault_test
Add some mix of tests into page_fault_test: memory regions with all the pairwise combinations of read-only, userfaultfd, and dirty-logging. For example, writing into a read-only region which has a hole handled with userfaultfd. Signed-off-by: Ricardo Koller <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 45acde4 commit ff2b550

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

tools/testing/selftests/kvm/aarch64/page_fault_test.c

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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. */
403409
static 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+
821896
static 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

Comments
 (0)