Commit c0c76d99 authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini
Browse files

KVM: selftests: Add helpers to make Xen-style VMCALL/VMMCALL hypercalls



Add wrappers to do hypercalls using VMCALL/VMMCALL and Xen's register ABI
(as opposed to full Xen-style hypercalls through a hypervisor provided
page).  Using the common helpers dedups a pile of code, and uses the
native hypercall instruction when running on AMD.

Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
Message-Id: <20230204024151.1373296-3-seanjc@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 4009e0bb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -1063,6 +1063,8 @@ uint64_t *vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr);

uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2,
		       uint64_t a3);
uint64_t __xen_hypercall(uint64_t nr, uint64_t a0, void *a1);
void xen_hypercall(uint64_t nr, uint64_t a0, void *a1);

void __vm_xsave_require_permission(int bit, const char *name);

+10 −0
Original line number Diff line number Diff line
@@ -1161,6 +1161,16 @@ uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2,
	return X86_HYPERCALL("a"(nr), "b"(a0), "c"(a1), "d"(a2), "S"(a3));
}

uint64_t __xen_hypercall(uint64_t nr, uint64_t a0, void *a1)
{
	return X86_HYPERCALL("a"(nr), "D"(a0), "S"(a1));
}

void xen_hypercall(uint64_t nr, uint64_t a0, void *a1)
{
	GUEST_ASSERT(!__xen_hypercall(nr, a0, a1));
}

const struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void)
{
	static struct kvm_cpuid2 *cpuid;
+9 −54
Original line number Diff line number Diff line
@@ -225,15 +225,8 @@ static void guest_code(void)

	/* Our turn. Deliver event channel (to ourselves) with
	 * EVTCHNOP_send hypercall. */
	unsigned long rax;
	struct evtchn_send s = { .port = 127 };
	__asm__ __volatile__ ("vmcall" :
			      "=a" (rax) :
			      "a" (__HYPERVISOR_event_channel_op),
			      "D" (EVTCHNOP_send),
			      "S" (&s));

	GUEST_ASSERT(rax == 0);
	xen_hypercall(__HYPERVISOR_event_channel_op, EVTCHNOP_send, &s);

	guest_wait_for_irq();

@@ -242,24 +235,15 @@ static void guest_code(void)
	/* Deliver "outbound" event channel to an eventfd which
	 * happens to be one of our own irqfds. */
	s.port = 197;
	__asm__ __volatile__ ("vmcall" :
			      "=a" (rax) :
			      "a" (__HYPERVISOR_event_channel_op),
			      "D" (EVTCHNOP_send),
			      "S" (&s));

	GUEST_ASSERT(rax == 0);
	xen_hypercall(__HYPERVISOR_event_channel_op, EVTCHNOP_send, &s);

	guest_wait_for_irq();

	GUEST_SYNC(13);

	/* Set a timer 100ms in the future. */
	__asm__ __volatile__ ("vmcall" :
			      "=a" (rax) :
			      "a" (__HYPERVISOR_set_timer_op),
			      "D" (rs->state_entry_time + 100000000));
	GUEST_ASSERT(rax == 0);
	xen_hypercall(__HYPERVISOR_set_timer_op,
		      rs->state_entry_time + 100000000, NULL);

	GUEST_SYNC(14);

@@ -281,37 +265,19 @@ static void guest_code(void)
		.timeout = 0,
	};

	__asm__ __volatile__ ("vmcall" :
			      "=a" (rax) :
			      "a" (__HYPERVISOR_sched_op),
			      "D" (SCHEDOP_poll),
			      "S" (&p));

	GUEST_ASSERT(rax == 0);
	xen_hypercall(__HYPERVISOR_sched_op, SCHEDOP_poll, &p);

	GUEST_SYNC(17);

	/* Poll for an unset port and wait for the timeout. */
	p.timeout = 100000000;
	__asm__ __volatile__ ("vmcall" :
			      "=a" (rax) :
			      "a" (__HYPERVISOR_sched_op),
			      "D" (SCHEDOP_poll),
			      "S" (&p));

	GUEST_ASSERT(rax == 0);
	xen_hypercall(__HYPERVISOR_sched_op, SCHEDOP_poll, &p);

	GUEST_SYNC(18);

	/* A timer will wake the masked port we're waiting on, while we poll */
	p.timeout = 0;
	__asm__ __volatile__ ("vmcall" :
			      "=a" (rax) :
			      "a" (__HYPERVISOR_sched_op),
			      "D" (SCHEDOP_poll),
			      "S" (&p));

	GUEST_ASSERT(rax == 0);
	xen_hypercall(__HYPERVISOR_sched_op, SCHEDOP_poll, &p);

	GUEST_SYNC(19);

@@ -319,13 +285,7 @@ static void guest_code(void)
	 * actual interrupt, while we're polling on a different port. */
	ports[0]++;
	p.timeout = 0;
	__asm__ __volatile__ ("vmcall" :
			      "=a" (rax) :
			      "a" (__HYPERVISOR_sched_op),
			      "D" (SCHEDOP_poll),
			      "S" (&p));

	GUEST_ASSERT(rax == 0);
	xen_hypercall(__HYPERVISOR_sched_op, SCHEDOP_poll, &p);

	guest_wait_for_irq();

@@ -360,12 +320,7 @@ static void guest_code(void)
	 * timer IRQ is dropped due to an invalid event channel.
	 */
	for (i = 0; i < 100 && !guest_saw_irq; i++)
		asm volatile("vmcall"
			     : "=a" (rax)
			     : "a" (__HYPERVISOR_sched_op),
			       "D" (SCHEDOP_poll),
			       "S" (&p)
			     : "memory");
		__xen_hypercall(__HYPERVISOR_sched_op, SCHEDOP_poll, &p);

	/*
	 * Re-send the timer IRQ if it was (likely) dropped due to the timer