mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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 -----BEGIN PGP SIGNATURE----- iQJDBAABCgAtFiEEn9UcU+C1Yxj9lZw9I9DQutE9ekMFAmPWwGEPHG1hekBrZXJu ZWwub3JnAAoJECPQ0LrRPXpDi/wP/3kbZrZ+y/YNcYioQwqibRS5DKuACKXM1dbh sMX0e8t3frmkrfkHZ1FsBNjSWtDLmRbjANNDWi8ypAXaPVm7/0whFqkJgyPWDO+v /1VXYMwMjy2zpWfPGPu+/fQL0Ninp+EfLP3Y2/Lr8VW5rH21bfuQ1rm41ucK/jB5 IsMiQ+YObZUTrSq22fHfNJKc8fysSqeMHW96bl0QnJxf6aDDieZFGF9rlRQf/faq lPux0faasgQC0VgXlokWGdU1x5kXIf3Ta4VtiKARKNwxziuG8B484+5hHXvoBR1h bXFJJUQjQs2qBuH75BJftini9fvWvQPgbk4NvkD1tlyMhlZ5w2MTTKB4QmuW/WDT OGuGXAcuP2stm0dUaSn1aCwzfYgtihssp+RCAB5DOoL64i/CtHl+FJgz8wZfDPRk UNXdK2JccDfD6bGv/kQqPJoozjI5e8Ha2ks1O4IPHIDpIsVMIWRRGULgIRvLaHaS iaR7Vx+XgzW50Knj++S85eak/aTSkVaykYZIiiB4DTai1/XuAZfMA79X6IvQLxHq 419FHmXwhJmYdWZ/JFBXWnbR6wRJiv4TR23A5u8X6o/YgBn6fmwAt6o8Avk1quZQ mslRPHG45hM/7Z7uSEsIQnbVVnHPhbaKr3GmHlJJ4zXRI8GaSMe23wpnJdUj1q9a w1Oe0rpq =2l/n -----END PGP SIGNATURE----- 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
This commit is contained in:
		
						commit
						25b72cf7da
					
				
					 6 changed files with 132 additions and 98 deletions
				
			
		| 
						 | 
					@ -8070,9 +8070,13 @@ considering the state as complete. VMM needs to ensure that the dirty
 | 
				
			||||||
state is final and avoid missing dirty pages from another ioctl ordered
 | 
					state is final and avoid missing dirty pages from another ioctl ordered
 | 
				
			||||||
after the bitmap collection.
 | 
					after the bitmap collection.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NOTE: One example of using the backup bitmap is saving arm64 vgic/its
 | 
					NOTE: Multiple examples of using the backup bitmap: (1) save vgic/its
 | 
				
			||||||
tables through KVM_DEV_ARM_{VGIC_GRP_CTRL, ITS_SAVE_TABLES} command on
 | 
					tables through command KVM_DEV_ARM_{VGIC_GRP_CTRL, ITS_SAVE_TABLES} on
 | 
				
			||||||
KVM device "kvm-arm-vgic-its" when dirty ring is enabled.
 | 
					KVM device "kvm-arm-vgic-its". (2) restore vgic/its tables through
 | 
				
			||||||
 | 
					command KVM_DEV_ARM_{VGIC_GRP_CTRL, ITS_RESTORE_TABLES} on KVM device
 | 
				
			||||||
 | 
					"kvm-arm-vgic-its". VGICv3 LPI pending status is restored. (3) save
 | 
				
			||||||
 | 
					vgic3 pending table through KVM_DEV_ARM_VGIC_{GRP_CTRL, SAVE_PENDING_TABLES}
 | 
				
			||||||
 | 
					command on KVM device "kvm-arm-vgic-v3".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
8.30 KVM_CAP_XEN_HVM
 | 
					8.30 KVM_CAP_XEN_HVM
 | 
				
			||||||
