Loading...
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
9struct ucall_header {
10 DECLARE_BITMAP(in_use, KVM_MAX_VCPUS);
11 struct ucall ucalls[KVM_MAX_VCPUS];
12};
13
14int ucall_nr_pages_required(uint64_t page_size)
15{
16 return align_up(sizeof(struct ucall_header), page_size) / page_size;
17}
18
19/*
20 * ucall_pool holds per-VM values (global data is duplicated by each VM), it
21 * must not be accessed from host code.
22 */
23static struct ucall_header *ucall_pool;
24
25void ucall_init(struct kvm_vm *vm, vm_paddr_t mmio_gpa)
26{
27 struct ucall_header *hdr;
28 struct ucall *uc;
29 vm_vaddr_t vaddr;
30 int i;
31
32 vaddr = vm_vaddr_alloc_shared(vm, sizeof(*hdr), KVM_UTIL_MIN_VADDR,
33 MEM_REGION_DATA);
34 hdr = (struct ucall_header *)addr_gva2hva(vm, vaddr);
35 memset(hdr, 0, sizeof(*hdr));
36
37 for (i = 0; i < KVM_MAX_VCPUS; ++i) {
38 uc = &hdr->ucalls[i];
39 uc->hva = uc;
40 }
41
42 write_guest_global(vm, ucall_pool, (struct ucall_header *)vaddr);
43
44 ucall_arch_init(vm, mmio_gpa);
45}
46
47static struct ucall *ucall_alloc(void)
48{
49 struct ucall *uc;
50 int i;
51
52 if (!ucall_pool)
53 goto ucall_failed;
54
55 for (i = 0; i < KVM_MAX_VCPUS; ++i) {
56 if (!test_and_set_bit(i, ucall_pool->in_use)) {
57 uc = &ucall_pool->ucalls[i];
58 memset(uc->args, 0, sizeof(uc->args));
59 return uc;
60 }
61 }
62
63ucall_failed:
64 /*
65 * If the vCPU cannot grab a ucall structure, make a bare ucall with a
66 * magic value to signal to get_ucall() that things went sideways.
67 * GUEST_ASSERT() depends on ucall_alloc() and so cannot be used here.
68 */
69 ucall_arch_do_ucall(GUEST_UCALL_FAILED);
70 return NULL;
71}
72
73static void ucall_free(struct ucall *uc)
74{
75 /* Beware, here be pointer arithmetic. */
76 clear_bit(uc - ucall_pool->ucalls, ucall_pool->in_use);
77}
78
79void ucall_assert(uint64_t cmd, const char *exp, const char *file,
80 unsigned int line, const char *fmt, ...)
81{
82 struct ucall *uc;
83 va_list va;
84
85 uc = ucall_alloc();
86 uc->cmd = cmd;
87
88 WRITE_ONCE(uc->args[GUEST_ERROR_STRING], (uint64_t)(exp));
89 WRITE_ONCE(uc->args[GUEST_FILE], (uint64_t)(file));
90 WRITE_ONCE(uc->args[GUEST_LINE], line);
91
92 va_start(va, fmt);
93 guest_vsnprintf(uc->buffer, UCALL_BUFFER_LEN, fmt, va);
94 va_end(va);
95
96 ucall_arch_do_ucall((vm_vaddr_t)uc->hva);
97
98 ucall_free(uc);
99}
100
101void ucall_fmt(uint64_t cmd, const char *fmt, ...)
102{
103 struct ucall *uc;
104 va_list va;
105
106 uc = ucall_alloc();
107 uc->cmd = cmd;
108
109 va_start(va, fmt);
110 guest_vsnprintf(uc->buffer, UCALL_BUFFER_LEN, fmt, va);
111 va_end(va);
112
113 ucall_arch_do_ucall((vm_vaddr_t)uc->hva);
114
115 ucall_free(uc);
116}
117
118void ucall(uint64_t cmd, int nargs, ...)
119{
120 struct ucall *uc;
121 va_list va;
122 int i;
123
124 uc = ucall_alloc();
125
126 WRITE_ONCE(uc->cmd, cmd);
127
128 nargs = min(nargs, UCALL_MAX_ARGS);
129
130 va_start(va, nargs);
131 for (i = 0; i < nargs; ++i)
132 WRITE_ONCE(uc->args[i], va_arg(va, uint64_t));
133 va_end(va);
134
135 ucall_arch_do_ucall((vm_vaddr_t)uc->hva);
136
137 ucall_free(uc);
138}
139
140uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
141{
142 struct ucall ucall;
143 void *addr;
144
145 if (!uc)
146 uc = &ucall;
147
148 addr = ucall_arch_get_ucall(vcpu);
149 if (addr) {
150 TEST_ASSERT(addr != (void *)GUEST_UCALL_FAILED,
151 "Guest failed to allocate ucall struct");
152
153 memcpy(uc, addr, sizeof(*uc));
154 vcpu_run_complete_io(vcpu);
155 } else {
156 memset(uc, 0, sizeof(*uc));
157 }
158
159 return uc->cmd;
160}