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

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

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/x86/hyperv_ipi.c
Extension
.c
Size
9338 bytes
Lines
311
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[2];
};

enum HV_GENERIC_SET_FORMAT {
	HV_GENERIC_SET_SPARSE_4K,
	HV_GENERIC_SET_ALL,
};

/* HvCallSendSyntheticClusterIpi hypercall */
struct hv_send_ipi {
	u32 vector;
	u32 reserved;
	u64 cpu_mask;
};

/* HvCallSendSyntheticClusterIpiEx hypercall */
struct hv_send_ipi_ex {
	u32 vector;
	u32 reserved;
	struct hv_vpset vp_set;
};

static inline void hv_init(gpa_t pgs_gpa)
{
	wrmsr(HV_X64_MSR_GUEST_OS_ID, HYPERV_LINUX_OS_ID);
	wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa);
}

static void receiver_code(void *hcall_page, gpa_t pgs_gpa)
{
	u32 vcpu_id;

	x2apic_enable();
	hv_init(pgs_gpa);

	vcpu_id = rdmsr(HV_X64_MSR_VP_INDEX);

	/* Signal sender vCPU we're ready */
	ipis_rcvd[vcpu_id] = (u64)-1;

	for (;;) {
		safe_halt();
		cli();
	}
}

static void guest_ipi_handler(struct ex_regs *regs)
{
	u32 vcpu_id = rdmsr(HV_X64_MSR_VP_INDEX);

	ipis_rcvd[vcpu_id]++;
	wrmsr(HV_X64_MSR_EOI, 1);
}

static inline void nop_loop(void)
{
	int i;

	for (i = 0; i < 100000000; i++)
		asm volatile("nop");
}

static void sender_guest_code(void *hcall_page, gpa_t pgs_gpa)
{
	struct hv_send_ipi *ipi = (struct hv_send_ipi *)hcall_page;
	struct hv_send_ipi_ex *ipi_ex = (struct hv_send_ipi_ex *)hcall_page;
	int stage = 1, ipis_expected[2] = {0};

	hv_init(pgs_gpa);
	GUEST_SYNC(stage++);

	/* Wait for receiver vCPUs to come up */
	while (!ipis_rcvd[RECEIVER_VCPU_ID_1] || !ipis_rcvd[RECEIVER_VCPU_ID_2])
		nop_loop();
	ipis_rcvd[RECEIVER_VCPU_ID_1] = ipis_rcvd[RECEIVER_VCPU_ID_2] = 0;

	/* 'Slow' HvCallSendSyntheticClusterIpi to RECEIVER_VCPU_ID_1 */
	ipi->vector = IPI_VECTOR;
	ipi->cpu_mask = 1 << RECEIVER_VCPU_ID_1;
	hyperv_hypercall(HVCALL_SEND_IPI, pgs_gpa, pgs_gpa + PAGE_SIZE);
	nop_loop();
	GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_1] == ++ipis_expected[0]);
	GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_2] == ipis_expected[1]);
	GUEST_SYNC(stage++);
	/* 'Fast' HvCallSendSyntheticClusterIpi to RECEIVER_VCPU_ID_1 */
	hyperv_hypercall(HVCALL_SEND_IPI | HV_HYPERCALL_FAST_BIT,
			 IPI_VECTOR, 1 << RECEIVER_VCPU_ID_1);

Annotation

Implementation Notes