Linux Audio

Check our new training course

Loading...
v6.2
  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
 
 
 
 
 
 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 */
 18static struct ucall_header *ucall_pool;
 19
 20void 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
 41static 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
 57ucall_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
 67static 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
 73void 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
 95uint64_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}
v6.13.7
  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
 12struct ucall_header {
 13	DECLARE_BITMAP(in_use, KVM_MAX_VCPUS);
 14	struct ucall ucalls[KVM_MAX_VCPUS];
 15};
 16
 17int 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 */
 26static struct ucall_header *ucall_pool;
 27
 28void 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
 50static 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
 66ucall_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
 76static 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
 82void 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
104void 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
121void 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
143uint64_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}