diff options
Diffstat (limited to 'tools/testing/selftests/kvm/lib/kvm_util.c')
-rw-r--r-- | tools/testing/selftests/kvm/lib/kvm_util.c | 1480 |
1 files changed, 1480 insertions, 0 deletions
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c new file mode 100644 index 000000000000..7ca1bb40c498 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/kvm_util.c | |||
@@ -0,0 +1,1480 @@ | |||
1 | /* | ||
2 | * tools/testing/selftests/kvm/lib/kvm_util.c | ||
3 | * | ||
4 | * Copyright (C) 2018, Google LLC. | ||
5 | * | ||
6 | * This work is licensed under the terms of the GNU GPL, version 2. | ||
7 | */ | ||
8 | |||
9 | #include "test_util.h" | ||
10 | #include "kvm_util.h" | ||
11 | #include "kvm_util_internal.h" | ||
12 | |||
13 | #include <assert.h> | ||
14 | #include <sys/mman.h> | ||
15 | #include <sys/types.h> | ||
16 | #include <sys/stat.h> | ||
17 | |||
18 | #define KVM_DEV_PATH "/dev/kvm" | ||
19 | |||
20 | #define KVM_UTIL_PGS_PER_HUGEPG 512 | ||
21 | #define KVM_UTIL_MIN_PADDR 0x2000 | ||
22 | |||
23 | /* Aligns x up to the next multiple of size. Size must be a power of 2. */ | ||
24 | static void *align(void *x, size_t size) | ||
25 | { | ||
26 | size_t mask = size - 1; | ||
27 | TEST_ASSERT(size != 0 && !(size & (size - 1)), | ||
28 | "size not a power of 2: %lu", size); | ||
29 | return (void *) (((size_t) x + mask) & ~mask); | ||
30 | } | ||
31 | |||
32 | /* Capability | ||
33 | * | ||
34 | * Input Args: | ||
35 | * cap - Capability | ||
36 | * | ||
37 | * Output Args: None | ||
38 | * | ||
39 | * Return: | ||
40 | * On success, the Value corresponding to the capability (KVM_CAP_*) | ||
41 | * specified by the value of cap. On failure a TEST_ASSERT failure | ||
42 | * is produced. | ||
43 | * | ||
44 | * Looks up and returns the value corresponding to the capability | ||
45 | * (KVM_CAP_*) given by cap. | ||
46 | */ | ||
47 | int kvm_check_cap(long cap) | ||
48 | { | ||
49 | int ret; | ||
50 | int kvm_fd; | ||
51 | |||
52 | kvm_fd = open(KVM_DEV_PATH, O_RDONLY); | ||
53 | TEST_ASSERT(kvm_fd >= 0, "open %s failed, rc: %i errno: %i", | ||
54 | KVM_DEV_PATH, kvm_fd, errno); | ||
55 | |||
56 | ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, cap); | ||
57 | TEST_ASSERT(ret != -1, "KVM_CHECK_EXTENSION IOCTL failed,\n" | ||
58 | " rc: %i errno: %i", ret, errno); | ||
59 | |||
60 | close(kvm_fd); | ||
61 | |||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | /* VM Create | ||
66 | * | ||
67 | * Input Args: | ||
68 | * mode - VM Mode (e.g. VM_MODE_FLAT48PG) | ||
69 | * phy_pages - Physical memory pages | ||
70 | * perm - permission | ||
71 | * | ||
72 | * Output Args: None | ||
73 | * | ||
74 | * Return: | ||
75 | * Pointer to opaque structure that describes the created VM. | ||
76 | * | ||
77 | * Creates a VM with the mode specified by mode (e.g. VM_MODE_FLAT48PG). | ||
78 | * When phy_pages is non-zero, a memory region of phy_pages physical pages | ||
79 | * is created and mapped starting at guest physical address 0. The file | ||
80 | * descriptor to control the created VM is created with the permissions | ||
81 | * given by perm (e.g. O_RDWR). | ||
82 | */ | ||
83 | struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) | ||
84 | { | ||
85 | struct kvm_vm *vm; | ||
86 | int kvm_fd; | ||
87 | |||
88 | /* Allocate memory. */ | ||
89 | vm = calloc(1, sizeof(*vm)); | ||
90 | TEST_ASSERT(vm != NULL, "Insufficent Memory"); | ||
91 | |||
92 | vm->mode = mode; | ||
93 | kvm_fd = open(KVM_DEV_PATH, perm); | ||
94 | TEST_ASSERT(kvm_fd >= 0, "open %s failed, rc: %i errno: %i", | ||
95 | KVM_DEV_PATH, kvm_fd, errno); | ||
96 | |||
97 | /* Create VM. */ | ||
98 | vm->fd = ioctl(kvm_fd, KVM_CREATE_VM, NULL); | ||
99 | TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " | ||
100 | "rc: %i errno: %i", vm->fd, errno); | ||
101 | |||
102 | close(kvm_fd); | ||
103 | |||
104 | /* Setup mode specific traits. */ | ||
105 | switch (vm->mode) { | ||
106 | case VM_MODE_FLAT48PG: | ||
107 | vm->page_size = 0x1000; | ||
108 | vm->page_shift = 12; | ||
109 | |||
110 | /* Limit to 48-bit canonical virtual addresses. */ | ||
111 | vm->vpages_valid = sparsebit_alloc(); | ||
112 | sparsebit_set_num(vm->vpages_valid, | ||
113 | 0, (1ULL << (48 - 1)) >> vm->page_shift); | ||
114 | sparsebit_set_num(vm->vpages_valid, | ||
115 | (~((1ULL << (48 - 1)) - 1)) >> vm->page_shift, | ||
116 | (1ULL << (48 - 1)) >> vm->page_shift); | ||
117 | |||
118 | /* Limit physical addresses to 52-bits. */ | ||
119 | vm->max_gfn = ((1ULL << 52) >> vm->page_shift) - 1; | ||
120 | break; | ||
121 | |||
122 | default: | ||
123 | TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); | ||
124 | } | ||
125 | |||
126 | /* Allocate and setup memory for guest. */ | ||
127 | vm->vpages_mapped = sparsebit_alloc(); | ||
128 | if (phy_pages != 0) | ||
129 | vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, | ||
130 | 0, 0, phy_pages, 0); | ||
131 | |||
132 | return vm; | ||
133 | } | ||
134 | |||
135 | /* Userspace Memory Region Find | ||
136 | * | ||
137 | * Input Args: | ||
138 | * vm - Virtual Machine | ||
139 | * start - Starting VM physical address | ||
140 | * end - Ending VM physical address, inclusive. | ||
141 | * | ||
142 | * Output Args: None | ||
143 | * | ||
144 | * Return: | ||
145 | * Pointer to overlapping region, NULL if no such region. | ||
146 | * | ||
147 | * Searches for a region with any physical memory that overlaps with | ||
148 | * any portion of the guest physical addresses from start to end | ||
149 | * inclusive. If multiple overlapping regions exist, a pointer to any | ||
150 | * of the regions is returned. Null is returned only when no overlapping | ||
151 | * region exists. | ||
152 | */ | ||
153 | static struct userspace_mem_region *userspace_mem_region_find( | ||
154 | struct kvm_vm *vm, uint64_t start, uint64_t end) | ||
155 | { | ||
156 | struct userspace_mem_region *region; | ||
157 | |||
158 | for (region = vm->userspace_mem_region_head; region; | ||
159 | region = region->next) { | ||
160 | uint64_t existing_start = region->region.guest_phys_addr; | ||
161 | uint64_t existing_end = region->region.guest_phys_addr | ||
162 | + region->region.memory_size - 1; | ||
163 | if (start <= existing_end && end >= existing_start) | ||
164 | return region; | ||
165 | } | ||
166 | |||
167 | return NULL; | ||
168 | } | ||
169 | |||
170 | /* KVM Userspace Memory Region Find | ||
171 | * | ||
172 | * Input Args: | ||
173 | * vm - Virtual Machine | ||
174 | * start - Starting VM physical address | ||
175 | * end - Ending VM physical address, inclusive. | ||
176 | * | ||
177 | * Output Args: None | ||
178 | * | ||
179 | * Return: | ||
180 | * Pointer to overlapping region, NULL if no such region. | ||
181 | * | ||
182 | * Public interface to userspace_mem_region_find. Allows tests to look up | ||
183 | * the memslot datastructure for a given range of guest physical memory. | ||
184 | */ | ||
185 | struct kvm_userspace_memory_region * | ||
186 | kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, | ||
187 | uint64_t end) | ||
188 | { | ||
189 | struct userspace_mem_region *region; | ||
190 | |||
191 | region = userspace_mem_region_find(vm, start, end); | ||
192 | if (!region) | ||
193 | return NULL; | ||
194 | |||
195 | return ®ion->region; | ||
196 | } | ||
197 | |||
198 | /* VCPU Find | ||
199 | * | ||
200 | * Input Args: | ||
201 | * vm - Virtual Machine | ||
202 | * vcpuid - VCPU ID | ||
203 | * | ||
204 | * Output Args: None | ||
205 | * | ||
206 | * Return: | ||
207 | * Pointer to VCPU structure | ||
208 | * | ||
209 | * Locates a vcpu structure that describes the VCPU specified by vcpuid and | ||
210 | * returns a pointer to it. Returns NULL if the VM doesn't contain a VCPU | ||
211 | * for the specified vcpuid. | ||
212 | */ | ||
213 | struct vcpu *vcpu_find(struct kvm_vm *vm, | ||
214 | uint32_t vcpuid) | ||
215 | { | ||
216 | struct vcpu *vcpup; | ||
217 | |||
218 | for (vcpup = vm->vcpu_head; vcpup; vcpup = vcpup->next) { | ||
219 | if (vcpup->id == vcpuid) | ||
220 | return vcpup; | ||
221 | } | ||
222 | |||
223 | return NULL; | ||
224 | } | ||
225 | |||
226 | /* VM VCPU Remove | ||
227 | * | ||
228 | * Input Args: | ||
229 | * vm - Virtual Machine | ||
230 | * vcpuid - VCPU ID | ||
231 | * | ||
232 | * Output Args: None | ||
233 | * | ||
234 | * Return: None, TEST_ASSERT failures for all error conditions | ||
235 | * | ||
236 | * Within the VM specified by vm, removes the VCPU given by vcpuid. | ||
237 | */ | ||
238 | static void vm_vcpu_rm(struct kvm_vm *vm, uint32_t vcpuid) | ||
239 | { | ||
240 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
241 | |||
242 | int ret = close(vcpu->fd); | ||
243 | TEST_ASSERT(ret == 0, "Close of VCPU fd failed, rc: %i " | ||
244 | "errno: %i", ret, errno); | ||
245 | |||
246 | if (vcpu->next) | ||
247 | vcpu->next->prev = vcpu->prev; | ||
248 | if (vcpu->prev) | ||
249 | vcpu->prev->next = vcpu->next; | ||
250 | else | ||
251 | vm->vcpu_head = vcpu->next; | ||
252 | free(vcpu); | ||
253 | } | ||
254 | |||
255 | |||
256 | /* Destroys and frees the VM pointed to by vmp. | ||
257 | */ | ||
258 | void kvm_vm_free(struct kvm_vm *vmp) | ||
259 | { | ||
260 | int ret; | ||
261 | |||
262 | if (vmp == NULL) | ||
263 | return; | ||
264 | |||
265 | /* Free userspace_mem_regions. */ | ||
266 | while (vmp->userspace_mem_region_head) { | ||
267 | struct userspace_mem_region *region | ||
268 | = vmp->userspace_mem_region_head; | ||
269 | |||
270 | region->region.memory_size = 0; | ||
271 | ret = ioctl(vmp->fd, KVM_SET_USER_MEMORY_REGION, | ||
272 | ®ion->region); | ||
273 | TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed, " | ||
274 | "rc: %i errno: %i", ret, errno); | ||
275 | |||
276 | vmp->userspace_mem_region_head = region->next; | ||
277 | sparsebit_free(®ion->unused_phy_pages); | ||
278 | ret = munmap(region->mmap_start, region->mmap_size); | ||
279 | TEST_ASSERT(ret == 0, "munmap failed, rc: %i errno: %i", | ||
280 | ret, errno); | ||
281 | |||
282 | free(region); | ||
283 | } | ||
284 | |||
285 | /* Free VCPUs. */ | ||
286 | while (vmp->vcpu_head) | ||
287 | vm_vcpu_rm(vmp, vmp->vcpu_head->id); | ||
288 | |||
289 | /* Free sparsebit arrays. */ | ||
290 | sparsebit_free(&vmp->vpages_valid); | ||
291 | sparsebit_free(&vmp->vpages_mapped); | ||
292 | |||
293 | /* Close file descriptor for the VM. */ | ||
294 | ret = close(vmp->fd); | ||
295 | TEST_ASSERT(ret == 0, "Close of vm fd failed,\n" | ||
296 | " vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno); | ||
297 | |||
298 | /* Free the structure describing the VM. */ | ||
299 | free(vmp); | ||
300 | } | ||
301 | |||
302 | /* Memory Compare, host virtual to guest virtual | ||
303 | * | ||
304 | * Input Args: | ||
305 | * hva - Starting host virtual address | ||
306 | * vm - Virtual Machine | ||
307 | * gva - Starting guest virtual address | ||
308 | * len - number of bytes to compare | ||
309 | * | ||
310 | * Output Args: None | ||
311 | * | ||
312 | * Input/Output Args: None | ||
313 | * | ||
314 | * Return: | ||
315 | * Returns 0 if the bytes starting at hva for a length of len | ||
316 | * are equal the guest virtual bytes starting at gva. Returns | ||
317 | * a value < 0, if bytes at hva are less than those at gva. | ||
318 | * Otherwise a value > 0 is returned. | ||
319 | * | ||
320 | * Compares the bytes starting at the host virtual address hva, for | ||
321 | * a length of len, to the guest bytes starting at the guest virtual | ||
322 | * address given by gva. | ||
323 | */ | ||
324 | int kvm_memcmp_hva_gva(void *hva, | ||
325 | struct kvm_vm *vm, vm_vaddr_t gva, size_t len) | ||
326 | { | ||
327 | size_t amt; | ||
328 | |||
329 | /* Compare a batch of bytes until either a match is found | ||
330 | * or all the bytes have been compared. | ||
331 | */ | ||
332 | for (uintptr_t offset = 0; offset < len; offset += amt) { | ||
333 | uintptr_t ptr1 = (uintptr_t)hva + offset; | ||
334 | |||
335 | /* Determine host address for guest virtual address | ||
336 | * at offset. | ||
337 | */ | ||
338 | uintptr_t ptr2 = (uintptr_t)addr_gva2hva(vm, gva + offset); | ||
339 | |||
340 | /* Determine amount to compare on this pass. | ||
341 | * Don't allow the comparsion to cross a page boundary. | ||
342 | */ | ||
343 | amt = len - offset; | ||
344 | if ((ptr1 >> vm->page_shift) != ((ptr1 + amt) >> vm->page_shift)) | ||
345 | amt = vm->page_size - (ptr1 % vm->page_size); | ||
346 | if ((ptr2 >> vm->page_shift) != ((ptr2 + amt) >> vm->page_shift)) | ||
347 | amt = vm->page_size - (ptr2 % vm->page_size); | ||
348 | |||
349 | assert((ptr1 >> vm->page_shift) == ((ptr1 + amt - 1) >> vm->page_shift)); | ||
350 | assert((ptr2 >> vm->page_shift) == ((ptr2 + amt - 1) >> vm->page_shift)); | ||
351 | |||
352 | /* Perform the comparison. If there is a difference | ||
353 | * return that result to the caller, otherwise need | ||
354 | * to continue on looking for a mismatch. | ||
355 | */ | ||
356 | int ret = memcmp((void *)ptr1, (void *)ptr2, amt); | ||
357 | if (ret != 0) | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | /* No mismatch found. Let the caller know the two memory | ||
362 | * areas are equal. | ||
363 | */ | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | /* Allocate an instance of struct kvm_cpuid2 | ||
368 | * | ||
369 | * Input Args: None | ||
370 | * | ||
371 | * Output Args: None | ||
372 | * | ||
373 | * Return: A pointer to the allocated struct. The caller is responsible | ||
374 | * for freeing this struct. | ||
375 | * | ||
376 | * Since kvm_cpuid2 uses a 0-length array to allow a the size of the | ||
377 | * array to be decided at allocation time, allocation is slightly | ||
378 | * complicated. This function uses a reasonable default length for | ||
379 | * the array and performs the appropriate allocation. | ||
380 | */ | ||
381 | struct kvm_cpuid2 *allocate_kvm_cpuid2(void) | ||
382 | { | ||
383 | struct kvm_cpuid2 *cpuid; | ||
384 | int nent = 100; | ||
385 | size_t size; | ||
386 | |||
387 | size = sizeof(*cpuid); | ||
388 | size += nent * sizeof(struct kvm_cpuid_entry2); | ||
389 | cpuid = malloc(size); | ||
390 | if (!cpuid) { | ||
391 | perror("malloc"); | ||
392 | abort(); | ||
393 | } | ||
394 | |||
395 | cpuid->nent = nent; | ||
396 | |||
397 | return cpuid; | ||
398 | } | ||
399 | |||
400 | /* KVM Supported CPUID Get | ||
401 | * | ||
402 | * Input Args: None | ||
403 | * | ||
404 | * Output Args: | ||
405 | * cpuid - The supported KVM CPUID | ||
406 | * | ||
407 | * Return: void | ||
408 | * | ||
409 | * Get the guest CPUID supported by KVM. | ||
410 | */ | ||
411 | void kvm_get_supported_cpuid(struct kvm_cpuid2 *cpuid) | ||
412 | { | ||
413 | int ret; | ||
414 | int kvm_fd; | ||
415 | |||
416 | kvm_fd = open(KVM_DEV_PATH, O_RDONLY); | ||
417 | TEST_ASSERT(kvm_fd >= 0, "open %s failed, rc: %i errno: %i", | ||
418 | KVM_DEV_PATH, kvm_fd, errno); | ||
419 | |||
420 | ret = ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); | ||
421 | TEST_ASSERT(ret == 0, "KVM_GET_SUPPORTED_CPUID failed %d %d\n", | ||
422 | ret, errno); | ||
423 | |||
424 | close(kvm_fd); | ||
425 | } | ||
426 | |||
427 | /* Locate a cpuid entry. | ||
428 | * | ||
429 | * Input Args: | ||
430 | * cpuid: The cpuid. | ||
431 | * function: The function of the cpuid entry to find. | ||
432 | * | ||
433 | * Output Args: None | ||
434 | * | ||
435 | * Return: A pointer to the cpuid entry. Never returns NULL. | ||
436 | */ | ||
437 | struct kvm_cpuid_entry2 * | ||
438 | find_cpuid_index_entry(struct kvm_cpuid2 *cpuid, uint32_t function, | ||
439 | uint32_t index) | ||
440 | { | ||
441 | struct kvm_cpuid_entry2 *entry = NULL; | ||
442 | int i; | ||
443 | |||
444 | for (i = 0; i < cpuid->nent; i++) { | ||
445 | if (cpuid->entries[i].function == function && | ||
446 | cpuid->entries[i].index == index) { | ||
447 | entry = &cpuid->entries[i]; | ||
448 | break; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | TEST_ASSERT(entry, "Guest CPUID entry not found: (EAX=%x, ECX=%x).", | ||
453 | function, index); | ||
454 | return entry; | ||
455 | } | ||
456 | |||
457 | /* VM Userspace Memory Region Add | ||
458 | * | ||
459 | * Input Args: | ||
460 | * vm - Virtual Machine | ||
461 | * backing_src - Storage source for this region. | ||
462 | * NULL to use anonymous memory. | ||
463 | * guest_paddr - Starting guest physical address | ||
464 | * slot - KVM region slot | ||
465 | * npages - Number of physical pages | ||
466 | * flags - KVM memory region flags (e.g. KVM_MEM_LOG_DIRTY_PAGES) | ||
467 | * | ||
468 | * Output Args: None | ||
469 | * | ||
470 | * Return: None | ||
471 | * | ||
472 | * Allocates a memory area of the number of pages specified by npages | ||
473 | * and maps it to the VM specified by vm, at a starting physical address | ||
474 | * given by guest_paddr. The region is created with a KVM region slot | ||
475 | * given by slot, which must be unique and < KVM_MEM_SLOTS_NUM. The | ||
476 | * region is created with the flags given by flags. | ||
477 | */ | ||
478 | void vm_userspace_mem_region_add(struct kvm_vm *vm, | ||
479 | enum vm_mem_backing_src_type src_type, | ||
480 | uint64_t guest_paddr, uint32_t slot, uint64_t npages, | ||
481 | uint32_t flags) | ||
482 | { | ||
483 | int ret; | ||
484 | unsigned long pmem_size = 0; | ||
485 | struct userspace_mem_region *region; | ||
486 | size_t huge_page_size = KVM_UTIL_PGS_PER_HUGEPG * vm->page_size; | ||
487 | |||
488 | TEST_ASSERT((guest_paddr % vm->page_size) == 0, "Guest physical " | ||
489 | "address not on a page boundary.\n" | ||
490 | " guest_paddr: 0x%lx vm->page_size: 0x%x", | ||
491 | guest_paddr, vm->page_size); | ||
492 | TEST_ASSERT((((guest_paddr >> vm->page_shift) + npages) - 1) | ||
493 | <= vm->max_gfn, "Physical range beyond maximum " | ||
494 | "supported physical address,\n" | ||
495 | " guest_paddr: 0x%lx npages: 0x%lx\n" | ||
496 | " vm->max_gfn: 0x%lx vm->page_size: 0x%x", | ||
497 | guest_paddr, npages, vm->max_gfn, vm->page_size); | ||
498 | |||
499 | /* Confirm a mem region with an overlapping address doesn't | ||
500 | * already exist. | ||
501 | */ | ||
502 | region = (struct userspace_mem_region *) userspace_mem_region_find( | ||
503 | vm, guest_paddr, guest_paddr + npages * vm->page_size); | ||
504 | if (region != NULL) | ||
505 | TEST_ASSERT(false, "overlapping userspace_mem_region already " | ||
506 | "exists\n" | ||
507 | " requested guest_paddr: 0x%lx npages: 0x%lx " | ||
508 | "page_size: 0x%x\n" | ||
509 | " existing guest_paddr: 0x%lx size: 0x%lx", | ||
510 | guest_paddr, npages, vm->page_size, | ||
511 | (uint64_t) region->region.guest_phys_addr, | ||
512 | (uint64_t) region->region.memory_size); | ||
513 | |||
514 | /* Confirm no region with the requested slot already exists. */ | ||
515 | for (region = vm->userspace_mem_region_head; region; | ||
516 | region = region->next) { | ||
517 | if (region->region.slot == slot) | ||
518 | break; | ||
519 | if ((guest_paddr <= (region->region.guest_phys_addr | ||
520 | + region->region.memory_size)) | ||
521 | && ((guest_paddr + npages * vm->page_size) | ||
522 | >= region->region.guest_phys_addr)) | ||
523 | break; | ||
524 | } | ||
525 | if (region != NULL) | ||
526 | TEST_ASSERT(false, "A mem region with the requested slot " | ||
527 | "or overlapping physical memory range already exists.\n" | ||
528 | " requested slot: %u paddr: 0x%lx npages: 0x%lx\n" | ||
529 | " existing slot: %u paddr: 0x%lx size: 0x%lx", | ||
530 | slot, guest_paddr, npages, | ||
531 | region->region.slot, | ||
532 | (uint64_t) region->region.guest_phys_addr, | ||
533 | (uint64_t) region->region.memory_size); | ||
534 | |||
535 | /* Allocate and initialize new mem region structure. */ | ||
536 | region = calloc(1, sizeof(*region)); | ||
537 | TEST_ASSERT(region != NULL, "Insufficient Memory"); | ||
538 | region->mmap_size = npages * vm->page_size; | ||
539 | |||
540 | /* Enough memory to align up to a huge page. */ | ||
541 | if (src_type == VM_MEM_SRC_ANONYMOUS_THP) | ||
542 | region->mmap_size += huge_page_size; | ||
543 | region->mmap_start = mmap(NULL, region->mmap_size, | ||
544 | PROT_READ | PROT_WRITE, | ||
545 | MAP_PRIVATE | MAP_ANONYMOUS | ||
546 | | (src_type == VM_MEM_SRC_ANONYMOUS_HUGETLB ? MAP_HUGETLB : 0), | ||
547 | -1, 0); | ||
548 | TEST_ASSERT(region->mmap_start != MAP_FAILED, | ||
549 | "test_malloc failed, mmap_start: %p errno: %i", | ||
550 | region->mmap_start, errno); | ||
551 | |||
552 | /* Align THP allocation up to start of a huge page. */ | ||
553 | region->host_mem = align(region->mmap_start, | ||
554 | src_type == VM_MEM_SRC_ANONYMOUS_THP ? huge_page_size : 1); | ||
555 | |||
556 | /* As needed perform madvise */ | ||
557 | if (src_type == VM_MEM_SRC_ANONYMOUS || src_type == VM_MEM_SRC_ANONYMOUS_THP) { | ||
558 | ret = madvise(region->host_mem, npages * vm->page_size, | ||
559 | src_type == VM_MEM_SRC_ANONYMOUS ? MADV_NOHUGEPAGE : MADV_HUGEPAGE); | ||
560 | TEST_ASSERT(ret == 0, "madvise failed,\n" | ||
561 | " addr: %p\n" | ||
562 | " length: 0x%lx\n" | ||
563 | " src_type: %x", | ||
564 | region->host_mem, npages * vm->page_size, src_type); | ||
565 | } | ||
566 | |||
567 | region->unused_phy_pages = sparsebit_alloc(); | ||
568 | sparsebit_set_num(region->unused_phy_pages, | ||
569 | guest_paddr >> vm->page_shift, npages); | ||
570 | region->region.slot = slot; | ||
571 | region->region.flags = flags; | ||
572 | region->region.guest_phys_addr = guest_paddr; | ||
573 | region->region.memory_size = npages * vm->page_size; | ||
574 | region->region.userspace_addr = (uintptr_t) region->host_mem; | ||
575 | ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); | ||
576 | TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" | ||
577 | " rc: %i errno: %i\n" | ||
578 | " slot: %u flags: 0x%x\n" | ||
579 | " guest_phys_addr: 0x%lx size: 0x%lx", | ||
580 | ret, errno, slot, flags, | ||
581 | guest_paddr, (uint64_t) region->region.memory_size); | ||
582 | |||
583 | /* Add to linked-list of memory regions. */ | ||
584 | if (vm->userspace_mem_region_head) | ||
585 | vm->userspace_mem_region_head->prev = region; | ||
586 | region->next = vm->userspace_mem_region_head; | ||
587 | vm->userspace_mem_region_head = region; | ||
588 | } | ||
589 | |||
590 | /* Memslot to region | ||
591 | * | ||
592 | * Input Args: | ||
593 | * vm - Virtual Machine | ||
594 | * memslot - KVM memory slot ID | ||
595 | * | ||
596 | * Output Args: None | ||
597 | * | ||
598 | * Return: | ||
599 | * Pointer to memory region structure that describe memory region | ||
600 | * using kvm memory slot ID given by memslot. TEST_ASSERT failure | ||
601 | * on error (e.g. currently no memory region using memslot as a KVM | ||
602 | * memory slot ID). | ||
603 | */ | ||
604 | static struct userspace_mem_region *memslot2region(struct kvm_vm *vm, | ||
605 | uint32_t memslot) | ||
606 | { | ||
607 | struct userspace_mem_region *region; | ||
608 | |||
609 | for (region = vm->userspace_mem_region_head; region; | ||
610 | region = region->next) { | ||
611 | if (region->region.slot == memslot) | ||
612 | break; | ||
613 | } | ||
614 | if (region == NULL) { | ||
615 | fprintf(stderr, "No mem region with the requested slot found,\n" | ||
616 | " requested slot: %u\n", memslot); | ||
617 | fputs("---- vm dump ----\n", stderr); | ||
618 | vm_dump(stderr, vm, 2); | ||
619 | TEST_ASSERT(false, "Mem region not found"); | ||
620 | } | ||
621 | |||
622 | return region; | ||
623 | } | ||
624 | |||
625 | /* VM Memory Region Flags Set | ||
626 | * | ||
627 | * Input Args: | ||
628 | * vm - Virtual Machine | ||
629 | * flags - Starting guest physical address | ||
630 | * | ||
631 | * Output Args: None | ||
632 | * | ||
633 | * Return: None | ||
634 | * | ||
635 | * Sets the flags of the memory region specified by the value of slot, | ||
636 | * to the values given by flags. | ||
637 | */ | ||
638 | void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) | ||
639 | { | ||
640 | int ret; | ||
641 | struct userspace_mem_region *region; | ||
642 | |||
643 | /* Locate memory region. */ | ||
644 | region = memslot2region(vm, slot); | ||
645 | |||
646 | region->region.flags = flags; | ||
647 | |||
648 | ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); | ||
649 | |||
650 | TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" | ||
651 | " rc: %i errno: %i slot: %u flags: 0x%x", | ||
652 | ret, errno, slot, flags); | ||
653 | } | ||
654 | |||
655 | /* VCPU mmap Size | ||
656 | * | ||
657 | * Input Args: None | ||
658 | * | ||
659 | * Output Args: None | ||
660 | * | ||
661 | * Return: | ||
662 | * Size of VCPU state | ||
663 | * | ||
664 | * Returns the size of the structure pointed to by the return value | ||
665 | * of vcpu_state(). | ||
666 | */ | ||
667 | static int vcpu_mmap_sz(void) | ||
668 | { | ||
669 | int dev_fd, ret; | ||
670 | |||
671 | dev_fd = open(KVM_DEV_PATH, O_RDONLY); | ||
672 | TEST_ASSERT(dev_fd >= 0, "%s open %s failed, rc: %i errno: %i", | ||
673 | __func__, KVM_DEV_PATH, dev_fd, errno); | ||
674 | |||
675 | ret = ioctl(dev_fd, KVM_GET_VCPU_MMAP_SIZE, NULL); | ||
676 | TEST_ASSERT(ret >= sizeof(struct kvm_run), | ||
677 | "%s KVM_GET_VCPU_MMAP_SIZE ioctl failed, rc: %i errno: %i", | ||
678 | __func__, ret, errno); | ||
679 | |||
680 | close(dev_fd); | ||
681 | |||
682 | return ret; | ||
683 | } | ||
684 | |||
685 | /* VM VCPU Add | ||
686 | * | ||
687 | * Input Args: | ||
688 | * vm - Virtual Machine | ||
689 | * vcpuid - VCPU ID | ||
690 | * | ||
691 | * Output Args: None | ||
692 | * | ||
693 | * Return: None | ||
694 | * | ||
695 | * Creates and adds to the VM specified by vm and virtual CPU with | ||
696 | * the ID given by vcpuid. | ||
697 | */ | ||
698 | void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) | ||
699 | { | ||
700 | struct vcpu *vcpu; | ||
701 | |||
702 | /* Confirm a vcpu with the specified id doesn't already exist. */ | ||
703 | vcpu = vcpu_find(vm, vcpuid); | ||
704 | if (vcpu != NULL) | ||
705 | TEST_ASSERT(false, "vcpu with the specified id " | ||
706 | "already exists,\n" | ||
707 | " requested vcpuid: %u\n" | ||
708 | " existing vcpuid: %u state: %p", | ||
709 | vcpuid, vcpu->id, vcpu->state); | ||
710 | |||
711 | /* Allocate and initialize new vcpu structure. */ | ||
712 | vcpu = calloc(1, sizeof(*vcpu)); | ||
713 | TEST_ASSERT(vcpu != NULL, "Insufficient Memory"); | ||
714 | vcpu->id = vcpuid; | ||
715 | vcpu->fd = ioctl(vm->fd, KVM_CREATE_VCPU, vcpuid); | ||
716 | TEST_ASSERT(vcpu->fd >= 0, "KVM_CREATE_VCPU failed, rc: %i errno: %i", | ||
717 | vcpu->fd, errno); | ||
718 | |||
719 | TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->state), "vcpu mmap size " | ||
720 | "smaller than expected, vcpu_mmap_sz: %i expected_min: %zi", | ||
721 | vcpu_mmap_sz(), sizeof(*vcpu->state)); | ||
722 | vcpu->state = (struct kvm_run *) mmap(NULL, sizeof(*vcpu->state), | ||
723 | PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, 0); | ||
724 | TEST_ASSERT(vcpu->state != MAP_FAILED, "mmap vcpu_state failed, " | ||
725 | "vcpu id: %u errno: %i", vcpuid, errno); | ||
726 | |||
727 | /* Add to linked-list of VCPUs. */ | ||
728 | if (vm->vcpu_head) | ||
729 | vm->vcpu_head->prev = vcpu; | ||
730 | vcpu->next = vm->vcpu_head; | ||
731 | vm->vcpu_head = vcpu; | ||
732 | |||
733 | vcpu_setup(vm, vcpuid); | ||
734 | } | ||
735 | |||
736 | /* VM Virtual Address Unused Gap | ||
737 | * | ||
738 | * Input Args: | ||
739 | * vm - Virtual Machine | ||
740 | * sz - Size (bytes) | ||
741 | * vaddr_min - Minimum Virtual Address | ||
742 | * | ||
743 | * Output Args: None | ||
744 | * | ||
745 | * Return: | ||
746 | * Lowest virtual address at or below vaddr_min, with at least | ||
747 | * sz unused bytes. TEST_ASSERT failure if no area of at least | ||
748 | * size sz is available. | ||
749 | * | ||
750 | * Within the VM specified by vm, locates the lowest starting virtual | ||
751 | * address >= vaddr_min, that has at least sz unallocated bytes. A | ||
752 | * TEST_ASSERT failure occurs for invalid input or no area of at least | ||
753 | * sz unallocated bytes >= vaddr_min is available. | ||
754 | */ | ||
755 | static vm_vaddr_t vm_vaddr_unused_gap(struct kvm_vm *vm, size_t sz, | ||
756 | vm_vaddr_t vaddr_min) | ||
757 | { | ||
758 | uint64_t pages = (sz + vm->page_size - 1) >> vm->page_shift; | ||
759 | |||
760 | /* Determine lowest permitted virtual page index. */ | ||
761 | uint64_t pgidx_start = (vaddr_min + vm->page_size - 1) >> vm->page_shift; | ||
762 | if ((pgidx_start * vm->page_size) < vaddr_min) | ||
763 | goto no_va_found; | ||
764 | |||
765 | /* Loop over section with enough valid virtual page indexes. */ | ||
766 | if (!sparsebit_is_set_num(vm->vpages_valid, | ||
767 | pgidx_start, pages)) | ||
768 | pgidx_start = sparsebit_next_set_num(vm->vpages_valid, | ||
769 | pgidx_start, pages); | ||
770 | do { | ||
771 | /* | ||
772 | * Are there enough unused virtual pages available at | ||
773 | * the currently proposed starting virtual page index. | ||
774 | * If not, adjust proposed starting index to next | ||
775 | * possible. | ||
776 | */ | ||
777 | if (sparsebit_is_clear_num(vm->vpages_mapped, | ||
778 | pgidx_start, pages)) | ||
779 | goto va_found; | ||
780 | pgidx_start = sparsebit_next_clear_num(vm->vpages_mapped, | ||
781 | pgidx_start, pages); | ||
782 | if (pgidx_start == 0) | ||
783 | goto no_va_found; | ||
784 | |||
785 | /* | ||
786 | * If needed, adjust proposed starting virtual address, | ||
787 | * to next range of valid virtual addresses. | ||
788 | */ | ||
789 | if (!sparsebit_is_set_num(vm->vpages_valid, | ||
790 | pgidx_start, pages)) { | ||
791 | pgidx_start = sparsebit_next_set_num( | ||
792 | vm->vpages_valid, pgidx_start, pages); | ||
793 | if (pgidx_start == 0) | ||
794 | goto no_va_found; | ||
795 | } | ||
796 | } while (pgidx_start != 0); | ||
797 | |||
798 | no_va_found: | ||
799 | TEST_ASSERT(false, "No vaddr of specified pages available, " | ||
800 | "pages: 0x%lx", pages); | ||
801 | |||
802 | /* NOT REACHED */ | ||
803 | return -1; | ||
804 | |||
805 | va_found: | ||
806 | TEST_ASSERT(sparsebit_is_set_num(vm->vpages_valid, | ||
807 | pgidx_start, pages), | ||
808 | "Unexpected, invalid virtual page index range,\n" | ||
809 | " pgidx_start: 0x%lx\n" | ||
810 | " pages: 0x%lx", | ||
811 | pgidx_start, pages); | ||
812 | TEST_ASSERT(sparsebit_is_clear_num(vm->vpages_mapped, | ||
813 | pgidx_start, pages), | ||
814 | "Unexpected, pages already mapped,\n" | ||
815 | " pgidx_start: 0x%lx\n" | ||
816 | " pages: 0x%lx", | ||
817 | pgidx_start, pages); | ||
818 | |||
819 | return pgidx_start * vm->page_size; | ||
820 | } | ||
821 | |||
822 | /* VM Virtual Address Allocate | ||
823 | * | ||
824 | * Input Args: | ||
825 | * vm - Virtual Machine | ||
826 | * sz - Size in bytes | ||
827 | * vaddr_min - Minimum starting virtual address | ||
828 | * data_memslot - Memory region slot for data pages | ||
829 | * pgd_memslot - Memory region slot for new virtual translation tables | ||
830 | * | ||
831 | * Output Args: None | ||
832 | * | ||
833 | * Return: | ||
834 | * Starting guest virtual address | ||
835 | * | ||
836 | * Allocates at least sz bytes within the virtual address space of the vm | ||
837 | * given by vm. The allocated bytes are mapped to a virtual address >= | ||
838 | * the address given by vaddr_min. Note that each allocation uses a | ||
839 | * a unique set of pages, with the minimum real allocation being at least | ||
840 | * a page. | ||
841 | */ | ||
842 | vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, | ||
843 | uint32_t data_memslot, uint32_t pgd_memslot) | ||
844 | { | ||
845 | uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0); | ||
846 | |||
847 | virt_pgd_alloc(vm, pgd_memslot); | ||
848 | |||
849 | /* Find an unused range of virtual page addresses of at least | ||
850 | * pages in length. | ||
851 | */ | ||
852 | vm_vaddr_t vaddr_start = vm_vaddr_unused_gap(vm, sz, vaddr_min); | ||
853 | |||
854 | /* Map the virtual pages. */ | ||
855 | for (vm_vaddr_t vaddr = vaddr_start; pages > 0; | ||
856 | pages--, vaddr += vm->page_size) { | ||
857 | vm_paddr_t paddr; | ||
858 | |||
859 | paddr = vm_phy_page_alloc(vm, KVM_UTIL_MIN_PADDR, data_memslot); | ||
860 | |||
861 | virt_pg_map(vm, vaddr, paddr, pgd_memslot); | ||
862 | |||
863 | sparsebit_set(vm->vpages_mapped, | ||
864 | vaddr >> vm->page_shift); | ||
865 | } | ||
866 | |||
867 | return vaddr_start; | ||
868 | } | ||
869 | |||
870 | /* Address VM Physical to Host Virtual | ||
871 | * | ||
872 | * Input Args: | ||
873 | * vm - Virtual Machine | ||
874 | * gpa - VM physical address | ||
875 | * | ||
876 | * Output Args: None | ||
877 | * | ||
878 | * Return: | ||
879 | * Equivalent host virtual address | ||
880 | * | ||
881 | * Locates the memory region containing the VM physical address given | ||
882 | * by gpa, within the VM given by vm. When found, the host virtual | ||
883 | * address providing the memory to the vm physical address is returned. | ||
884 | * A TEST_ASSERT failure occurs if no region containing gpa exists. | ||
885 | */ | ||
886 | void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa) | ||
887 | { | ||
888 | struct userspace_mem_region *region; | ||
889 | for (region = vm->userspace_mem_region_head; region; | ||
890 | region = region->next) { | ||
891 | if ((gpa >= region->region.guest_phys_addr) | ||
892 | && (gpa <= (region->region.guest_phys_addr | ||
893 | + region->region.memory_size - 1))) | ||
894 | return (void *) ((uintptr_t) region->host_mem | ||
895 | + (gpa - region->region.guest_phys_addr)); | ||
896 | } | ||
897 | |||
898 | TEST_ASSERT(false, "No vm physical memory at 0x%lx", gpa); | ||
899 | return NULL; | ||
900 | } | ||
901 | |||
902 | /* Address Host Virtual to VM Physical | ||
903 | * | ||
904 | * Input Args: | ||
905 | * vm - Virtual Machine | ||
906 | * hva - Host virtual address | ||
907 | * | ||
908 | * Output Args: None | ||
909 | * | ||
910 | * Return: | ||
911 | * Equivalent VM physical address | ||
912 | * | ||
913 | * Locates the memory region containing the host virtual address given | ||
914 | * by hva, within the VM given by vm. When found, the equivalent | ||
915 | * VM physical address is returned. A TEST_ASSERT failure occurs if no | ||
916 | * region containing hva exists. | ||
917 | */ | ||
918 | vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva) | ||
919 | { | ||
920 | struct userspace_mem_region *region; | ||
921 | for (region = vm->userspace_mem_region_head; region; | ||
922 | region = region->next) { | ||
923 | if ((hva >= region->host_mem) | ||
924 | && (hva <= (region->host_mem | ||
925 | + region->region.memory_size - 1))) | ||
926 | return (vm_paddr_t) ((uintptr_t) | ||
927 | region->region.guest_phys_addr | ||
928 | + (hva - (uintptr_t) region->host_mem)); | ||
929 | } | ||
930 | |||
931 | TEST_ASSERT(false, "No mapping to a guest physical address, " | ||
932 | "hva: %p", hva); | ||
933 | return -1; | ||
934 | } | ||
935 | |||
936 | /* VM Create IRQ Chip | ||
937 | * | ||
938 | * Input Args: | ||
939 | * vm - Virtual Machine | ||
940 | * | ||
941 | * Output Args: None | ||
942 | * | ||
943 | * Return: None | ||
944 | * | ||
945 | * Creates an interrupt controller chip for the VM specified by vm. | ||
946 | */ | ||
947 | void vm_create_irqchip(struct kvm_vm *vm) | ||
948 | { | ||
949 | int ret; | ||
950 | |||
951 | ret = ioctl(vm->fd, KVM_CREATE_IRQCHIP, 0); | ||
952 | TEST_ASSERT(ret == 0, "KVM_CREATE_IRQCHIP IOCTL failed, " | ||
953 | "rc: %i errno: %i", ret, errno); | ||
954 | } | ||
955 | |||
956 | /* VM VCPU State | ||
957 | * | ||
958 | * Input Args: | ||
959 | * vm - Virtual Machine | ||
960 | * vcpuid - VCPU ID | ||
961 | * | ||
962 | * Output Args: None | ||
963 | * | ||
964 | * Return: | ||
965 | * Pointer to structure that describes the state of the VCPU. | ||
966 | * | ||
967 | * Locates and returns a pointer to a structure that describes the | ||
968 | * state of the VCPU with the given vcpuid. | ||
969 | */ | ||
970 | struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) | ||
971 | { | ||
972 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
973 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
974 | |||
975 | return vcpu->state; | ||
976 | } | ||
977 | |||
978 | /* VM VCPU Run | ||
979 | * | ||
980 | * Input Args: | ||
981 | * vm - Virtual Machine | ||
982 | * vcpuid - VCPU ID | ||
983 | * | ||
984 | * Output Args: None | ||
985 | * | ||
986 | * Return: None | ||
987 | * | ||
988 | * Switch to executing the code for the VCPU given by vcpuid, within the VM | ||
989 | * given by vm. | ||
990 | */ | ||
991 | void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) | ||
992 | { | ||
993 | int ret = _vcpu_run(vm, vcpuid); | ||
994 | TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " | ||
995 | "rc: %i errno: %i", ret, errno); | ||
996 | } | ||
997 | |||
998 | int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) | ||
999 | { | ||
1000 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1001 | int rc; | ||
1002 | |||
1003 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1004 | do { | ||
1005 | rc = ioctl(vcpu->fd, KVM_RUN, NULL); | ||
1006 | } while (rc == -1 && errno == EINTR); | ||
1007 | return rc; | ||
1008 | } | ||
1009 | |||
1010 | /* VM VCPU Set MP State | ||
1011 | * | ||
1012 | * Input Args: | ||
1013 | * vm - Virtual Machine | ||
1014 | * vcpuid - VCPU ID | ||
1015 | * mp_state - mp_state to be set | ||
1016 | * | ||
1017 | * Output Args: None | ||
1018 | * | ||
1019 | * Return: None | ||
1020 | * | ||
1021 | * Sets the MP state of the VCPU given by vcpuid, to the state given | ||
1022 | * by mp_state. | ||
1023 | */ | ||
1024 | void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, | ||
1025 | struct kvm_mp_state *mp_state) | ||
1026 | { | ||
1027 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1028 | int ret; | ||
1029 | |||
1030 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1031 | |||
1032 | ret = ioctl(vcpu->fd, KVM_SET_MP_STATE, mp_state); | ||
1033 | TEST_ASSERT(ret == 0, "KVM_SET_MP_STATE IOCTL failed, " | ||
1034 | "rc: %i errno: %i", ret, errno); | ||
1035 | } | ||
1036 | |||
1037 | /* VM VCPU Regs Get | ||
1038 | * | ||
1039 | * Input Args: | ||
1040 | * vm - Virtual Machine | ||
1041 | * vcpuid - VCPU ID | ||
1042 | * | ||
1043 | * Output Args: | ||
1044 | * regs - current state of VCPU regs | ||
1045 | * | ||
1046 | * Return: None | ||
1047 | * | ||
1048 | * Obtains the current register state for the VCPU specified by vcpuid | ||
1049 | * and stores it at the location given by regs. | ||
1050 | */ | ||
1051 | void vcpu_regs_get(struct kvm_vm *vm, | ||
1052 | uint32_t vcpuid, struct kvm_regs *regs) | ||
1053 | { | ||
1054 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1055 | int ret; | ||
1056 | |||
1057 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1058 | |||
1059 | /* Get the regs. */ | ||
1060 | ret = ioctl(vcpu->fd, KVM_GET_REGS, regs); | ||
1061 | TEST_ASSERT(ret == 0, "KVM_GET_REGS failed, rc: %i errno: %i", | ||
1062 | ret, errno); | ||
1063 | } | ||
1064 | |||
1065 | /* VM VCPU Regs Set | ||
1066 | * | ||
1067 | * Input Args: | ||
1068 | * vm - Virtual Machine | ||
1069 | * vcpuid - VCPU ID | ||
1070 | * regs - Values to set VCPU regs to | ||
1071 | * | ||
1072 | * Output Args: None | ||
1073 | * | ||
1074 | * Return: None | ||
1075 | * | ||
1076 | * Sets the regs of the VCPU specified by vcpuid to the values | ||
1077 | * given by regs. | ||
1078 | */ | ||
1079 | void vcpu_regs_set(struct kvm_vm *vm, | ||
1080 | uint32_t vcpuid, struct kvm_regs *regs) | ||
1081 | { | ||
1082 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1083 | int ret; | ||
1084 | |||
1085 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1086 | |||
1087 | /* Set the regs. */ | ||
1088 | ret = ioctl(vcpu->fd, KVM_SET_REGS, regs); | ||
1089 | TEST_ASSERT(ret == 0, "KVM_SET_REGS failed, rc: %i errno: %i", | ||
1090 | ret, errno); | ||
1091 | } | ||
1092 | |||
1093 | void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, | ||
1094 | struct kvm_vcpu_events *events) | ||
1095 | { | ||
1096 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1097 | int ret; | ||
1098 | |||
1099 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1100 | |||
1101 | /* Get the regs. */ | ||
1102 | ret = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, events); | ||
1103 | TEST_ASSERT(ret == 0, "KVM_GET_VCPU_EVENTS, failed, rc: %i errno: %i", | ||
1104 | ret, errno); | ||
1105 | } | ||
1106 | |||
1107 | void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, | ||
1108 | struct kvm_vcpu_events *events) | ||
1109 | { | ||
1110 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1111 | int ret; | ||
1112 | |||
1113 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1114 | |||
1115 | /* Set the regs. */ | ||
1116 | ret = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, events); | ||
1117 | TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i", | ||
1118 | ret, errno); | ||
1119 | } | ||
1120 | |||
1121 | /* VM VCPU Args Set | ||
1122 | * | ||
1123 | * Input Args: | ||
1124 | * vm - Virtual Machine | ||
1125 | * vcpuid - VCPU ID | ||
1126 | * num - number of arguments | ||
1127 | * ... - arguments, each of type uint64_t | ||
1128 | * | ||
1129 | * Output Args: None | ||
1130 | * | ||
1131 | * Return: None | ||
1132 | * | ||
1133 | * Sets the first num function input arguments to the values | ||
1134 | * given as variable args. Each of the variable args is expected to | ||
1135 | * be of type uint64_t. | ||
1136 | */ | ||
1137 | void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) | ||
1138 | { | ||
1139 | va_list ap; | ||
1140 | struct kvm_regs regs; | ||
1141 | |||
1142 | TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n" | ||
1143 | " num: %u\n", | ||
1144 | num); | ||
1145 | |||
1146 | va_start(ap, num); | ||
1147 | vcpu_regs_get(vm, vcpuid, ®s); | ||
1148 | |||
1149 | if (num >= 1) | ||
1150 | regs.rdi = va_arg(ap, uint64_t); | ||
1151 | |||
1152 | if (num >= 2) | ||
1153 | regs.rsi = va_arg(ap, uint64_t); | ||
1154 | |||
1155 | if (num >= 3) | ||
1156 | regs.rdx = va_arg(ap, uint64_t); | ||
1157 | |||
1158 | if (num >= 4) | ||
1159 | regs.rcx = va_arg(ap, uint64_t); | ||
1160 | |||
1161 | if (num >= 5) | ||
1162 | regs.r8 = va_arg(ap, uint64_t); | ||
1163 | |||
1164 | if (num >= 6) | ||
1165 | regs.r9 = va_arg(ap, uint64_t); | ||
1166 | |||
1167 | vcpu_regs_set(vm, vcpuid, ®s); | ||
1168 | va_end(ap); | ||
1169 | } | ||
1170 | |||
1171 | /* VM VCPU System Regs Get | ||
1172 | * | ||
1173 | * Input Args: | ||
1174 | * vm - Virtual Machine | ||
1175 | * vcpuid - VCPU ID | ||
1176 | * | ||
1177 | * Output Args: | ||
1178 | * sregs - current state of VCPU system regs | ||
1179 | * | ||
1180 | * Return: None | ||
1181 | * | ||
1182 | * Obtains the current system register state for the VCPU specified by | ||
1183 | * vcpuid and stores it at the location given by sregs. | ||
1184 | */ | ||
1185 | void vcpu_sregs_get(struct kvm_vm *vm, | ||
1186 | uint32_t vcpuid, struct kvm_sregs *sregs) | ||
1187 | { | ||
1188 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1189 | int ret; | ||
1190 | |||
1191 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1192 | |||
1193 | /* Get the regs. */ | ||
1194 | /* Get the regs. */ | ||
1195 | ret = ioctl(vcpu->fd, KVM_GET_SREGS, sregs); | ||
1196 | TEST_ASSERT(ret == 0, "KVM_GET_SREGS failed, rc: %i errno: %i", | ||
1197 | ret, errno); | ||
1198 | } | ||
1199 | |||
1200 | /* VM VCPU System Regs Set | ||
1201 | * | ||
1202 | * Input Args: | ||
1203 | * vm - Virtual Machine | ||
1204 | * vcpuid - VCPU ID | ||
1205 | * sregs - Values to set VCPU system regs to | ||
1206 | * | ||
1207 | * Output Args: None | ||
1208 | * | ||
1209 | * Return: None | ||
1210 | * | ||
1211 | * Sets the system regs of the VCPU specified by vcpuid to the values | ||
1212 | * given by sregs. | ||
1213 | */ | ||
1214 | void vcpu_sregs_set(struct kvm_vm *vm, | ||
1215 | uint32_t vcpuid, struct kvm_sregs *sregs) | ||
1216 | { | ||
1217 | int ret = _vcpu_sregs_set(vm, vcpuid, sregs); | ||
1218 | TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " | ||
1219 | "rc: %i errno: %i", ret, errno); | ||
1220 | } | ||
1221 | |||
1222 | int _vcpu_sregs_set(struct kvm_vm *vm, | ||
1223 | uint32_t vcpuid, struct kvm_sregs *sregs) | ||
1224 | { | ||
1225 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1226 | int ret; | ||
1227 | |||
1228 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1229 | |||
1230 | /* Get the regs. */ | ||
1231 | return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); | ||
1232 | } | ||
1233 | |||
1234 | /* VCPU Ioctl | ||
1235 | * | ||
1236 | * Input Args: | ||
1237 | * vm - Virtual Machine | ||
1238 | * vcpuid - VCPU ID | ||
1239 | * cmd - Ioctl number | ||
1240 | * arg - Argument to pass to the ioctl | ||
1241 | * | ||
1242 | * Return: None | ||
1243 | * | ||
1244 | * Issues an arbitrary ioctl on a VCPU fd. | ||
1245 | */ | ||
1246 | void vcpu_ioctl(struct kvm_vm *vm, | ||
1247 | uint32_t vcpuid, unsigned long cmd, void *arg) | ||
1248 | { | ||
1249 | struct vcpu *vcpu = vcpu_find(vm, vcpuid); | ||
1250 | int ret; | ||
1251 | |||
1252 | TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); | ||
1253 | |||
1254 | ret = ioctl(vcpu->fd, cmd, arg); | ||
1255 | TEST_ASSERT(ret == 0, "vcpu ioctl %lu failed, rc: %i errno: %i (%s)", | ||
1256 | cmd, ret, errno, strerror(errno)); | ||
1257 | } | ||
1258 | |||
1259 | /* VM Ioctl | ||
1260 | * | ||
1261 | * Input Args: | ||
1262 | * vm - Virtual Machine | ||
1263 | * cmd - Ioctl number | ||
1264 | * arg - Argument to pass to the ioctl | ||
1265 | * | ||
1266 | * Return: None | ||
1267 | * | ||
1268 | * Issues an arbitrary ioctl on a VM fd. | ||
1269 | */ | ||
1270 | void vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) | ||
1271 | { | ||
1272 | int ret; | ||
1273 | |||
1274 | ret = ioctl(vm->fd, cmd, arg); | ||
1275 | TEST_ASSERT(ret == 0, "vm ioctl %lu failed, rc: %i errno: %i (%s)", | ||
1276 | cmd, ret, errno, strerror(errno)); | ||
1277 | } | ||
1278 | |||
1279 | /* VM Dump | ||
1280 | * | ||
1281 | * Input Args: | ||
1282 | * vm - Virtual Machine | ||
1283 | * indent - Left margin indent amount | ||
1284 | * | ||
1285 | * Output Args: | ||
1286 | * stream - Output FILE stream | ||
1287 | * | ||
1288 | * Return: None | ||
1289 | * | ||
1290 | * Dumps the current state of the VM given by vm, to the FILE stream | ||
1291 | * given by stream. | ||
1292 | */ | ||
1293 | void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) | ||
1294 | { | ||
1295 | struct userspace_mem_region *region; | ||
1296 | struct vcpu *vcpu; | ||
1297 | |||
1298 | fprintf(stream, "%*smode: 0x%x\n", indent, "", vm->mode); | ||
1299 | fprintf(stream, "%*sfd: %i\n", indent, "", vm->fd); | ||
1300 | fprintf(stream, "%*spage_size: 0x%x\n", indent, "", vm->page_size); | ||
1301 | fprintf(stream, "%*sMem Regions:\n", indent, ""); | ||
1302 | for (region = vm->userspace_mem_region_head; region; | ||
1303 | region = region->next) { | ||
1304 | fprintf(stream, "%*sguest_phys: 0x%lx size: 0x%lx " | ||
1305 | "host_virt: %p\n", indent + 2, "", | ||
1306 | (uint64_t) region->region.guest_phys_addr, | ||
1307 | (uint64_t) region->region.memory_size, | ||
1308 | region->host_mem); | ||
1309 | fprintf(stream, "%*sunused_phy_pages: ", indent + 2, ""); | ||
1310 | sparsebit_dump(stream, region->unused_phy_pages, 0); | ||
1311 | } | ||
1312 | fprintf(stream, "%*sMapped Virtual Pages:\n", indent, ""); | ||
1313 | sparsebit_dump(stream, vm->vpages_mapped, indent + 2); | ||
1314 | fprintf(stream, "%*spgd_created: %u\n", indent, "", | ||
1315 | vm->pgd_created); | ||
1316 | if (vm->pgd_created) { | ||
1317 | fprintf(stream, "%*sVirtual Translation Tables:\n", | ||
1318 | indent + 2, ""); | ||
1319 | virt_dump(stream, vm, indent + 4); | ||
1320 | } | ||
1321 | fprintf(stream, "%*sVCPUs:\n", indent, ""); | ||
1322 | for (vcpu = vm->vcpu_head; vcpu; vcpu = vcpu->next) | ||
1323 | vcpu_dump(stream, vm, vcpu->id, indent + 2); | ||
1324 | } | ||
1325 | |||
1326 | /* VM VCPU Dump | ||
1327 | * | ||
1328 | * Input Args: | ||
1329 | * vm - Virtual Machine | ||
1330 | * vcpuid - VCPU ID | ||
1331 | * indent - Left margin indent amount | ||
1332 | * | ||
1333 | * Output Args: | ||
1334 | * stream - Output FILE stream | ||
1335 | * | ||
1336 | * Return: None | ||
1337 | * | ||
1338 | * Dumps the current state of the VCPU specified by vcpuid, within the VM | ||
1339 | * given by vm, to the FILE stream given by stream. | ||
1340 | */ | ||
1341 | void vcpu_dump(FILE *stream, struct kvm_vm *vm, | ||
1342 | uint32_t vcpuid, uint8_t indent) | ||
1343 | { | ||
1344 | struct kvm_regs regs; | ||
1345 | struct kvm_sregs sregs; | ||
1346 | |||
1347 | fprintf(stream, "%*scpuid: %u\n", indent, "", vcpuid); | ||
1348 | |||
1349 | fprintf(stream, "%*sregs:\n", indent + 2, ""); | ||
1350 | vcpu_regs_get(vm, vcpuid, ®s); | ||
1351 | regs_dump(stream, ®s, indent + 4); | ||
1352 | |||
1353 | fprintf(stream, "%*ssregs:\n", indent + 2, ""); | ||
1354 | vcpu_sregs_get(vm, vcpuid, &sregs); | ||
1355 | sregs_dump(stream, &sregs, indent + 4); | ||
1356 | } | ||
1357 | |||
1358 | /* Known KVM exit reasons */ | ||
1359 | static struct exit_reason { | ||
1360 | unsigned int reason; | ||
1361 | const char *name; | ||
1362 | } exit_reasons_known[] = { | ||
1363 | {KVM_EXIT_UNKNOWN, "UNKNOWN"}, | ||
1364 | {KVM_EXIT_EXCEPTION, "EXCEPTION"}, | ||
1365 | {KVM_EXIT_IO, "IO"}, | ||
1366 | {KVM_EXIT_HYPERCALL, "HYPERCALL"}, | ||
1367 | {KVM_EXIT_DEBUG, "DEBUG"}, | ||
1368 | {KVM_EXIT_HLT, "HLT"}, | ||
1369 | {KVM_EXIT_MMIO, "MMIO"}, | ||
1370 | {KVM_EXIT_IRQ_WINDOW_OPEN, "IRQ_WINDOW_OPEN"}, | ||
1371 | {KVM_EXIT_SHUTDOWN, "SHUTDOWN"}, | ||
1372 | {KVM_EXIT_FAIL_ENTRY, "FAIL_ENTRY"}, | ||
1373 | {KVM_EXIT_INTR, "INTR"}, | ||
1374 | {KVM_EXIT_SET_TPR, "SET_TPR"}, | ||
1375 | {KVM_EXIT_TPR_ACCESS, "TPR_ACCESS"}, | ||
1376 | {KVM_EXIT_S390_SIEIC, "S390_SIEIC"}, | ||
1377 | {KVM_EXIT_S390_RESET, "S390_RESET"}, | ||
1378 | {KVM_EXIT_DCR, "DCR"}, | ||
1379 | {KVM_EXIT_NMI, "NMI"}, | ||
1380 | {KVM_EXIT_INTERNAL_ERROR, "INTERNAL_ERROR"}, | ||
1381 | {KVM_EXIT_OSI, "OSI"}, | ||
1382 | {KVM_EXIT_PAPR_HCALL, "PAPR_HCALL"}, | ||
1383 | #ifdef KVM_EXIT_MEMORY_NOT_PRESENT | ||
1384 | {KVM_EXIT_MEMORY_NOT_PRESENT, "MEMORY_NOT_PRESENT"}, | ||
1385 | #endif | ||
1386 | }; | ||
1387 | |||
1388 | /* Exit Reason String | ||
1389 | * | ||
1390 | * Input Args: | ||
1391 | * exit_reason - Exit reason | ||
1392 | * | ||
1393 | * Output Args: None | ||
1394 | * | ||
1395 | * Return: | ||
1396 | * Constant string pointer describing the exit reason. | ||
1397 | * | ||
1398 | * Locates and returns a constant string that describes the KVM exit | ||
1399 | * reason given by exit_reason. If no such string is found, a constant | ||
1400 | * string of "Unknown" is returned. | ||
1401 | */ | ||
1402 | const char *exit_reason_str(unsigned int exit_reason) | ||
1403 | { | ||
1404 | unsigned int n1; | ||
1405 | |||
1406 | for (n1 = 0; n1 < ARRAY_SIZE(exit_reasons_known); n1++) { | ||
1407 | if (exit_reason == exit_reasons_known[n1].reason) | ||
1408 | return exit_reasons_known[n1].name; | ||
1409 | } | ||
1410 | |||
1411 | return "Unknown"; | ||
1412 | } | ||
1413 | |||
1414 | /* Physical Page Allocate | ||
1415 | * | ||
1416 | * Input Args: | ||
1417 | * vm - Virtual Machine | ||
1418 | * paddr_min - Physical address minimum | ||
1419 | * memslot - Memory region to allocate page from | ||
1420 | * | ||
1421 | * Output Args: None | ||
1422 | * | ||
1423 | * Return: | ||
1424 | * Starting physical address | ||
1425 | * | ||
1426 | * Within the VM specified by vm, locates an available physical page | ||
1427 | * at or above paddr_min. If found, the page is marked as in use | ||
1428 | * and its address is returned. A TEST_ASSERT failure occurs if no | ||
1429 | * page is available at or above paddr_min. | ||
1430 | */ | ||
1431 | vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, | ||
1432 | vm_paddr_t paddr_min, uint32_t memslot) | ||
1433 | { | ||
1434 | struct userspace_mem_region *region; | ||
1435 | sparsebit_idx_t pg; | ||
1436 | |||
1437 | TEST_ASSERT((paddr_min % vm->page_size) == 0, "Min physical address " | ||
1438 | "not divisable by page size.\n" | ||
1439 | " paddr_min: 0x%lx page_size: 0x%x", | ||
1440 | paddr_min, vm->page_size); | ||
1441 | |||
1442 | /* Locate memory region. */ | ||
1443 | region = memslot2region(vm, memslot); | ||
1444 | |||
1445 | /* Locate next available physical page at or above paddr_min. */ | ||
1446 | pg = paddr_min >> vm->page_shift; | ||
1447 | |||
1448 | if (!sparsebit_is_set(region->unused_phy_pages, pg)) { | ||
1449 | pg = sparsebit_next_set(region->unused_phy_pages, pg); | ||
1450 | if (pg == 0) { | ||
1451 | fprintf(stderr, "No guest physical page available, " | ||
1452 | "paddr_min: 0x%lx page_size: 0x%x memslot: %u", | ||
1453 | paddr_min, vm->page_size, memslot); | ||
1454 | fputs("---- vm dump ----\n", stderr); | ||
1455 | vm_dump(stderr, vm, 2); | ||
1456 | abort(); | ||
1457 | } | ||
1458 | } | ||
1459 | |||
1460 | /* Specify page as in use and return its address. */ | ||
1461 | sparsebit_clear(region->unused_phy_pages, pg); | ||
1462 | |||
1463 | return pg * vm->page_size; | ||
1464 | } | ||
1465 | |||
1466 | /* Address Guest Virtual to Host Virtual | ||
1467 | * | ||
1468 | * Input Args: | ||
1469 | * vm - Virtual Machine | ||
1470 | * gva - VM virtual address | ||
1471 | * | ||
1472 | * Output Args: None | ||
1473 | * | ||
1474 | * Return: | ||
1475 | * Equivalent host virtual address | ||
1476 | */ | ||
1477 | void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva) | ||
1478 | { | ||
1479 | return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); | ||
1480 | } | ||