Merge tag 'for-linus-20191012' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / tools / testing / selftests / kvm / lib / x86_64 / ucall.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * ucall support. A ucall is a "hypercall to userspace".
4  *
5  * Copyright (C) 2018, Red Hat, Inc.
6  */
7 #include "kvm_util.h"
8
9 #define UCALL_PIO_PORT ((uint16_t)0x1000)
10
11 void ucall_init(struct kvm_vm *vm, void *arg)
12 {
13 }
14
15 void ucall_uninit(struct kvm_vm *vm)
16 {
17 }
18
19 void ucall(uint64_t cmd, int nargs, ...)
20 {
21         struct ucall uc = {
22                 .cmd = cmd,
23         };
24         va_list va;
25         int i;
26
27         nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS;
28
29         va_start(va, nargs);
30         for (i = 0; i < nargs; ++i)
31                 uc.args[i] = va_arg(va, uint64_t);
32         va_end(va);
33
34         asm volatile("in %[port], %%al"
35                 : : [port] "d" (UCALL_PIO_PORT), "D" (&uc) : "rax", "memory");
36 }
37
38 uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc)
39 {
40         struct kvm_run *run = vcpu_state(vm, vcpu_id);
41         struct ucall ucall = {};
42
43         if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
44                 struct kvm_regs regs;
45
46                 vcpu_regs_get(vm, vcpu_id, &regs);
47                 memcpy(&ucall, addr_gva2hva(vm, (vm_vaddr_t)regs.rdi),
48                        sizeof(ucall));
49
50                 vcpu_run_complete_io(vm, vcpu_id);
51                 if (uc)
52                         memcpy(uc, &ucall, sizeof(ucall));
53         }
54
55         return ucall.cmd;
56 }