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