summaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/kvm/lib/x86_64
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2019-09-11 18:06:15 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2019-09-11 18:06:15 +0200
commit17a81bdb4ee441bcbf09ec76f530197c3788d610 (patch)
tree9385f7487c54d8d5f730da6b2f8b0d64730977dc /tools/testing/selftests/kvm/lib/x86_64
parent95c065400a127291f05ab8a9e72ba65fbcda2335 (diff)
parent81cb736c0c928444e2f4707513c167d5d39844a4 (diff)
downloadlinux-17a81bdb4ee441bcbf09ec76f530197c3788d610.tar.bz2
Merge tag 'kvm-s390-next-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD
* More selftests * Improved KVM_S390_MEM_OP ioctl input checking * Add kvm_valid_regs and kvm_dirty_regs invalid bit checking
Diffstat (limited to 'tools/testing/selftests/kvm/lib/x86_64')
-rw-r--r--tools/testing/selftests/kvm/lib/x86_64/ucall.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/tools/testing/selftests/kvm/lib/x86_64/ucall.c b/tools/testing/selftests/kvm/lib/x86_64/ucall.c
new file mode 100644
index 000000000000..4bfc9a90b1de
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/x86_64/ucall.c
@@ -0,0 +1,56 @@
+// 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;
+}