~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/kvm/lib/ucall_common.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 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 
 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 
 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 
 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 
 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 
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 
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 
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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php