tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c
Extension
.c
Size
21114 bytes
Lines
670
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct hv_vpset {
	u64 format;
	u64 valid_bank_mask;
	u64 bank_contents[];
};

enum HV_GENERIC_SET_FORMAT {
	HV_GENERIC_SET_SPARSE_4K,
	HV_GENERIC_SET_ALL,
};

#define HV_FLUSH_ALL_PROCESSORS			BIT(0)
#define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES	BIT(1)
#define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY	BIT(2)
#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT	BIT(3)

/* HvFlushVirtualAddressSpace, HvFlushVirtualAddressList hypercalls */
struct hv_tlb_flush {
	u64 address_space;
	u64 flags;
	u64 processor_mask;
	u64 gva_list[];
} __packed;

/* HvFlushVirtualAddressSpaceEx, HvFlushVirtualAddressListEx hypercalls */
struct hv_tlb_flush_ex {
	u64 address_space;
	u64 flags;
	struct hv_vpset hv_vp_set;
	u64 gva_list[];
} __packed;

/*
 * Pass the following info to 'workers' and 'sender'
 * - Hypercall page's GVA
 * - Hypercall page's GPA
 * - Test pages GVA
 * - GVAs of the test pages' PTEs
 */
struct test_data {
	gva_t hcall_gva;
	gpa_t hcall_gpa;
	gva_t test_pages;
	gva_t test_pages_pte[NTEST_PAGES];
};

/* 'Worker' vCPU code checking the contents of the test page */
static void worker_guest_code(gva_t test_data)
{
	struct test_data *data = (struct test_data *)test_data;
	u32 vcpu_id = rdmsr(HV_X64_MSR_VP_INDEX);
	void *exp_page = (void *)data->test_pages + PAGE_SIZE * NTEST_PAGES;
	u64 *this_cpu = (u64 *)(exp_page + vcpu_id * sizeof(u64));
	u64 expected, val;

	x2apic_enable();
	wrmsr(HV_X64_MSR_GUEST_OS_ID, HYPERV_LINUX_OS_ID);

	for (;;) {
		cpu_relax();

		expected = READ_ONCE(*this_cpu);

		/*
		 * Make sure the value in the test page is read after reading
		 * the expectation for the first time. Pairs with wmb() in
		 * prepare_to_test().
		 */
		rmb();

		val = READ_ONCE(*(u64 *)data->test_pages);

		/*
		 * Make sure the value in the test page is read after before
		 * reading the expectation for the second time. Pairs with wmb()
		 * post_test().
		 */
		rmb();

		/*
		 * '0' indicates the sender is between iterations, wait until
		 * the sender is ready for this vCPU to start checking again.
		 */
		if (!expected)
			continue;

		/*
		 * Re-read the per-vCPU byte to ensure the sender didn't move
		 * onto a new iteration.
		 */

Annotation

Implementation Notes