Commit 2040f414 authored by Thomas Huth's avatar Thomas Huth Committed by Christian Borntraeger
Browse files

KVM: selftests: Split ucall.c into architecture specific files



The way we exit from a guest to userspace is very specific to the
architecture: On x86, we use PIO, on aarch64 we are using MMIO and on
s390x we're going to use an instruction instead. The possibility to
select a type via the ucall_type_t enum is currently also completely
unused, so the code in ucall.c currently looks more complex than
required. Let's split this up into architecture specific ucall.c
files instead, so we can get rid of the #ifdefs and the unnecessary
ucall_type_t handling.

Reviewed-by: default avatarAndrew Jones <drjones@redhat.com>
Signed-off-by: default avatarThomas Huth <thuth@redhat.com>
Acked-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Link: https://lore.kernel.org/r/20190731151525.17156-2-thuth@redhat.com


Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
parent 609488bc
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -7,9 +7,9 @@ top_srcdir = ../../../..
KSFT_KHDR_INSTALL := 1
UNAME_M := $(shell uname -m)

LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/ucall.c lib/sparsebit.c
LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c
LIBKVM_aarch64 = lib/aarch64/processor.c
LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c
LIBKVM_x86_64 = lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/ucall.c
LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c
LIBKVM_s390x = lib/s390x/processor.c

TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test
+1 −1
Original line number Diff line number Diff line
@@ -337,7 +337,7 @@ static void run_test(enum vm_guest_mode mode, unsigned long iterations,
	vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
#endif
#ifdef __aarch64__
	ucall_init(vm, UCALL_MMIO, NULL);
	ucall_init(vm, NULL);
#endif

	/* Export the shared variables to the guest */
+1 −7
Original line number Diff line number Diff line
@@ -165,12 +165,6 @@ int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd);
	memcpy(&(g), _p, sizeof(g));				\
})

/* ucall implementation types */
typedef enum {
	UCALL_PIO,
	UCALL_MMIO,
} ucall_type_t;

/* Common ucalls */
enum {
	UCALL_NONE,
@@ -186,7 +180,7 @@ struct ucall {
	uint64_t args[UCALL_MAX_ARGS];
};

void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg);
void ucall_init(struct kvm_vm *vm, void *arg);
void ucall_uninit(struct kvm_vm *vm);
void ucall(uint64_t cmd, int nargs, ...);
uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc);
+112 −0
Original line number Diff line number Diff line
@@ -5,11 +5,8 @@
 * Copyright (C) 2018, Red Hat, Inc.
 */
#include "kvm_util.h"
#include "kvm_util_internal.h"
#include "../kvm_util_internal.h"

#define UCALL_PIO_PORT ((uint16_t)0x1000)

static ucall_type_t ucall_type;
static vm_vaddr_t *ucall_exit_mmio_addr;

static bool ucall_mmio_init(struct kvm_vm *vm, vm_paddr_t gpa)
@@ -25,17 +22,10 @@ static bool ucall_mmio_init(struct kvm_vm *vm, vm_paddr_t gpa)
	return true;
}

void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg)
void ucall_init(struct kvm_vm *vm, void *arg)
{
	ucall_type = type;
	sync_global_to_guest(vm, ucall_type);

	if (type == UCALL_PIO)
		return;

	if (type == UCALL_MMIO) {
	vm_paddr_t gpa, start, end, step, offset;
		unsigned bits;
	unsigned int bits;
	bool ret;

	if (arg) {
@@ -74,29 +64,13 @@ void ucall_init(struct kvm_vm *vm, ucall_type_t type, void *arg)
	}
	TEST_ASSERT(false, "Can't find a ucall mmio address");
}
}

void ucall_uninit(struct kvm_vm *vm)
{
	ucall_type = 0;
	sync_global_to_guest(vm, ucall_type);
	ucall_exit_mmio_addr = 0;
	sync_global_to_guest(vm, ucall_exit_mmio_addr);
}

static void ucall_pio_exit(struct ucall *uc)
{
#ifdef __x86_64__
	asm volatile("in %[port], %%al"
		: : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax");
#endif
}

static void ucall_mmio_exit(struct ucall *uc)
{
	*ucall_exit_mmio_addr = (vm_vaddr_t)uc;
}

void ucall(uint64_t cmd, int nargs, ...)
{
	struct ucall uc = {
@@ -112,42 +86,23 @@ void ucall(uint64_t cmd, int nargs, ...)
		uc.args[i] = va_arg(va, uint64_t);
	va_end(va);

	switch (ucall_type) {
	case UCALL_PIO:
		ucall_pio_exit(&uc);
		break;
	case UCALL_MMIO:
		ucall_mmio_exit(&uc);
		break;
	};
	*ucall_exit_mmio_addr = (vm_vaddr_t)&uc;
}

uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc)
{
	struct kvm_run *run = vcpu_state(vm, vcpu_id);
	struct ucall ucall = {};
	bool got_ucall = false;

#ifdef __x86_64__
	if (ucall_type == UCALL_PIO && run->exit_reason == KVM_EXIT_IO &&
	    run->io.port == UCALL_PIO_PORT) {
		struct kvm_regs regs;
		vcpu_regs_get(vm, vcpu_id, &regs);
		memcpy(&ucall, addr_gva2hva(vm, (vm_vaddr_t)regs.rdi), sizeof(ucall));
		got_ucall = true;
	}
#endif
	if (ucall_type == UCALL_MMIO && run->exit_reason == KVM_EXIT_MMIO &&

	if (run->exit_reason == KVM_EXIT_MMIO &&
	    run->mmio.phys_addr == (uint64_t)ucall_exit_mmio_addr) {
		vm_vaddr_t gva;

		TEST_ASSERT(run->mmio.is_write && run->mmio.len == 8,
			    "Unexpected ucall exit mmio address access");
		memcpy(&gva, run->mmio.data, sizeof(gva));
		memcpy(&ucall, addr_gva2hva(vm, gva), sizeof(ucall));
		got_ucall = true;
	}

	if (got_ucall) {
		vcpu_run_complete_io(vm, vcpu_id);
		if (uc)
			memcpy(uc, &ucall, sizeof(ucall));
+56 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * ucall support. A ucall is a "hypercall to userspace".
 *
 * Copyright (C) 2018, Red Hat, Inc.
 */
#include "kvm_util.h"

#define UCALL_PIO_PORT ((uint16_t)0x1000)

void ucall_init(struct kvm_vm *vm, void *arg)
{
}

void ucall_uninit(struct kvm_vm *vm)
{
}

void ucall(uint64_t cmd, int nargs, ...)
{
	struct ucall uc = {
		.cmd = cmd,
	};
	va_list va;
	int i;

	nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS;

	va_start(va, nargs);
	for (i = 0; i < nargs; ++i)
		uc.args[i] = va_arg(va, uint64_t);
	va_end(va);

	asm volatile("in %[port], %%al"
		: : [port] "d" (UCALL_PIO_PORT), "D" (&uc) : "rax");
}

uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc)
{
	struct kvm_run *run = vcpu_state(vm, vcpu_id);
	struct ucall ucall = {};

	if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
		struct kvm_regs regs;

		vcpu_regs_get(vm, vcpu_id, &regs);
		memcpy(&ucall, addr_gva2hva(vm, (vm_vaddr_t)regs.rdi),
		       sizeof(ucall));

		vcpu_run_complete_io(vm, vcpu_id);
		if (uc)
			memcpy(uc, &ucall, sizeof(ucall));
	}

	return ucall.cmd;
}
Loading