diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2023-02-04 08:57:43 -0500 | 
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2023-02-04 08:57:43 -0500 | 
| commit | 25b72cf7da9f0d66eef3979187ddfda98d4efcd0 (patch) | |
| tree | 492767ede5690f54b0917b4a9a6d00b7810d571f /tools/testing | |
| parent | c2c46b10d52624376322b01654095a84611c7e09 (diff) | |
| parent | 08ddbbdf0b55839ca93a12677a30a1ef24634969 (diff) | |
Merge tag 'kvmarm-fixes-6.2-3' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/arm64 fixes for 6.2, take #3
- Yet another fix for non-CPU accesses to the memory backing
  the VGICv3 subsystem
- A set of fixes for the setlftest checking for the S1PTW
  behaviour after the fix that went in ealier in the cycle
Diffstat (limited to 'tools/testing')
| -rw-r--r-- | tools/testing/selftests/kvm/aarch64/page_fault_test.c | 187 | 
1 files changed, 103 insertions, 84 deletions
| diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c index beb944fa6fd4..54680dc5887f 100644 --- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -237,6 +237,11 @@ static void guest_check_s1ptw_wr_in_dirty_log(void)  	GUEST_SYNC(CMD_CHECK_S1PTW_WR_IN_DIRTY_LOG);  } +static void guest_check_no_s1ptw_wr_in_dirty_log(void) +{ +	GUEST_SYNC(CMD_CHECK_NO_S1PTW_WR_IN_DIRTY_LOG); +} +  static void guest_exec(void)  {  	int (*code)(void) = (int (*)(void))TEST_EXEC_GVA; @@ -304,7 +309,7 @@ static struct uffd_args {  /* Returns true to continue the test, and false if it should be skipped. */  static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg, -				struct uffd_args *args, bool expect_write) +				struct uffd_args *args)  {  	uint64_t addr = msg->arg.pagefault.address;  	uint64_t flags = msg->arg.pagefault.flags; @@ -313,7 +318,6 @@ static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg,  	TEST_ASSERT(uffd_mode == UFFDIO_REGISTER_MODE_MISSING,  		    "The only expected UFFD mode is MISSING"); -	ASSERT_EQ(!!(flags & UFFD_PAGEFAULT_FLAG_WRITE), expect_write);  	ASSERT_EQ(addr, (uint64_t)args->hva);  	pr_debug("uffd fault: addr=%p write=%d\n", @@ -337,19 +341,14 @@ static int uffd_generic_handler(int uffd_mode, int uffd, struct uffd_msg *msg,  	return 0;  } -static int uffd_pt_write_handler(int mode, int uffd, struct uffd_msg *msg) -{ -	return uffd_generic_handler(mode, uffd, msg, &pt_args, true); -} - -static int uffd_data_write_handler(int mode, int uffd, struct uffd_msg *msg) +static int uffd_pt_handler(int mode, int uffd, struct uffd_msg *msg)  { -	return uffd_generic_handler(mode, uffd, msg, &data_args, true); +	return uffd_generic_handler(mode, uffd, msg, &pt_args);  } -static int uffd_data_read_handler(int mode, int uffd, struct uffd_msg *msg) +static int uffd_data_handler(int mode, int uffd, struct uffd_msg *msg)  { -	return uffd_generic_handler(mode, uffd, msg, &data_args, false); +	return uffd_generic_handler(mode, uffd, msg, &data_args);  }  static void setup_uffd_args(struct userspace_mem_region *region, @@ -471,9 +470,12 @@ static bool handle_cmd(struct kvm_vm *vm, int cmd)  {  	struct userspace_mem_region *data_region, *pt_region;  	bool continue_test = true; +	uint64_t pte_gpa, pte_pg;  	data_region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA);  	pt_region = vm_get_mem_region(vm, MEM_REGION_PT); +	pte_gpa = addr_hva2gpa(vm, virt_get_pte_hva(vm, TEST_GVA)); +	pte_pg = (pte_gpa - pt_region->region.guest_phys_addr) / getpagesize();  	if (cmd == CMD_SKIP_TEST)  		continue_test = false; @@ -486,13 +488,13 @@ static bool handle_cmd(struct kvm_vm *vm, int cmd)  		TEST_ASSERT(check_write_in_dirty_log(vm, data_region, 0),  			    "Missing write in dirty log");  	if (cmd & CMD_CHECK_S1PTW_WR_IN_DIRTY_LOG) -		TEST_ASSERT(check_write_in_dirty_log(vm, pt_region, 0), +		TEST_ASSERT(check_write_in_dirty_log(vm, pt_region, pte_pg),  			    "Missing s1ptw write in dirty log");  	if (cmd & CMD_CHECK_NO_WRITE_IN_DIRTY_LOG)  		TEST_ASSERT(!check_write_in_dirty_log(vm, data_region, 0),  			    "Unexpected write in dirty log");  	if (cmd & CMD_CHECK_NO_S1PTW_WR_IN_DIRTY_LOG) -		TEST_ASSERT(!check_write_in_dirty_log(vm, pt_region, 0), +		TEST_ASSERT(!check_write_in_dirty_log(vm, pt_region, pte_pg),  			    "Unexpected s1ptw write in dirty log");  	return continue_test; @@ -797,7 +799,7 @@ static void help(char *name)  	.expected_events	= { .uffd_faults = _uffd_faults, },		\  } -#define TEST_DIRTY_LOG(_access, _with_af, _test_check)				\ +#define TEST_DIRTY_LOG(_access, _with_af, _test_check, _pt_check)		\  {										\  	.name			= SCAT3(dirty_log, _access, _with_af),		\  	.data_memslot_flags	= KVM_MEM_LOG_DIRTY_PAGES,			\ @@ -805,13 +807,12 @@ static void help(char *name)  	.guest_prepare		= { _PREPARE(_with_af),				\  				    _PREPARE(_access) },			\  	.guest_test		= _access,					\ -	.guest_test_check	= { _CHECK(_with_af), _test_check,		\ -				    guest_check_s1ptw_wr_in_dirty_log},		\ +	.guest_test_check	= { _CHECK(_with_af), _test_check, _pt_check },	\  	.expected_events	= { 0 },					\  }  #define TEST_UFFD_AND_DIRTY_LOG(_access, _with_af, _uffd_data_handler,		\ -				_uffd_faults, _test_check)			\ +				_uffd_faults, _test_check, _pt_check)		\  {										\  	.name			= SCAT3(uffd_and_dirty_log, _access, _with_af),	\  	.data_memslot_flags	= KVM_MEM_LOG_DIRTY_PAGES,			\ @@ -820,16 +821,17 @@ static void help(char *name)  				    _PREPARE(_access) },			\  	.guest_test		= _access,					\  	.mem_mark_cmd		= CMD_HOLE_DATA | CMD_HOLE_PT,			\ -	.guest_test_check	= { _CHECK(_with_af), _test_check },		\ +	.guest_test_check	= { _CHECK(_with_af), _test_check, _pt_check },	\  	.uffd_data_handler	= _uffd_data_handler,				\ -	.uffd_pt_handler	= uffd_pt_write_handler,			\ +	.uffd_pt_handler	= uffd_pt_handler,				\  	.expected_events	= { .uffd_faults = _uffd_faults, },		\  }  #define TEST_RO_MEMSLOT(_access, _mmio_handler, _mmio_exits)			\  {										\ -	.name			= SCAT3(ro_memslot, _access, _with_af),		\ +	.name			= SCAT2(ro_memslot, _access),			\  	.data_memslot_flags	= KVM_MEM_READONLY,				\ +	.pt_memslot_flags	= KVM_MEM_READONLY,				\  	.guest_prepare		= { _PREPARE(_access) },			\  	.guest_test		= _access,					\  	.mmio_handler		= _mmio_handler,				\ @@ -840,6 +842,7 @@ static void help(char *name)  {										\  	.name			= SCAT2(ro_memslot_no_syndrome, _access),	\  	.data_memslot_flags	= KVM_MEM_READONLY,				\ +	.pt_memslot_flags	= KVM_MEM_READONLY,				\  	.guest_test		= _access,					\  	.fail_vcpu_run_handler	= fail_vcpu_run_mmio_no_syndrome_handler,	\  	.expected_events	= { .fail_vcpu_runs = 1 },			\ @@ -848,9 +851,9 @@ static void help(char *name)  #define TEST_RO_MEMSLOT_AND_DIRTY_LOG(_access, _mmio_handler, _mmio_exits,	\  				      _test_check)				\  {										\ -	.name			= SCAT3(ro_memslot, _access, _with_af),		\ +	.name			= SCAT2(ro_memslot, _access),			\  	.data_memslot_flags	= KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES,	\ -	.pt_memslot_flags	= KVM_MEM_LOG_DIRTY_PAGES,			\ +	.pt_memslot_flags	= KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES,	\  	.guest_prepare		= { _PREPARE(_access) },			\  	.guest_test		= _access,					\  	.guest_test_check	= { _test_check },				\ @@ -862,7 +865,7 @@ static void help(char *name)  {										\  	.name			= SCAT2(ro_memslot_no_syn_and_dlog, _access),	\  	.data_memslot_flags	= KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES,	\ -	.pt_memslot_flags	= KVM_MEM_LOG_DIRTY_PAGES,			\ +	.pt_memslot_flags	= KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES,	\  	.guest_test		= _access,					\  	.guest_test_check	= { _test_check },				\  	.fail_vcpu_run_handler	= fail_vcpu_run_mmio_no_syndrome_handler,	\ @@ -874,11 +877,12 @@ static void help(char *name)  {										\  	.name			= SCAT2(ro_memslot_uffd, _access),		\  	.data_memslot_flags	= KVM_MEM_READONLY,				\ +	.pt_memslot_flags	= KVM_MEM_READONLY,				\  	.mem_mark_cmd		= CMD_HOLE_DATA | CMD_HOLE_PT,			\  	.guest_prepare		= { _PREPARE(_access) },			\  	.guest_test		= _access,					\  	.uffd_data_handler	= _uffd_data_handler,				\ -	.uffd_pt_handler	= uffd_pt_write_handler,			\ +	.uffd_pt_handler	= uffd_pt_handler,				\  	.mmio_handler		= _mmio_handler,				\  	.expected_events	= { .mmio_exits = _mmio_exits,			\  				    .uffd_faults = _uffd_faults },		\ @@ -889,10 +893,11 @@ static void help(char *name)  {										\  	.name			= SCAT2(ro_memslot_no_syndrome, _access),	\  	.data_memslot_flags	= KVM_MEM_READONLY,				\ +	.pt_memslot_flags	= KVM_MEM_READONLY,				\  	.mem_mark_cmd		= CMD_HOLE_DATA | CMD_HOLE_PT,			\  	.guest_test		= _access,					\  	.uffd_data_handler	= _uffd_data_handler,				\ -	.uffd_pt_handler	= uffd_pt_write_handler,			\ +	.uffd_pt_handler	= uffd_pt_handler,			\  	.fail_vcpu_run_handler	= fail_vcpu_run_mmio_no_syndrome_handler,	\  	.expected_events	= { .fail_vcpu_runs = 1,			\  				    .uffd_faults = _uffd_faults },		\ @@ -933,44 +938,51 @@ static struct test_desc tests[] = {  	 * (S1PTW).  	 */  	TEST_UFFD(guest_read64, with_af, CMD_HOLE_DATA | CMD_HOLE_PT, -		  uffd_data_read_handler, uffd_pt_write_handler, 2), -	/* no_af should also lead to a PT write. */ +		  uffd_data_handler, uffd_pt_handler, 2),  	TEST_UFFD(guest_read64, no_af, CMD_HOLE_DATA | CMD_HOLE_PT, -		  uffd_data_read_handler, uffd_pt_write_handler, 2), -	/* Note how that cas invokes the read handler. */ +		  uffd_data_handler, uffd_pt_handler, 2),  	TEST_UFFD(guest_cas, with_af, CMD_HOLE_DATA | CMD_HOLE_PT, -		  uffd_data_read_handler, uffd_pt_write_handler, 2), +		  uffd_data_handler, uffd_pt_handler, 2),  	/*  	 * Can't test guest_at with_af as it's IMPDEF whether the AF is set.  	 * The S1PTW fault should still be marked as a write.  	 */  	TEST_UFFD(guest_at, no_af, CMD_HOLE_DATA | CMD_HOLE_PT, -		  uffd_data_read_handler, uffd_pt_write_handler, 1), +		  uffd_no_handler, uffd_pt_handler, 1),  	TEST_UFFD(guest_ld_preidx, with_af, CMD_HOLE_DATA | CMD_HOLE_PT, -		  uffd_data_read_handler, uffd_pt_write_handler, 2), +		  uffd_data_handler, uffd_pt_handler, 2),  	TEST_UFFD(guest_write64, with_af, CMD_HOLE_DATA | CMD_HOLE_PT, -		  uffd_data_write_handler, uffd_pt_write_handler, 2), +		  uffd_data_handler, uffd_pt_handler, 2),  	TEST_UFFD(guest_dc_zva, with_af, CMD_HOLE_DATA | CMD_HOLE_PT, -		  uffd_data_write_handler, uffd_pt_write_handler, 2), +		  uffd_data_handler, uffd_pt_handler, 2),  	TEST_UFFD(guest_st_preidx, with_af, CMD_HOLE_DATA | CMD_HOLE_PT, -		  uffd_data_write_handler, uffd_pt_write_handler, 2), +		  uffd_data_handler, uffd_pt_handler, 2),  	TEST_UFFD(guest_exec, with_af, CMD_HOLE_DATA | CMD_HOLE_PT, -		  uffd_data_read_handler, uffd_pt_write_handler, 2), +		  uffd_data_handler, uffd_pt_handler, 2),  	/*  	 * Try accesses when the data and PT memory regions are both  	 * tracked for dirty logging.  	 */ -	TEST_DIRTY_LOG(guest_read64, with_af, guest_check_no_write_in_dirty_log), -	/* no_af should also lead to a PT write. */ -	TEST_DIRTY_LOG(guest_read64, no_af, guest_check_no_write_in_dirty_log), -	TEST_DIRTY_LOG(guest_ld_preidx, with_af, guest_check_no_write_in_dirty_log), -	TEST_DIRTY_LOG(guest_at, no_af, guest_check_no_write_in_dirty_log), -	TEST_DIRTY_LOG(guest_exec, with_af, guest_check_no_write_in_dirty_log), -	TEST_DIRTY_LOG(guest_write64, with_af, guest_check_write_in_dirty_log), -	TEST_DIRTY_LOG(guest_cas, with_af, guest_check_write_in_dirty_log), -	TEST_DIRTY_LOG(guest_dc_zva, with_af, guest_check_write_in_dirty_log), -	TEST_DIRTY_LOG(guest_st_preidx, with_af, guest_check_write_in_dirty_log), +	TEST_DIRTY_LOG(guest_read64, with_af, guest_check_no_write_in_dirty_log, +		       guest_check_s1ptw_wr_in_dirty_log), +	TEST_DIRTY_LOG(guest_read64, no_af, guest_check_no_write_in_dirty_log, +		       guest_check_no_s1ptw_wr_in_dirty_log), +	TEST_DIRTY_LOG(guest_ld_preidx, with_af, +		       guest_check_no_write_in_dirty_log, +		       guest_check_s1ptw_wr_in_dirty_log), +	TEST_DIRTY_LOG(guest_at, no_af, guest_check_no_write_in_dirty_log, +		       guest_check_no_s1ptw_wr_in_dirty_log), +	TEST_DIRTY_LOG(guest_exec, with_af, guest_check_no_write_in_dirty_log, +		       guest_check_s1ptw_wr_in_dirty_log), +	TEST_DIRTY_LOG(guest_write64, with_af, guest_check_write_in_dirty_log, +		       guest_check_s1ptw_wr_in_dirty_log), +	TEST_DIRTY_LOG(guest_cas, with_af, guest_check_write_in_dirty_log, +		       guest_check_s1ptw_wr_in_dirty_log), +	TEST_DIRTY_LOG(guest_dc_zva, with_af, guest_check_write_in_dirty_log, +		       guest_check_s1ptw_wr_in_dirty_log), +	TEST_DIRTY_LOG(guest_st_preidx, with_af, guest_check_write_in_dirty_log, +		       guest_check_s1ptw_wr_in_dirty_log),  	/*  	 * Access when the data and PT memory regions are both marked for @@ -980,29 +992,43 @@ static struct test_desc tests[] = {  	 * fault, and nothing in the dirty log.  Any S1PTW should result in  	 * a write in the dirty log and a userfaultfd write.  	 */ -	TEST_UFFD_AND_DIRTY_LOG(guest_read64, with_af, uffd_data_read_handler, 2, -				guest_check_no_write_in_dirty_log), -	/* no_af should also lead to a PT write. */ -	TEST_UFFD_AND_DIRTY_LOG(guest_read64, no_af, uffd_data_read_handler, 2, -				guest_check_no_write_in_dirty_log), -	TEST_UFFD_AND_DIRTY_LOG(guest_ld_preidx, with_af, uffd_data_read_handler, -				2, guest_check_no_write_in_dirty_log), -	TEST_UFFD_AND_DIRTY_LOG(guest_at, with_af, 0, 1, -				guest_check_no_write_in_dirty_log), -	TEST_UFFD_AND_DIRTY_LOG(guest_exec, with_af, uffd_data_read_handler, 2, -				guest_check_no_write_in_dirty_log), -	TEST_UFFD_AND_DIRTY_LOG(guest_write64, with_af, uffd_data_write_handler, -				2, guest_check_write_in_dirty_log), -	TEST_UFFD_AND_DIRTY_LOG(guest_cas, with_af, uffd_data_read_handler, 2, -				guest_check_write_in_dirty_log), -	TEST_UFFD_AND_DIRTY_LOG(guest_dc_zva, with_af, uffd_data_write_handler, -				2, guest_check_write_in_dirty_log), +	TEST_UFFD_AND_DIRTY_LOG(guest_read64, with_af, +				uffd_data_handler, 2, +				guest_check_no_write_in_dirty_log, +				guest_check_s1ptw_wr_in_dirty_log), +	TEST_UFFD_AND_DIRTY_LOG(guest_read64, no_af, +				uffd_data_handler, 2, +				guest_check_no_write_in_dirty_log, +				guest_check_no_s1ptw_wr_in_dirty_log), +	TEST_UFFD_AND_DIRTY_LOG(guest_ld_preidx, with_af, +				uffd_data_handler, +				2, guest_check_no_write_in_dirty_log, +				guest_check_s1ptw_wr_in_dirty_log), +	TEST_UFFD_AND_DIRTY_LOG(guest_at, with_af, uffd_no_handler, 1, +				guest_check_no_write_in_dirty_log, +				guest_check_s1ptw_wr_in_dirty_log), +	TEST_UFFD_AND_DIRTY_LOG(guest_exec, with_af, +				uffd_data_handler, 2, +				guest_check_no_write_in_dirty_log, +				guest_check_s1ptw_wr_in_dirty_log), +	TEST_UFFD_AND_DIRTY_LOG(guest_write64, with_af, +				uffd_data_handler, +				2, guest_check_write_in_dirty_log, +				guest_check_s1ptw_wr_in_dirty_log), +	TEST_UFFD_AND_DIRTY_LOG(guest_cas, with_af, +				uffd_data_handler, 2, +				guest_check_write_in_dirty_log, +				guest_check_s1ptw_wr_in_dirty_log), +	TEST_UFFD_AND_DIRTY_LOG(guest_dc_zva, with_af, +				uffd_data_handler, +				2, guest_check_write_in_dirty_log, +				guest_check_s1ptw_wr_in_dirty_log),  	TEST_UFFD_AND_DIRTY_LOG(guest_st_preidx, with_af, -				uffd_data_write_handler, 2, -				guest_check_write_in_dirty_log), - +				uffd_data_handler, 2, +				guest_check_write_in_dirty_log, +				guest_check_s1ptw_wr_in_dirty_log),  	/* -	 * Try accesses when the data memory region is marked read-only +	 * Access when both the PT and data regions are marked read-only  	 * (with KVM_MEM_READONLY). Writes with a syndrome result in an  	 * MMIO exit, writes with no syndrome (e.g., CAS) result in a  	 * failed vcpu run, and reads/execs with and without syndroms do @@ -1018,7 +1044,7 @@ static struct test_desc tests[] = {  	TEST_RO_MEMSLOT_NO_SYNDROME(guest_st_preidx),  	/* -	 * Access when both the data region is both read-only and marked +	 * The PT and data regions are both read-only and marked  	 * for dirty logging at the same time. The expected result is that  	 * for writes there should be no write in the dirty log. The  	 * readonly handling is the same as if the memslot was not marked @@ -1043,7 +1069,7 @@ static struct test_desc tests[] = {  						  guest_check_no_write_in_dirty_log),  	/* -	 * Access when the data region is both read-only and punched with +	 * The PT and data regions are both read-only and punched with  	 * holes tracked with userfaultfd.  The expected result is the  	 * union of both userfaultfd and read-only behaviors. For example,  	 * write accesses result in a userfaultfd write fault and an MMIO @@ -1051,22 +1077,15 @@ static struct test_desc tests[] = {  	 * no userfaultfd write fault. Reads result in userfaultfd getting  	 * triggered.  	 */ -	TEST_RO_MEMSLOT_AND_UFFD(guest_read64, 0, 0, -				 uffd_data_read_handler, 2), -	TEST_RO_MEMSLOT_AND_UFFD(guest_ld_preidx, 0, 0, -				 uffd_data_read_handler, 2), -	TEST_RO_MEMSLOT_AND_UFFD(guest_at, 0, 0, -				 uffd_no_handler, 1), -	TEST_RO_MEMSLOT_AND_UFFD(guest_exec, 0, 0, -				 uffd_data_read_handler, 2), +	TEST_RO_MEMSLOT_AND_UFFD(guest_read64, 0, 0, uffd_data_handler, 2), +	TEST_RO_MEMSLOT_AND_UFFD(guest_ld_preidx, 0, 0, uffd_data_handler, 2), +	TEST_RO_MEMSLOT_AND_UFFD(guest_at, 0, 0, uffd_no_handler, 1), +	TEST_RO_MEMSLOT_AND_UFFD(guest_exec, 0, 0, uffd_data_handler, 2),  	TEST_RO_MEMSLOT_AND_UFFD(guest_write64, mmio_on_test_gpa_handler, 1, -				 uffd_data_write_handler, 2), -	TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_cas, -					     uffd_data_read_handler, 2), -	TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_dc_zva, -					     uffd_no_handler, 1), -	TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_st_preidx, -					     uffd_no_handler, 1), +				 uffd_data_handler, 2), +	TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_cas, uffd_data_handler, 2), +	TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_dc_zva, uffd_no_handler, 1), +	TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_st_preidx, uffd_no_handler, 1),  	{ 0 }  }; | 
