Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.4 115 lines 2.4 kB view raw
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}