xref: /linux/tools/testing/selftests/kvm/lib/ucall_common.c (revision 1c07425e902cd3137961c3d45b4271bf8a9b8eb9)
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include "kvm_util.h"
3 #include "linux/types.h"
4 #include "linux/bitmap.h"
5 #include "linux/atomic.h"
6 
7 #define GUEST_UCALL_FAILED -1
8 
9 struct ucall_header {
10 	DECLARE_BITMAP(in_use, KVM_MAX_VCPUS);
11 	struct ucall ucalls[KVM_MAX_VCPUS];
12 };
13 
14 /*
15  * ucall_pool holds per-VM values (global data is duplicated by each VM), it
16  * must not be accessed from host code.
17  */
18 static struct ucall_header *ucall_pool;
19 
20 void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa)
21 {
22 	struct ucall_header *hdr;
23 	struct ucall *uc;
24 	vm_vaddr_t vaddr;
25 	int i;
26 
27 	vaddr = __vm_vaddr_alloc(vm, sizeof(*hdr), KVM_UTIL_MIN_VADDR, MEM_REGION_DATA);
28 	hdr = (struct ucall_header *)addr_gva2hva(vm, vaddr);
29 	memset(hdr, 0, sizeof(*hdr));
30 
31 	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
32 		uc = &hdr->ucalls[i];
33 		uc->hva = uc;
34 	}
35 
36 	write_guest_global(vm, ucall_pool, (struct ucall_header *)vaddr);
37 
38 	ucall_arch_init(vm, mmio_gpa);
39 }
40 
41 static struct ucall *ucall_alloc(void)
42 {
43 	struct ucall *uc;
44 	int i;
45 
46 	if (!ucall_pool)
47 		goto ucall_failed;
48 
49 	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
50 		if (!test_and_set_bit(i, ucall_pool->in_use)) {
51 			uc = &ucall_pool->ucalls[i];
52 			memset(uc->args, 0, sizeof(uc->args));
53 			return uc;
54 		}
55 	}
56 
57 ucall_failed:
58 	/*
59 	 * If the vCPU cannot grab a ucall structure, make a bare ucall with a
60 	 * magic value to signal to get_ucall() that things went sideways.
61 	 * GUEST_ASSERT() depends on ucall_alloc() and so cannot be used here.
62 	 */
63 	ucall_arch_do_ucall(GUEST_UCALL_FAILED);
64 	return NULL;
65 }
66 
67 static void ucall_free(struct ucall *uc)
68 {
69 	/* Beware, here be pointer arithmetic.  */
70 	clear_bit(uc - ucall_pool->ucalls, ucall_pool->in_use);
71 }
72 
73 void ucall(uint64_t cmd, int nargs, ...)
74 {
75 	struct ucall *uc;
76 	va_list va;
77 	int i;
78 
79 	uc = ucall_alloc();
80 
81 	WRITE_ONCE(uc->cmd, cmd);
82 
83 	nargs = min(nargs, UCALL_MAX_ARGS);
84 
85 	va_start(va, nargs);
86 	for (i = 0; i < nargs; ++i)
87 		WRITE_ONCE(uc->args[i], va_arg(va, uint64_t));
88 	va_end(va);
89 
90 	ucall_arch_do_ucall((vm_vaddr_t)uc->hva);
91 
92 	ucall_free(uc);
93 }
94 
95 uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
96 {
97 	struct ucall ucall;
98 	void *addr;
99 
100 	if (!uc)
101 		uc = &ucall;
102 
103 	addr = ucall_arch_get_ucall(vcpu);
104 	if (addr) {
105 		TEST_ASSERT(addr != (void *)GUEST_UCALL_FAILED,
106 			    "Guest failed to allocate ucall struct");
107 
108 		memcpy(uc, addr, sizeof(*uc));
109 		vcpu_run_complete_io(vcpu);
110 	} else {
111 		memset(uc, 0, sizeof(*uc));
112 	}
113 
114 	return uc->cmd;
115 }
116