]> granicus.if.org Git - strace/blob - kvm.c
bfin, csky, m68k, sh: fix build regression
[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  * Copyright (c) 2017-2019 The strace developers.
7  * All rights reserved.
8  *
9  * SPDX-License-Identifier: LGPL-2.1-or-later
10  */
11
12 #include "defs.h"
13
14 #ifdef HAVE_LINUX_KVM_H
15 # include <linux/kvm.h>
16 # include "print_fields.h"
17 # include "arch_kvm.c"
18 # include "xmalloc.h"
19 # include "mmap_cache.h"
20
21 struct vcpu_info {
22         struct vcpu_info *next;
23         int fd;
24         int cpuid;
25         long mmap_addr;
26         unsigned long mmap_len;
27         bool resolved;
28 };
29
30 static bool dump_kvm_run_structure;
31
32 static struct vcpu_info *
33 vcpu_find(struct tcb *const tcp, int fd)
34 {
35         for (struct vcpu_info *vcpu_info = tcp->vcpu_info_list;
36              vcpu_info;
37              vcpu_info = vcpu_info->next)
38                 if (vcpu_info->fd == fd)
39                         return vcpu_info;
40
41         return NULL;
42 }
43
44 static struct vcpu_info *
45 vcpu_alloc(struct tcb *const tcp, int fd, int cpuid)
46 {
47         struct vcpu_info *vcpu_info = xzalloc(sizeof(*vcpu_info));
48
49         vcpu_info->fd = fd;
50         vcpu_info->cpuid = cpuid;
51
52         vcpu_info->next = tcp->vcpu_info_list;
53         tcp->vcpu_info_list = vcpu_info;
54
55         return vcpu_info;
56 }
57
58 void
59 kvm_vcpu_info_free(struct tcb *tcp)
60 {
61         struct vcpu_info *head, *next;
62
63         for (head = tcp->vcpu_info_list; head; head = next) {
64                 next = head->next;
65                 free(head);
66         }
67
68         tcp->vcpu_info_list = NULL;
69 }
70
71 static void
72 vcpu_register(struct tcb *const tcp, int fd, int cpuid)
73 {
74         if (fd < 0)
75                 return;
76
77         struct vcpu_info *vcpu_info = vcpu_find(tcp, fd);
78
79         if (!vcpu_info) {
80                 vcpu_alloc(tcp, fd, cpuid);
81         } else if (vcpu_info->cpuid != cpuid) {
82                 vcpu_info->cpuid = cpuid;
83                 vcpu_info->resolved = false;
84         }
85 }
86
87 static bool
88 is_map_for_file(struct mmap_cache_entry_t *map_info, void *data)
89 {
90         /* major version for anon inode may be given in get_anon_bdev()
91          * in linux kernel.
92          *
93          *      *p = MKDEV(0, dev & MINORMASK);
94          *-----------------^
95          */
96         return map_info->binary_filename &&
97                 map_info->major == 0 &&
98                 strcmp(map_info->binary_filename, data) == 0;
99 }
100
101 static unsigned long
102 map_len(struct mmap_cache_entry_t *map_info)
103 {
104         return map_info->start_addr < map_info->end_addr
105                 ? map_info->end_addr - map_info->start_addr
106                 : 0;
107 }
108
109 # define VCPU_DENTRY_PREFIX "anon_inode:kvm-vcpu:"
110
111 static struct vcpu_info*
112 vcpu_get_info(struct tcb *const tcp, int fd)
113 {
114         struct vcpu_info *vcpu_info = vcpu_find(tcp, fd);
115         struct mmap_cache_entry_t *map_info;
116         const char *cpuid_str;
117
118         enum mmap_cache_rebuild_result mc_stat =
119                 mmap_cache_rebuild_if_invalid(tcp, __func__);
120         if (mc_stat == MMAP_CACHE_REBUILD_NOCACHE)
121                 return NULL;
122
123         if (vcpu_info && vcpu_info->resolved) {
124                 if (mc_stat == MMAP_CACHE_REBUILD_READY)
125                         return vcpu_info;
126                 else {
127                         map_info = mmap_cache_search(tcp, vcpu_info->mmap_addr);
128                         if (map_info) {
129                                 cpuid_str =
130                                         STR_STRIP_PREFIX(map_info->binary_filename,
131                                                          VCPU_DENTRY_PREFIX);
132                                 if (cpuid_str != map_info->binary_filename) {
133                                         int cpuid = string_to_uint(cpuid_str);
134                                         if (cpuid < 0)
135                                                 return NULL;
136                                         if (vcpu_info->cpuid == cpuid)
137                                                 return vcpu_info;
138                                 }
139                         }
140
141                         /* The vcpu vma may be mremap'ed. */
142                         vcpu_info->resolved = false;
143                 }
144         }
145
146         /* Slow path: !vcpu_info || !vcpu_info->resolved */
147         char path[PATH_MAX + 1];
148         cpuid_str = path;
149         if (getfdpath(tcp, fd, path, sizeof(path)) >= 0)
150                 cpuid_str = STR_STRIP_PREFIX(path, VCPU_DENTRY_PREFIX);
151         if (cpuid_str == path)
152                 map_info = NULL;
153         else
154                 map_info = mmap_cache_search_custom(tcp, is_map_for_file, path);
155
156         if (map_info) {
157                 int cpuid = string_to_uint(cpuid_str);
158                 if (cpuid < 0)
159                         return NULL;
160                 if (!vcpu_info)
161                         vcpu_info = vcpu_alloc(tcp, fd, cpuid);
162                 else if (vcpu_info->cpuid != cpuid)
163                         vcpu_info->cpuid = cpuid;
164                 vcpu_info->mmap_addr = map_info->start_addr;
165                 vcpu_info->mmap_len  = map_len(map_info);
166                 vcpu_info->resolved  = true;
167                 return vcpu_info;
168         }
169
170         return NULL;
171 }
172
173 static int
174 kvm_ioctl_create_vcpu(struct tcb *const tcp, const kernel_ulong_t arg)
175 {
176         uint32_t cpuid = arg;
177
178         if (entering(tcp)) {
179                 tprintf(", %u", cpuid);
180                 if (dump_kvm_run_structure)
181                         return 0;
182         } else if (!syserror(tcp)) {
183                 vcpu_register(tcp, tcp->u_rval, cpuid);
184         }
185
186         return RVAL_IOCTL_DECODED | RVAL_FD;
187 }
188
189 # ifdef HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION
190 #  include "xlat/kvm_mem_flags.h"
191 static int
192 kvm_ioctl_set_user_memory_region(struct tcb *const tcp, const kernel_ulong_t arg)
193 {
194         struct kvm_userspace_memory_region u_memory_region;
195
196         tprints(", ");
197         if (umove_or_printaddr(tcp, arg, &u_memory_region))
198                 return RVAL_IOCTL_DECODED;
199
200         PRINT_FIELD_U("{", u_memory_region, slot);
201         PRINT_FIELD_FLAGS(", ", u_memory_region, flags, kvm_mem_flags,
202                           "KVM_MEM_???");
203         PRINT_FIELD_X(", ", u_memory_region, guest_phys_addr);
204         PRINT_FIELD_U(", ", u_memory_region, memory_size);
205         PRINT_FIELD_X(", ", u_memory_region, userspace_addr);
206         tprints("}");
207
208         return RVAL_IOCTL_DECODED;
209 }
210 # endif /* HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION */
211
212 # ifdef HAVE_STRUCT_KVM_REGS
213 static int
214 kvm_ioctl_decode_regs(struct tcb *const tcp, const unsigned int code,
215                       const kernel_ulong_t arg)
216 {
217         struct kvm_regs regs;
218
219         if (code == KVM_GET_REGS && entering(tcp))
220                 return 0;
221
222         tprints(", ");
223         if (!umove_or_printaddr(tcp, arg, &regs))
224                 arch_print_kvm_regs(tcp, arg, &regs);
225
226         return RVAL_IOCTL_DECODED;
227 }
228 # endif /* HAVE_STRUCT_KVM_REGS */
229
230 # ifdef HAVE_STRUCT_KVM_CPUID2
231 #  include "xlat/kvm_cpuid_flags.h"
232 static bool
233 print_kvm_cpuid_entry(struct tcb *const tcp,
234                       void* elem_buf, size_t elem_size, void* data)
235 {
236         const struct kvm_cpuid_entry2 *entry = elem_buf;
237         PRINT_FIELD_X("{", *entry, function);
238         PRINT_FIELD_X(", ", *entry, index);
239         PRINT_FIELD_FLAGS(", ", *entry, flags, kvm_cpuid_flags,
240                           "KVM_CPUID_FLAG_???");
241         PRINT_FIELD_X(", ", *entry, eax);
242         PRINT_FIELD_X(", ", *entry, ebx);
243         PRINT_FIELD_X(", ", *entry, ecx);
244         PRINT_FIELD_X(", ", *entry, edx);
245         tprints("}");
246
247         return true;
248 }
249
250 static int
251 kvm_ioctl_decode_cpuid2(struct tcb *const tcp, const unsigned int code,
252                         const kernel_ulong_t arg)
253 {
254         struct kvm_cpuid2 cpuid;
255
256         if (entering(tcp) && (code == KVM_GET_SUPPORTED_CPUID
257 #  ifdef KVM_GET_EMULATED_CPUID
258                               || code == KVM_GET_EMULATED_CPUID
259 #  endif
260                              ))
261                 return 0;
262
263         tprints(", ");
264         if (!umove_or_printaddr(tcp, arg, &cpuid)) {
265                 PRINT_FIELD_U("{", cpuid, nent);
266
267                 tprints(", entries=");
268                 if (abbrev(tcp)) {
269                         tprints("[");
270                         if (cpuid.nent)
271                                 tprints("...");
272                         tprints("]");
273
274                 } else {
275                         struct kvm_cpuid_entry2 entry;
276                         print_array(tcp, arg + sizeof(cpuid), cpuid.nent,
277                                     &entry, sizeof(entry), tfetch_mem,
278                                     print_kvm_cpuid_entry, NULL);
279                 }
280                 tprints("}");
281         }
282
283         return RVAL_IOCTL_DECODED;
284 }
285 # endif /* HAVE_STRUCT_KVM_CPUID2 */
286
287 # ifdef HAVE_STRUCT_KVM_SREGS
288 static int
289 kvm_ioctl_decode_sregs(struct tcb *const tcp, const unsigned int code,
290                        const kernel_ulong_t arg)
291 {
292         struct kvm_sregs sregs;
293
294         if (code == KVM_GET_SREGS && entering(tcp))
295                 return 0;
296
297         tprints(", ");
298         if (!umove_or_printaddr(tcp, arg, &sregs))
299                 arch_print_kvm_sregs(tcp, arg, &sregs);
300
301         return RVAL_IOCTL_DECODED;
302 }
303 # endif /* HAVE_STRUCT_KVM_SREGS */
304
305 # include "xlat/kvm_cap.h"
306 static int
307 kvm_ioctl_decode_check_extension(struct tcb *const tcp, const unsigned int code,
308                                  const kernel_ulong_t arg)
309 {
310         tprints(", ");
311         printxval64(kvm_cap, arg, "KVM_CAP_???");
312         return RVAL_IOCTL_DECODED;
313 }
314
315 # include "xlat/kvm_exit_reason.h"
316 static void
317 kvm_ioctl_run_attach_auxstr(struct tcb *const tcp,
318                             struct vcpu_info *info)
319
320 {
321         static struct kvm_run vcpu_run_struct;
322
323         if (info->mmap_len < sizeof(vcpu_run_struct))
324                 return;
325
326         if (umove(tcp, info->mmap_addr, &vcpu_run_struct) < 0)
327                 return;
328
329         tcp->auxstr = xlookup(kvm_exit_reason, vcpu_run_struct.exit_reason);
330         if (!tcp->auxstr)
331                 tcp->auxstr = "KVM_EXIT_???";
332 }
333
334 static int
335 kvm_ioctl_decode_run(struct tcb *const tcp)
336 {
337
338         if (entering(tcp))
339                 return 0;
340
341         int r = RVAL_DECODED;
342
343         if (syserror(tcp))
344                 return r;
345
346         if (dump_kvm_run_structure) {
347                 tcp->auxstr = NULL;
348                 int fd = tcp->u_arg[0];
349                 struct vcpu_info *info = vcpu_get_info(tcp, fd);
350
351                 if (info) {
352                         kvm_ioctl_run_attach_auxstr(tcp, info);
353                         if (tcp->auxstr)
354                                 r |= RVAL_STR;
355                 }
356         }
357
358         return r;
359 }
360
361 int
362 kvm_ioctl(struct tcb *const tcp, const unsigned int code, const kernel_ulong_t arg)
363 {
364         switch (code) {
365         case KVM_CREATE_VCPU:
366                 return kvm_ioctl_create_vcpu(tcp, arg);
367
368 # ifdef HAVE_STRUCT_KVM_USERSPACE_MEMORY_REGION
369         case KVM_SET_USER_MEMORY_REGION:
370                 return kvm_ioctl_set_user_memory_region(tcp, arg);
371 # endif
372
373 # ifdef HAVE_STRUCT_KVM_REGS
374         case KVM_SET_REGS:
375         case KVM_GET_REGS:
376                 return kvm_ioctl_decode_regs(tcp, code, arg);
377 # endif
378
379 # ifdef HAVE_STRUCT_KVM_SREGS
380         case KVM_SET_SREGS:
381         case KVM_GET_SREGS:
382                 return kvm_ioctl_decode_sregs(tcp, code, arg);
383 # endif
384
385 # ifdef HAVE_STRUCT_KVM_CPUID2
386        case KVM_SET_CPUID2:
387        case KVM_GET_SUPPORTED_CPUID:
388 #  ifdef KVM_GET_EMULATED_CPUID
389        case KVM_GET_EMULATED_CPUID:
390 #  endif
391                return kvm_ioctl_decode_cpuid2(tcp, code, arg);
392 # endif
393
394         case KVM_CHECK_EXTENSION:
395                 return kvm_ioctl_decode_check_extension(tcp, code, arg);
396
397         case KVM_CREATE_VM:
398                 return RVAL_DECODED | RVAL_FD;
399
400         case KVM_RUN:
401                 return kvm_ioctl_decode_run(tcp);
402
403         case KVM_GET_VCPU_MMAP_SIZE:
404         case KVM_GET_API_VERSION:
405         default:
406                 return RVAL_DECODED;
407         }
408 }
409
410 void
411 kvm_run_structure_decoder_init(void)
412 {
413         dump_kvm_run_structure = true;
414         mmap_cache_enable();
415 }
416
417 #endif /* HAVE_LINUX_KVM_H */