]> granicus.if.org Git - strace/blob - kvm.c
Update ioctl entries from linux v4.18
[strace] / kvm.c
1 /*
2  * Support for decoding of KVM_* ioctl commands.
3  *
4  * Copyright (c) 2017 Masatake YAMATO <yamato@redhat.com>
5  * Copyright (c) 2017 Red Hat, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "defs.h"
32
33 #ifdef HAVE_LINUX_KVM_H
34 # include <linux/kvm.h>
35 # include "print_fields.h"
36 # include "arch_kvm.c"
37 # include "xmalloc.h"
38 # include "mmap_cache.h"
39
40 struct vcpu_info {
41         struct vcpu_info *next;
42         int fd;
43         int cpuid;
44         long mmap_addr;
45         unsigned long mmap_len;
46         bool resolved;
47 };
48
49 static bool dump_kvm_run_structure;
50
51 static struct vcpu_info *
52 vcpu_find(struct tcb *const tcp, int fd)
53 {
54         for (struct vcpu_info *vcpu_info = tcp->vcpu_info_list;
55              vcpu_info;
56              vcpu_info = vcpu_info->next)
57                 if (vcpu_info->fd == fd)
58                         return vcpu_info;
59
60         return NULL;
61 }
62
63 static struct vcpu_info *
64 vcpu_alloc(struct tcb *const tcp, int fd, int cpuid)
65 {
66         struct vcpu_info *vcpu_info = xcalloc(1, sizeof(*vcpu_info));
67
68         vcpu_info->fd = fd;
69         vcpu_info->cpuid = cpuid;
70
71         vcpu_info->next = tcp->vcpu_info_list;
72         tcp->vcpu_info_list = vcpu_info;
73
74         return vcpu_info;
75 }
76
77 void
78 kvm_vcpu_info_free(struct tcb *tcp)
79 {
80         struct vcpu_info *head, *next;
81
82         for (head = tcp->vcpu_info_list; head; head = next) {
83                 next = head->next;
84                 free(head);
85         }
86
87         tcp->vcpu_info_list = NULL;
88 }
89
90 static void
91 vcpu_register(struct tcb *const tcp, int fd, int cpuid)
92 {
93         if (fd < 0)
94                 return;
95
96         struct vcpu_info *vcpu_info = vcpu_find(tcp, fd);
97
98         if (!vcpu_info)
99                 vcpu_info = vcpu_alloc(tcp, fd, cpuid);
100         else if (vcpu_info->cpuid != cpuid)
101         {
102                 vcpu_info->cpuid = cpuid;
103                 vcpu_info->resolved = false;
104         }
105 }
106
107 static bool
108 is_map_for_file(struct mmap_cache_entry_t *map_info, void *data)
109 {
110         /* major version for anon inode may be given in get_anon_bdev()
111          * in linux kernel.
112          *
113          *      *p = MKDEV(0, dev & MINORMASK);
114          *-----------------^
115          */
116         return map_info->binary_filename &&
117                 map_info->major == 0 &&
118                 strcmp(map_info->binary_filename, data) == 0;
119 }
120
121 static unsigned long
122 map_len(struct mmap_cache_entry_t *map_info)
123 {
124         return map_info->start_addr < map_info->end_addr
125                 ? map_info->end_addr - map_info->start_addr
126                 : 0;
127 }
128
129 #define VCPU_DENTRY_PREFIX "anon_inode:kvm-vcpu:"
130
131 static struct vcpu_info*
132 vcpu_get_info(struct tcb *const tcp, int fd)
133 {
134         struct vcpu_info *vcpu_info = vcpu_find(tcp, fd);
135         struct mmap_cache_entry_t *map_info;
136         const char *cpuid_str;
137
138         enum mmap_cache_rebuild_result mc_stat =
139                 mmap_cache_rebuild_if_invalid(tcp, __func__);
140         if (mc_stat == MMAP_CACHE_REBUILD_NOCACHE)
141                 return NULL;
142
143         if (vcpu_info && vcpu_info->resolved) {
144                 if (mc_stat == MMAP_CACHE_REBUILD_READY)
145                         return vcpu_info;
146                 else {
147                         map_info = mmap_cache_search(tcp, vcpu_info->mmap_addr);
148                         if (map_info) {
149                                 cpuid_str =
150                                         STR_STRIP_PREFIX(map_info->binary_filename,
151                                                          VCPU_DENTRY_PREFIX);
152                                 if (cpuid_str != map_info->binary_filename) {
153                                         int cpuid = string_to_uint(cpuid_str);
154                                         if (cpuid < 0)
155                                                 return NULL;
156                                         if (vcpu_info->cpuid == cpuid)
157                                                 return vcpu_info;
158                                 }
159                         }
160
161                         /* The vcpu vma may be mremap'ed. */
162                         vcpu_info->resolved = false;
163                 }
164         }
165
166         /* Slow path: !vcpu_info || !vcpu_info->resolved */
167         char path[PATH_MAX + 1];
168         cpuid_str = path;
169         if (getfdpath(tcp, fd, path, sizeof(path)) >= 0)
170                 cpuid_str = STR_STRIP_PREFIX(path, VCPU_DENTRY_PREFIX);
171         if (cpuid_str == path)
172                 map_info = NULL;
173         else
174                 map_info = mmap_cache_search_custom(tcp, is_map_for_file, path);
175
176         if (map_info) {
177                 int cpuid = string_to_uint(cpuid_str);
178                 if (cpuid < 0)
179                         return NULL;
180                 if (!vcpu_info)
181                         vcpu_info = vcpu_alloc(tcp, fd, cpuid);
182                 else if (vcpu_info->cpuid != cpuid)
183                         vcpu_info->cpuid = cpuid;
184                 vcpu_info->mmap_addr = map_info->start_addr;
185                 vcpu_info->mmap_len  = map_len(map_info);
186                 vcpu_info->resolved  = true;
187                 return vcpu_info;
188         }
189
190         return NULL;
191 }
192
193 static int
194 kvm_ioctl_create_vcpu(struct tcb *const tcp, const kernel_ulong_t arg)
195 {
196         uint32_t cpuid = arg;
197
198         if (entering(tcp)) {
199                 tprintf(", %u", cpuid);
200                 if (dump_kvm_run_structure)
201                         return 0;
202         } else if (!syserror(tcp)) {
203                 vcpu_register(tcp, tcp->u_rval, cpuid);
204         }
205
206         return RVAL_IOCTL_DECODED | RVAL_FD;
207 }
208
209 # ifdef HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION
210 #  include "xlat/kvm_mem_flags.h"
211 static int
212 kvm_ioctl_set_user_memory_region(struct tcb *const tcp, const kernel_ulong_t arg)
213 {
214         struct kvm_userspace_memory_region u_memory_region;
215
216         tprints(", ");
217         if (umove_or_printaddr(tcp, arg, &u_memory_region))
218                 return RVAL_IOCTL_DECODED;
219
220         PRINT_FIELD_U("{", u_memory_region, slot);
221         PRINT_FIELD_FLAGS(", ", u_memory_region, flags, kvm_mem_flags,
222                           "KVM_MEM_???");
223         PRINT_FIELD_X(", ", u_memory_region, guest_phys_addr);
224         PRINT_FIELD_U(", ", u_memory_region, memory_size);
225         PRINT_FIELD_X(", ", u_memory_region, userspace_addr);
226         tprints("}");
227
228         return RVAL_IOCTL_DECODED;
229 }
230 # endif /* HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION */
231
232 # ifdef HAVE_STRUCT_KVM_REGS
233 static int
234 kvm_ioctl_decode_regs(struct tcb *const tcp, const unsigned int code,
235                       const kernel_ulong_t arg)
236 {
237         struct kvm_regs regs;
238
239         if (code == KVM_GET_REGS && entering(tcp))
240                 return 0;
241
242         tprints(", ");
243         if (!umove_or_printaddr(tcp, arg, &regs))
244                 arch_print_kvm_regs(tcp, arg, &regs);
245
246         return RVAL_IOCTL_DECODED;
247 }
248 # endif /* HAVE_STRUCT_KVM_REGS */
249
250 # ifdef HAVE_STRUCT_KVM_CPUID2
251 #  include "xlat/kvm_cpuid_flags.h"
252 static bool
253 print_kvm_cpuid_entry(struct tcb *const tcp,
254                       void* elem_buf, size_t elem_size, void* data)
255 {
256         const struct kvm_cpuid_entry2 *entry = elem_buf;
257         PRINT_FIELD_X("{", *entry, function);
258         PRINT_FIELD_X(", ", *entry, index);
259         PRINT_FIELD_FLAGS(", ", *entry, flags, kvm_cpuid_flags,
260                           "KVM_CPUID_FLAG_???");
261         PRINT_FIELD_X(", ", *entry, eax);
262         PRINT_FIELD_X(", ", *entry, ebx);
263         PRINT_FIELD_X(", ", *entry, ecx);
264         PRINT_FIELD_X(", ", *entry, edx);
265         tprints("}");
266
267         return true;
268 }
269
270 static int
271 kvm_ioctl_decode_cpuid2(struct tcb *const tcp, const unsigned int code,
272                         const kernel_ulong_t arg)
273 {
274         struct kvm_cpuid2 cpuid;
275
276         if (entering(tcp) && (code == KVM_GET_SUPPORTED_CPUID
277 #  ifdef KVM_GET_EMULATED_CPUID
278                               || code == KVM_GET_EMULATED_CPUID
279 #  endif
280                              ))
281                 return 0;
282
283         tprints(", ");
284         if (!umove_or_printaddr(tcp, arg, &cpuid)) {
285                 PRINT_FIELD_U("{", cpuid, nent);
286
287                 tprints(", entries=");
288                 if (abbrev(tcp)) {
289                         tprints("[");
290                         if (cpuid.nent)
291                                 tprints("...");
292                         tprints("]");
293
294                 } else {
295                         struct kvm_cpuid_entry2 entry;
296                         print_array(tcp, arg + sizeof(cpuid), cpuid.nent,
297                                     &entry, sizeof(entry), tfetch_mem,
298                                     print_kvm_cpuid_entry, NULL);
299                 }
300                 tprints("}");
301         }
302
303         return RVAL_IOCTL_DECODED;
304 }
305 # endif /* HAVE_STRUCT_KVM_CPUID2 */
306
307 # ifdef HAVE_STRUCT_KVM_SREGS
308 static int
309 kvm_ioctl_decode_sregs(struct tcb *const tcp, const unsigned int code,
310                        const kernel_ulong_t arg)
311 {
312         struct kvm_sregs sregs;
313
314         if (code == KVM_GET_SREGS && entering(tcp))
315                 return 0;
316
317         tprints(", ");
318         if (!umove_or_printaddr(tcp, arg, &sregs))
319                 arch_print_kvm_sregs(tcp, arg, &sregs);
320
321         return RVAL_IOCTL_DECODED;
322 }
323 # endif /* HAVE_STRUCT_KVM_SREGS */
324
325 # include "xlat/kvm_exit_reason.h"
326 static void
327 kvm_ioctl_run_attach_auxstr(struct tcb *const tcp,
328                             struct vcpu_info *info)
329
330 {
331         static struct kvm_run vcpu_run_struct;
332
333         if (info->mmap_len < sizeof(vcpu_run_struct))
334                 return;
335
336         if (umove(tcp, info->mmap_addr, &vcpu_run_struct) < 0)
337                 return;
338
339         tcp->auxstr = xlat_idx(kvm_exit_reason, ARRAY_SIZE(kvm_exit_reason) - 1,
340                                vcpu_run_struct.exit_reason);
341         if (!tcp->auxstr)
342                 tcp->auxstr = "KVM_EXIT_???";
343 }
344
345 static int
346 kvm_ioctl_decode_run(struct tcb *const tcp)
347 {
348
349         if (entering(tcp))
350                 return 0;
351
352         int r = RVAL_DECODED;
353
354         if (syserror(tcp))
355                 return r;
356
357         if (dump_kvm_run_structure) {
358                 tcp->auxstr = NULL;
359                 int fd = tcp->u_arg[0];
360                 struct vcpu_info *info = vcpu_get_info(tcp, fd);
361
362                 if (info) {
363                         kvm_ioctl_run_attach_auxstr(tcp, info);
364                         if (tcp->auxstr)
365                                 r |= RVAL_STR;
366                 }
367         }
368
369         return r;
370 }
371
372 int
373 kvm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
374 {
375         switch (code) {
376         case KVM_CREATE_VCPU:
377                 return kvm_ioctl_create_vcpu(tcp, arg);
378
379 # ifdef HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION
380         case KVM_SET_USER_MEMORY_REGION:
381                 return kvm_ioctl_set_user_memory_region(tcp, arg);
382 # endif
383
384 # ifdef HAVE_STRUCT_KVM_REGS
385         case KVM_SET_REGS:
386         case KVM_GET_REGS:
387                 return kvm_ioctl_decode_regs(tcp, code, arg);
388 # endif
389
390 # ifdef HAVE_STRUCT_KVM_SREGS
391         case KVM_SET_SREGS:
392         case KVM_GET_SREGS:
393                 return kvm_ioctl_decode_sregs(tcp, code, arg);
394 # endif
395
396 # ifdef HAVE_STRUCT_KVM_CPUID2
397        case KVM_SET_CPUID2:
398        case KVM_GET_SUPPORTED_CPUID:
399 #  ifdef KVM_GET_EMULATED_CPUID
400        case KVM_GET_EMULATED_CPUID:
401 #  endif
402                return kvm_ioctl_decode_cpuid2(tcp, code, arg);
403 # endif
404
405         case KVM_CREATE_VM:
406                 return RVAL_DECODED | RVAL_FD;
407
408         case KVM_RUN:
409                 return kvm_ioctl_decode_run(tcp);
410
411         case KVM_GET_VCPU_MMAP_SIZE:
412         case KVM_GET_API_VERSION:
413         default:
414                 return RVAL_DECODED;
415         }
416 }
417
418 void
419 kvm_run_structure_decoder_init(void)
420 {
421         dump_kvm_run_structure = true;
422         mmap_cache_enable();
423 }
424
425 #endif /* HAVE_LINUX_KVM_H */