--------------------
 | 
					--------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2187,7 +2187,7 @@ static int vgic_its_save_ite(struct vgic_its *its, struct its_device *dev,
 | 
				
			||||||
	       ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
 | 
						       ((u64)ite->irq->intid << KVM_ITS_ITE_PINTID_SHIFT) |
 | 
				
			||||||
		ite->collection->collection_id;
 | 
							ite->collection->collection_id;
 | 
				
			||||||
	val = cpu_to_le64(val);
 | 
						val = cpu_to_le64(val);
 | 
				
			||||||
	return kvm_write_guest_lock(kvm, gpa, &val, ite_esz);
 | 
						return vgic_write_guest_lock(kvm, gpa, &val, ite_esz);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -2339,7 +2339,7 @@ static int vgic_its_save_dte(struct vgic_its *its, struct its_device *dev,
 | 
				
			||||||
	       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
 | 
						       (itt_addr_field << KVM_ITS_DTE_ITTADDR_SHIFT) |
 | 
				
			||||||
		(dev->num_eventid_bits - 1));
 | 
							(dev->num_eventid_bits - 1));
 | 
				
			||||||
	val = cpu_to_le64(val);
 | 
						val = cpu_to_le64(val);
 | 
				
			||||||
	return kvm_write_guest_lock(kvm, ptr, &val, dte_esz);
 | 
						return vgic_write_guest_lock(kvm, ptr, &val, dte_esz);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -2526,7 +2526,7 @@ static int vgic_its_save_cte(struct vgic_its *its,
 | 
				
			||||||
	       ((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) |
 | 
						       ((u64)collection->target_addr << KVM_ITS_CTE_RDBASE_SHIFT) |
 | 
				
			||||||
	       collection->collection_id);
 | 
						       collection->collection_id);
 | 
				
			||||||
	val = cpu_to_le64(val);
 | 
						val = cpu_to_le64(val);
 | 
				
			||||||
	return kvm_write_guest_lock(its->dev->kvm, gpa, &val, esz);
 | 
						return vgic_write_guest_lock(its->dev->kvm, gpa, &val, esz);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -2607,7 +2607,7 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	val = 0;
 | 
						val = 0;
 | 
				
			||||||
	BUG_ON(cte_esz > sizeof(val));
 | 
						BUG_ON(cte_esz > sizeof(val));
 | 
				
			||||||
	ret = kvm_write_guest_lock(its->dev->kvm, gpa, &val, cte_esz);
 | 
						ret = vgic_write_guest_lock(its->dev->kvm, gpa, &val, cte_esz);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2743,7 +2743,6 @@ static int vgic_its_has_attr(struct kvm_device *dev,
 | 
				
			||||||
static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
 | 
					static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct vgic_its_abi *abi = vgic_its_get_abi(its);
 | 
						const struct vgic_its_abi *abi = vgic_its_get_abi(its);
 | 
				
			||||||
	struct vgic_dist *dist = &kvm->arch.vgic;
 | 
					 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (attr == KVM_DEV_ARM_VGIC_CTRL_INIT) /* Nothing to do */
 | 
						if (attr == KVM_DEV_ARM_VGIC_CTRL_INIT) /* Nothing to do */
 | 
				
			||||||
| 
						 | 
					@ -2763,9 +2762,7 @@ static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
 | 
				
			||||||
		vgic_its_reset(kvm, its);
 | 
							vgic_its_reset(kvm, its);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case KVM_DEV_ARM_ITS_SAVE_TABLES:
 | 
						case KVM_DEV_ARM_ITS_SAVE_TABLES:
 | 
				
			||||||
		dist->save_its_tables_in_progress = true;
 | 
					 | 
				
			||||||
		ret = abi->save_tables(its);
 | 
							ret = abi->save_tables(its);
 | 
				
			||||||
		dist->save_its_tables_in_progress = false;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case KVM_DEV_ARM_ITS_RESTORE_TABLES:
 | 
						case KVM_DEV_ARM_ITS_RESTORE_TABLES:
 | 
				
			||||||
		ret = abi->restore_tables(its);
 | 
							ret = abi->restore_tables(its);
 | 
				
			||||||
| 
						 | 
					@ -2792,7 +2789,7 @@ bool kvm_arch_allow_write_without_running_vcpu(struct kvm *kvm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct vgic_dist *dist = &kvm->arch.vgic;
 | 
						struct vgic_dist *dist = &kvm->arch.vgic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return dist->save_its_tables_in_progress;
 | 
						return dist->table_write_in_progress;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vgic_its_set_attr(struct kvm_device *dev,
 | 
					static int vgic_its_set_attr(struct kvm_device *dev,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -339,7 +339,7 @@ int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq)
 | 
				
			||||||
	if (status) {
 | 
						if (status) {
 | 
				
			||||||
		/* clear consumed data */
 | 
							/* clear consumed data */
 | 
				
			||||||
		val &= ~(1 << bit_nr);
 | 
							val &= ~(1 << bit_nr);
 | 
				
			||||||
		ret = kvm_write_guest_lock(kvm, ptr, &val, 1);
 | 
							ret = vgic_write_guest_lock(kvm, ptr, &val, 1);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -434,7 +434,7 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			val &= ~(1 << bit_nr);
 | 
								val &= ~(1 << bit_nr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = kvm_write_guest_lock(kvm, ptr, &val, 1);
 | 
							ret = vgic_write_guest_lock(kvm, ptr, &val, 1);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
#define __KVM_ARM_VGIC_NEW_H__
 | 
					#define __KVM_ARM_VGIC_NEW_H__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/irqchip/arm-gic-common.h>
 | 
					#include <linux/irqchip/arm-gic-common.h>
 | 
				
			||||||
 | 
					#include <asm/kvm_mmu.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 | 
					#define PRODUCT_ID_KVM		0x4b	/* ASCII code K */
 | 
				
			||||||
#define IMPLEMENTER_ARM		0x43b
 | 
					#define IMPLEMENTER_ARM		0x43b
 | 
				
			||||||
| 
						 | 
					@ -131,6 +132,19 @@ static inline bool vgic_irq_is_multi_sgi(struct vgic_irq *irq)
 | 
				
			||||||
	return vgic_irq_get_lr_count(irq) > 1;
 | 
						return vgic_irq_get_lr_count(irq) > 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa,
 | 
				
			||||||
 | 
										const void *data, unsigned long len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vgic_dist *dist = &kvm->arch.vgic;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dist->table_write_in_progress = true;
 | 
				
			||||||
 | 
						ret = kvm_write_guest_lock(kvm, gpa, data, len);
 | 
				
			||||||
 | 
						dist->table_write_in_progress = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This struct provides an intermediate representation of the fields contained
 | 
					 * This struct provides an intermediate representation of the fields contained
 | 
				
			||||||
 * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC
 | 
					 * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -263,7 +263,7 @@ struct vgic_dist {
 | 
				
			||||||
	struct vgic_io_device	dist_iodev;
 | 
						struct vgic_io_device	dist_iodev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool			has_its;
 | 
						bool			has_its;
 | 
				
			||||||
	bool			save_its_tables_in_progress;
 | 
						bool			table_write_in_progress;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Contains the attributes and gpa of the LPI configuration table.
 | 
						 * Contains the attributes and gpa of the LPI configuration table.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -237,6 +237,11 @@ static void guest_check_s1ptw_wr_in_dirty_log(void)
 | 
				
			||||||
	GUEST_SYNC(CMD_CHECK_S1PTW_WR_IN_DIRTY_LOG);
 | 
						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)
 | 
					static void guest_exec(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int (*code)(void) = (int (*)(void))TEST_EXEC_GVA;
 | 
						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. */
 | 
					/* 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,
 | 
					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 addr = msg->arg.pagefault.address;
 | 
				
			||||||
	uint64_t flags = msg->arg.pagefault.flags;
 | 
						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,
 | 
						TEST_ASSERT(uffd_mode == UFFDIO_REGISTER_MODE_MISSING,
 | 
				
			||||||
		    "The only expected UFFD mode is MISSING");
 | 
							    "The only expected UFFD mode is MISSING");
 | 
				
			||||||
	ASSERT_EQ(!!(flags & UFFD_PAGEFAULT_FLAG_WRITE), expect_write);
 | 
					 | 
				
			||||||
	ASSERT_EQ(addr, (uint64_t)args->hva);
 | 
						ASSERT_EQ(addr, (uint64_t)args->hva);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pr_debug("uffd fault: addr=%p write=%d\n",
 | 
						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;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int uffd_pt_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, &pt_args, true);
 | 
						return uffd_generic_handler(mode, uffd, msg, &pt_args);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int uffd_data_write_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, true);
 | 
						return uffd_generic_handler(mode, uffd, msg, &data_args);
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int uffd_data_read_handler(int mode, int uffd, struct uffd_msg *msg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return uffd_generic_handler(mode, uffd, msg, &data_args, false);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void setup_uffd_args(struct userspace_mem_region *region,
 | 
					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;
 | 
						struct userspace_mem_region *data_region, *pt_region;
 | 
				
			||||||
	bool continue_test = true;
 | 
						bool continue_test = true;
 | 
				
			||||||
 | 
						uint64_t pte_gpa, pte_pg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data_region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA);
 | 
						data_region = vm_get_mem_region(vm, MEM_REGION_TEST_DATA);
 | 
				
			||||||
	pt_region = vm_get_mem_region(vm, MEM_REGION_PT);
 | 
						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)
 | 
						if (cmd == CMD_SKIP_TEST)
 | 
				
			||||||
		continue_test = false;
 | 
							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),
 | 
							TEST_ASSERT(check_write_in_dirty_log(vm, data_region, 0),
 | 
				
			||||||
			    "Missing write in dirty log");
 | 
								    "Missing write in dirty log");
 | 
				
			||||||
	if (cmd & CMD_CHECK_S1PTW_WR_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");
 | 
								    "Missing s1ptw write in dirty log");
 | 
				
			||||||
	if (cmd & CMD_CHECK_NO_WRITE_IN_DIRTY_LOG)
 | 
						if (cmd & CMD_CHECK_NO_WRITE_IN_DIRTY_LOG)
 | 
				
			||||||
		TEST_ASSERT(!check_write_in_dirty_log(vm, data_region, 0),
 | 
							TEST_ASSERT(!check_write_in_dirty_log(vm, data_region, 0),
 | 
				
			||||||
			    "Unexpected write in dirty log");
 | 
								    "Unexpected write in dirty log");
 | 
				
			||||||
	if (cmd & CMD_CHECK_NO_S1PTW_WR_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");
 | 
								    "Unexpected s1ptw write in dirty log");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return continue_test;
 | 
						return continue_test;
 | 
				
			||||||
| 
						 | 
					@ -797,7 +799,7 @@ static void help(char *name)
 | 
				
			||||||
	.expected_events	= { .uffd_faults = _uffd_faults, },		\
 | 
						.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),		\
 | 
						.name			= SCAT3(dirty_log, _access, _with_af),		\
 | 
				
			||||||
	.data_memslot_flags	= KVM_MEM_LOG_DIRTY_PAGES,			\
 | 
						.data_memslot_flags	= KVM_MEM_LOG_DIRTY_PAGES,			\
 | 
				
			||||||
| 
						 | 
					@ -805,13 +807,12 @@ static void help(char *name)
 | 
				
			||||||
	.guest_prepare		= { _PREPARE(_with_af),				\
 | 
						.guest_prepare		= { _PREPARE(_with_af),				\
 | 
				
			||||||
				    _PREPARE(_access) },			\
 | 
									    _PREPARE(_access) },			\
 | 
				
			||||||
	.guest_test		= _access,					\
 | 
						.guest_test		= _access,					\
 | 
				
			||||||
	.guest_test_check	= { _CHECK(_with_af), _test_check,		\
 | 
						.guest_test_check	= { _CHECK(_with_af), _test_check, _pt_check },	\
 | 
				
			||||||
				    guest_check_s1ptw_wr_in_dirty_log},		\
 | 
					 | 
				
			||||||
	.expected_events	= { 0 },					\
 | 
						.expected_events	= { 0 },					\
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TEST_UFFD_AND_DIRTY_LOG(_access, _with_af, _uffd_data_handler,		\
 | 
					#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),	\
 | 
						.name			= SCAT3(uffd_and_dirty_log, _access, _with_af),	\
 | 
				
			||||||
	.data_memslot_flags	= KVM_MEM_LOG_DIRTY_PAGES,			\
 | 
						.data_memslot_flags	= KVM_MEM_LOG_DIRTY_PAGES,			\
 | 
				
			||||||
| 
						 | 
					@ -820,16 +821,17 @@ static void help(char *name)
 | 
				
			||||||
				    _PREPARE(_access) },			\
 | 
									    _PREPARE(_access) },			\
 | 
				
			||||||
	.guest_test		= _access,					\
 | 
						.guest_test		= _access,					\
 | 
				
			||||||
	.mem_mark_cmd		= CMD_HOLE_DATA | CMD_HOLE_PT,			\
 | 
						.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_data_handler	= _uffd_data_handler,				\
 | 
				
			||||||
	.uffd_pt_handler	= uffd_pt_write_handler,			\
 | 
						.uffd_pt_handler	= uffd_pt_handler,				\
 | 
				
			||||||
	.expected_events	= { .uffd_faults = _uffd_faults, },		\
 | 
						.expected_events	= { .uffd_faults = _uffd_faults, },		\
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TEST_RO_MEMSLOT(_access, _mmio_handler, _mmio_exits)			\
 | 
					#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,				\
 | 
						.data_memslot_flags	= KVM_MEM_READONLY,				\
 | 
				
			||||||
 | 
						.pt_memslot_flags	= KVM_MEM_READONLY,				\
 | 
				
			||||||
	.guest_prepare		= { _PREPARE(_access) },			\
 | 
						.guest_prepare		= { _PREPARE(_access) },			\
 | 
				
			||||||
	.guest_test		= _access,					\
 | 
						.guest_test		= _access,					\
 | 
				
			||||||
	.mmio_handler		= _mmio_handler,				\
 | 
						.mmio_handler		= _mmio_handler,				\
 | 
				
			||||||
| 
						 | 
					@ -840,6 +842,7 @@ static void help(char *name)
 | 
				
			||||||
{										\
 | 
					{										\
 | 
				
			||||||
	.name			= SCAT2(ro_memslot_no_syndrome, _access),	\
 | 
						.name			= SCAT2(ro_memslot_no_syndrome, _access),	\
 | 
				
			||||||
	.data_memslot_flags	= KVM_MEM_READONLY,				\
 | 
						.data_memslot_flags	= KVM_MEM_READONLY,				\
 | 
				
			||||||
 | 
						.pt_memslot_flags	= KVM_MEM_READONLY,				\
 | 
				
			||||||
	.guest_test		= _access,					\
 | 
						.guest_test		= _access,					\
 | 
				
			||||||
	.fail_vcpu_run_handler	= fail_vcpu_run_mmio_no_syndrome_handler,	\
 | 
						.fail_vcpu_run_handler	= fail_vcpu_run_mmio_no_syndrome_handler,	\
 | 
				
			||||||
	.expected_events	= { .fail_vcpu_runs = 1 },			\
 | 
						.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,	\
 | 
					#define TEST_RO_MEMSLOT_AND_DIRTY_LOG(_access, _mmio_handler, _mmio_exits,	\
 | 
				
			||||||
				      _test_check)				\
 | 
									      _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,	\
 | 
						.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_prepare		= { _PREPARE(_access) },			\
 | 
				
			||||||
	.guest_test		= _access,					\
 | 
						.guest_test		= _access,					\
 | 
				
			||||||
	.guest_test_check	= { _test_check },				\
 | 
						.guest_test_check	= { _test_check },				\
 | 
				
			||||||
| 
						 | 
					@ -862,7 +865,7 @@ static void help(char *name)
 | 
				
			||||||
{										\
 | 
					{										\
 | 
				
			||||||
	.name			= SCAT2(ro_memslot_no_syn_and_dlog, _access),	\
 | 
						.name			= SCAT2(ro_memslot_no_syn_and_dlog, _access),	\
 | 
				
			||||||
	.data_memslot_flags	= KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES,	\
 | 
						.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		= _access,					\
 | 
				
			||||||
	.guest_test_check	= { _test_check },				\
 | 
						.guest_test_check	= { _test_check },				\
 | 
				
			||||||
	.fail_vcpu_run_handler	= fail_vcpu_run_mmio_no_syndrome_handler,	\
 | 
						.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),		\
 | 
						.name			= SCAT2(ro_memslot_uffd, _access),		\
 | 
				
			||||||
	.data_memslot_flags	= KVM_MEM_READONLY,				\
 | 
						.data_memslot_flags	= KVM_MEM_READONLY,				\
 | 
				
			||||||
 | 
						.pt_memslot_flags	= KVM_MEM_READONLY,				\
 | 
				
			||||||
	.mem_mark_cmd		= CMD_HOLE_DATA | CMD_HOLE_PT,			\
 | 
						.mem_mark_cmd		= CMD_HOLE_DATA | CMD_HOLE_PT,			\
 | 
				
			||||||
	.guest_prepare		= { _PREPARE(_access) },			\
 | 
						.guest_prepare		= { _PREPARE(_access) },			\
 | 
				
			||||||
	.guest_test		= _access,					\
 | 
						.guest_test		= _access,					\
 | 
				
			||||||
	.uffd_data_handler	= _uffd_data_handler,				\
 | 
						.uffd_data_handler	= _uffd_data_handler,				\
 | 
				
			||||||
	.uffd_pt_handler	= uffd_pt_write_handler,			\
 | 
						.uffd_pt_handler	= uffd_pt_handler,				\
 | 
				
			||||||
	.mmio_handler		= _mmio_handler,				\
 | 
						.mmio_handler		= _mmio_handler,				\
 | 
				
			||||||
	.expected_events	= { .mmio_exits = _mmio_exits,			\
 | 
						.expected_events	= { .mmio_exits = _mmio_exits,			\
 | 
				
			||||||
				    .uffd_faults = _uffd_faults },		\
 | 
									    .uffd_faults = _uffd_faults },		\
 | 
				
			||||||
| 
						 | 
					@ -889,10 +893,11 @@ static void help(char *name)
 | 
				
			||||||
{										\
 | 
					{										\
 | 
				
			||||||
	.name			= SCAT2(ro_memslot_no_syndrome, _access),	\
 | 
						.name			= SCAT2(ro_memslot_no_syndrome, _access),	\
 | 
				
			||||||
	.data_memslot_flags	= KVM_MEM_READONLY,				\
 | 
						.data_memslot_flags	= KVM_MEM_READONLY,				\
 | 
				
			||||||
 | 
						.pt_memslot_flags	= KVM_MEM_READONLY,				\
 | 
				
			||||||
	.mem_mark_cmd		= CMD_HOLE_DATA | CMD_HOLE_PT,			\
 | 
						.mem_mark_cmd		= CMD_HOLE_DATA | CMD_HOLE_PT,			\
 | 
				
			||||||
	.guest_test		= _access,					\
 | 
						.guest_test		= _access,					\
 | 
				
			||||||
	.uffd_data_handler	= _uffd_data_handler,				\
 | 
						.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,	\
 | 
						.fail_vcpu_run_handler	= fail_vcpu_run_mmio_no_syndrome_handler,	\
 | 
				
			||||||
	.expected_events	= { .fail_vcpu_runs = 1,			\
 | 
						.expected_events	= { .fail_vcpu_runs = 1,			\
 | 
				
			||||||
				    .uffd_faults = _uffd_faults },		\
 | 
									    .uffd_faults = _uffd_faults },		\
 | 
				
			||||||
| 
						 | 
					@ -933,44 +938,51 @@ static struct test_desc tests[] = {
 | 
				
			||||||
	 * (S1PTW).
 | 
						 * (S1PTW).
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	TEST_UFFD(guest_read64, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
 | 
						TEST_UFFD(guest_read64, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
 | 
				
			||||||
		  uffd_data_read_handler, uffd_pt_write_handler, 2),
 | 
							  uffd_data_handler, uffd_pt_handler, 2),
 | 
				
			||||||
	/* no_af should also lead to a PT write. */
 | 
					 | 
				
			||||||
	TEST_UFFD(guest_read64, no_af, CMD_HOLE_DATA | CMD_HOLE_PT,
 | 
						TEST_UFFD(guest_read64, no_af, CMD_HOLE_DATA | CMD_HOLE_PT,
 | 
				
			||||||
		  uffd_data_read_handler, uffd_pt_write_handler, 2),
 | 
							  uffd_data_handler, uffd_pt_handler, 2),
 | 
				
			||||||
	/* Note how that cas invokes the read handler. */
 | 
					 | 
				
			||||||
	TEST_UFFD(guest_cas, with_af, CMD_HOLE_DATA | CMD_HOLE_PT,
 | 
						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.
 | 
						 * 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.
 | 
						 * The S1PTW fault should still be marked as a write.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	TEST_UFFD(guest_at, no_af, CMD_HOLE_DATA | CMD_HOLE_PT,
 | 
						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,
 | 
						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,
 | 
						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,
 | 
						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,
 | 
						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,
 | 
						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
 | 
						 * Try accesses when the data and PT memory regions are both
 | 
				
			||||||
	 * tracked for dirty logging.
 | 
						 * tracked for dirty logging.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	TEST_DIRTY_LOG(guest_read64, with_af, guest_check_no_write_in_dirty_log),
 | 
						TEST_DIRTY_LOG(guest_read64, with_af, guest_check_no_write_in_dirty_log,
 | 
				
			||||||
	/* no_af should also lead to a PT write. */
 | 
							       guest_check_s1ptw_wr_in_dirty_log),
 | 
				
			||||||
	TEST_DIRTY_LOG(guest_read64, no_af, guest_check_no_write_in_dirty_log),
 | 
						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),
 | 
							       guest_check_no_s1ptw_wr_in_dirty_log),
 | 
				
			||||||
	TEST_DIRTY_LOG(guest_at, no_af, guest_check_no_write_in_dirty_log),
 | 
						TEST_DIRTY_LOG(guest_ld_preidx, with_af,
 | 
				
			||||||
	TEST_DIRTY_LOG(guest_exec, with_af, guest_check_no_write_in_dirty_log),
 | 
							       guest_check_no_write_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),
 | 
						TEST_DIRTY_LOG(guest_at, no_af, guest_check_no_write_in_dirty_log,
 | 
				
			||||||
	TEST_DIRTY_LOG(guest_dc_zva, with_af, guest_check_write_in_dirty_log),
 | 
							       guest_check_no_s1ptw_wr_in_dirty_log),
 | 
				
			||||||
	TEST_DIRTY_LOG(guest_st_preidx, with_af, guest_check_write_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
 | 
						 * 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
 | 
						 * fault, and nothing in the dirty log.  Any S1PTW should result in
 | 
				
			||||||
	 * a write in the dirty log and a userfaultfd write.
 | 
						 * a write in the dirty log and a userfaultfd write.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	TEST_UFFD_AND_DIRTY_LOG(guest_read64, with_af, uffd_data_read_handler, 2,
 | 
						TEST_UFFD_AND_DIRTY_LOG(guest_read64, with_af,
 | 
				
			||||||
				guest_check_no_write_in_dirty_log),
 | 
									uffd_data_handler, 2,
 | 
				
			||||||
	/* no_af should also lead to a PT write. */
 | 
									guest_check_no_write_in_dirty_log,
 | 
				
			||||||
	TEST_UFFD_AND_DIRTY_LOG(guest_read64, no_af, uffd_data_read_handler, 2,
 | 
									guest_check_s1ptw_wr_in_dirty_log),
 | 
				
			||||||
				guest_check_no_write_in_dirty_log),
 | 
						TEST_UFFD_AND_DIRTY_LOG(guest_read64, no_af,
 | 
				
			||||||
	TEST_UFFD_AND_DIRTY_LOG(guest_ld_preidx, with_af, uffd_data_read_handler,
 | 
									uffd_data_handler, 2,
 | 
				
			||||||
				2, guest_check_no_write_in_dirty_log),
 | 
									guest_check_no_write_in_dirty_log,
 | 
				
			||||||
	TEST_UFFD_AND_DIRTY_LOG(guest_at, with_af, 0, 1,
 | 
									guest_check_no_s1ptw_wr_in_dirty_log),
 | 
				
			||||||
				guest_check_no_write_in_dirty_log),
 | 
						TEST_UFFD_AND_DIRTY_LOG(guest_ld_preidx, with_af,
 | 
				
			||||||
	TEST_UFFD_AND_DIRTY_LOG(guest_exec, with_af, uffd_data_read_handler, 2,
 | 
									uffd_data_handler,
 | 
				
			||||||
				guest_check_no_write_in_dirty_log),
 | 
									2, guest_check_no_write_in_dirty_log,
 | 
				
			||||||
	TEST_UFFD_AND_DIRTY_LOG(guest_write64, with_af, uffd_data_write_handler,
 | 
									guest_check_s1ptw_wr_in_dirty_log),
 | 
				
			||||||
				2, guest_check_write_in_dirty_log),
 | 
						TEST_UFFD_AND_DIRTY_LOG(guest_at, with_af, uffd_no_handler, 1,
 | 
				
			||||||
	TEST_UFFD_AND_DIRTY_LOG(guest_cas, with_af, uffd_data_read_handler, 2,
 | 
									guest_check_no_write_in_dirty_log,
 | 
				
			||||||
				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_write_handler,
 | 
						TEST_UFFD_AND_DIRTY_LOG(guest_exec, with_af,
 | 
				
			||||||
				2, guest_check_write_in_dirty_log),
 | 
									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,
 | 
						TEST_UFFD_AND_DIRTY_LOG(guest_st_preidx, with_af,
 | 
				
			||||||
				uffd_data_write_handler, 2,
 | 
									uffd_data_handler, 2,
 | 
				
			||||||
				guest_check_write_in_dirty_log),
 | 
									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
 | 
						 * (with KVM_MEM_READONLY). Writes with a syndrome result in an
 | 
				
			||||||
	 * MMIO exit, writes with no syndrome (e.g., CAS) result in a
 | 
						 * MMIO exit, writes with no syndrome (e.g., CAS) result in a
 | 
				
			||||||
	 * failed vcpu run, and reads/execs with and without syndroms do
 | 
						 * 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),
 | 
						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 dirty logging at the same time. The expected result is that
 | 
				
			||||||
	 * for writes there should be no write in the dirty log. The
 | 
						 * for writes there should be no write in the dirty log. The
 | 
				
			||||||
	 * readonly handling is the same as if the memslot was not marked
 | 
						 * 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),
 | 
											  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
 | 
						 * holes tracked with userfaultfd.  The expected result is the
 | 
				
			||||||
	 * union of both userfaultfd and read-only behaviors. For example,
 | 
						 * union of both userfaultfd and read-only behaviors. For example,
 | 
				
			||||||
	 * write accesses result in a userfaultfd write fault and an MMIO
 | 
						 * 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
 | 
						 * no userfaultfd write fault. Reads result in userfaultfd getting
 | 
				
			||||||
	 * triggered.
 | 
						 * triggered.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	TEST_RO_MEMSLOT_AND_UFFD(guest_read64, 0, 0,
 | 
						TEST_RO_MEMSLOT_AND_UFFD(guest_read64, 0, 0, uffd_data_handler, 2),
 | 
				
			||||||
				 uffd_data_read_handler, 2),
 | 
						TEST_RO_MEMSLOT_AND_UFFD(guest_ld_preidx, 0, 0, uffd_data_handler, 2),
 | 
				
			||||||
	TEST_RO_MEMSLOT_AND_UFFD(guest_ld_preidx, 0, 0,
 | 
						TEST_RO_MEMSLOT_AND_UFFD(guest_at, 0, 0, uffd_no_handler, 1),
 | 
				
			||||||
				 uffd_data_read_handler, 2),
 | 
						TEST_RO_MEMSLOT_AND_UFFD(guest_exec, 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_read_handler, 2),
 | 
					 | 
				
			||||||
	TEST_RO_MEMSLOT_AND_UFFD(guest_write64, mmio_on_test_gpa_handler, 1,
 | 
						TEST_RO_MEMSLOT_AND_UFFD(guest_write64, mmio_on_test_gpa_handler, 1,
 | 
				
			||||||
				 uffd_data_write_handler, 2),
 | 
									 uffd_data_handler, 2),
 | 
				
			||||||
	TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_cas,
 | 
						TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_cas, uffd_data_handler, 2),
 | 
				
			||||||
					     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_dc_zva,
 | 
						TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_st_preidx, uffd_no_handler, 1),
 | 
				
			||||||
					     uffd_no_handler, 1),
 | 
					 | 
				
			||||||
	TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_st_preidx,
 | 
					 | 
				
			||||||
					     uffd_no_handler, 1),
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{ 0 }
 | 
						{ 0 }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue