18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * tools/testing/selftests/kvm/lib/kvm_util.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2018, Google LLC. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "test_util.h" 98c2ecf20Sopenharmony_ci#include "kvm_util.h" 108c2ecf20Sopenharmony_ci#include "kvm_util_internal.h" 118c2ecf20Sopenharmony_ci#include "processor.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <assert.h> 148c2ecf20Sopenharmony_ci#include <sys/mman.h> 158c2ecf20Sopenharmony_ci#include <sys/types.h> 168c2ecf20Sopenharmony_ci#include <sys/stat.h> 178c2ecf20Sopenharmony_ci#include <unistd.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define KVM_UTIL_PGS_PER_HUGEPG 512 218c2ecf20Sopenharmony_ci#define KVM_UTIL_MIN_PFN 2 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Aligns x up to the next multiple of size. Size must be a power of 2. */ 248c2ecf20Sopenharmony_cistatic void *align(void *x, size_t size) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci size_t mask = size - 1; 278c2ecf20Sopenharmony_ci TEST_ASSERT(size != 0 && !(size & (size - 1)), 288c2ecf20Sopenharmony_ci "size not a power of 2: %lu", size); 298c2ecf20Sopenharmony_ci return (void *) (((size_t) x + mask) & ~mask); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Capability 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Input Args: 368c2ecf20Sopenharmony_ci * cap - Capability 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Output Args: None 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * Return: 418c2ecf20Sopenharmony_ci * On success, the Value corresponding to the capability (KVM_CAP_*) 428c2ecf20Sopenharmony_ci * specified by the value of cap. On failure a TEST_ASSERT failure 438c2ecf20Sopenharmony_ci * is produced. 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * Looks up and returns the value corresponding to the capability 468c2ecf20Sopenharmony_ci * (KVM_CAP_*) given by cap. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ciint kvm_check_cap(long cap) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci int ret; 518c2ecf20Sopenharmony_ci int kvm_fd; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci kvm_fd = open(KVM_DEV_PATH, O_RDONLY); 548c2ecf20Sopenharmony_ci if (kvm_fd < 0) 558c2ecf20Sopenharmony_ci exit(KSFT_SKIP); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, cap); 588c2ecf20Sopenharmony_ci TEST_ASSERT(ret >= 0, "KVM_CHECK_EXTENSION IOCTL failed,\n" 598c2ecf20Sopenharmony_ci " rc: %i errno: %i", ret, errno); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci close(kvm_fd); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return ret; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* VM Enable Capability 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * Input Args: 698c2ecf20Sopenharmony_ci * vm - Virtual Machine 708c2ecf20Sopenharmony_ci * cap - Capability 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * Output Args: None 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * Return: On success, 0. On failure a TEST_ASSERT failure is produced. 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * Enables a capability (KVM_CAP_*) on the VM. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ciint vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci int ret; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ret = ioctl(vm->fd, KVM_ENABLE_CAP, cap); 838c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_ENABLE_CAP IOCTL failed,\n" 848c2ecf20Sopenharmony_ci " rc: %i errno: %i", ret, errno); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return ret; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* VCPU Enable Capability 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * Input Args: 928c2ecf20Sopenharmony_ci * vm - Virtual Machine 938c2ecf20Sopenharmony_ci * vcpu_id - VCPU 948c2ecf20Sopenharmony_ci * cap - Capability 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * Output Args: None 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * Return: On success, 0. On failure a TEST_ASSERT failure is produced. 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Enables a capability (KVM_CAP_*) on the VCPU. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ciint vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, 1038c2ecf20Sopenharmony_ci struct kvm_enable_cap *cap) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpu_id); 1068c2ecf20Sopenharmony_ci int r; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu, "cannot find vcpu %d", vcpu_id); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci r = ioctl(vcpu->fd, KVM_ENABLE_CAP, cap); 1118c2ecf20Sopenharmony_ci TEST_ASSERT(!r, "KVM_ENABLE_CAP vCPU ioctl failed,\n" 1128c2ecf20Sopenharmony_ci " rc: %i, errno: %i", r, errno); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return r; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void vm_open(struct kvm_vm *vm, int perm) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci vm->kvm_fd = open(KVM_DEV_PATH, perm); 1208c2ecf20Sopenharmony_ci if (vm->kvm_fd < 0) 1218c2ecf20Sopenharmony_ci exit(KSFT_SKIP); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!kvm_check_cap(KVM_CAP_IMMEDIATE_EXIT)) { 1248c2ecf20Sopenharmony_ci print_skip("immediate_exit not available"); 1258c2ecf20Sopenharmony_ci exit(KSFT_SKIP); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci vm->fd = ioctl(vm->kvm_fd, KVM_CREATE_VM, vm->type); 1298c2ecf20Sopenharmony_ci TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " 1308c2ecf20Sopenharmony_ci "rc: %i errno: %i", vm->fd, errno); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ciconst char * const vm_guest_mode_string[] = { 1348c2ecf20Sopenharmony_ci "PA-bits:52, VA-bits:48, 4K pages", 1358c2ecf20Sopenharmony_ci "PA-bits:52, VA-bits:48, 64K pages", 1368c2ecf20Sopenharmony_ci "PA-bits:48, VA-bits:48, 4K pages", 1378c2ecf20Sopenharmony_ci "PA-bits:48, VA-bits:48, 64K pages", 1388c2ecf20Sopenharmony_ci "PA-bits:40, VA-bits:48, 4K pages", 1398c2ecf20Sopenharmony_ci "PA-bits:40, VA-bits:48, 64K pages", 1408c2ecf20Sopenharmony_ci "PA-bits:ANY, VA-bits:48, 4K pages", 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci_Static_assert(sizeof(vm_guest_mode_string)/sizeof(char *) == NUM_VM_MODES, 1438c2ecf20Sopenharmony_ci "Missing new mode strings?"); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistruct vm_guest_mode_params { 1468c2ecf20Sopenharmony_ci unsigned int pa_bits; 1478c2ecf20Sopenharmony_ci unsigned int va_bits; 1488c2ecf20Sopenharmony_ci unsigned int page_size; 1498c2ecf20Sopenharmony_ci unsigned int page_shift; 1508c2ecf20Sopenharmony_ci}; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic const struct vm_guest_mode_params vm_guest_mode_params[] = { 1538c2ecf20Sopenharmony_ci { 52, 48, 0x1000, 12 }, 1548c2ecf20Sopenharmony_ci { 52, 48, 0x10000, 16 }, 1558c2ecf20Sopenharmony_ci { 48, 48, 0x1000, 12 }, 1568c2ecf20Sopenharmony_ci { 48, 48, 0x10000, 16 }, 1578c2ecf20Sopenharmony_ci { 40, 48, 0x1000, 12 }, 1588c2ecf20Sopenharmony_ci { 40, 48, 0x10000, 16 }, 1598c2ecf20Sopenharmony_ci { 0, 0, 0x1000, 12 }, 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci_Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_params) == NUM_VM_MODES, 1628c2ecf20Sopenharmony_ci "Missing new mode params?"); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* 1658c2ecf20Sopenharmony_ci * VM Create 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * Input Args: 1688c2ecf20Sopenharmony_ci * mode - VM Mode (e.g. VM_MODE_P52V48_4K) 1698c2ecf20Sopenharmony_ci * phy_pages - Physical memory pages 1708c2ecf20Sopenharmony_ci * perm - permission 1718c2ecf20Sopenharmony_ci * 1728c2ecf20Sopenharmony_ci * Output Args: None 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * Return: 1758c2ecf20Sopenharmony_ci * Pointer to opaque structure that describes the created VM. 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * Creates a VM with the mode specified by mode (e.g. VM_MODE_P52V48_4K). 1788c2ecf20Sopenharmony_ci * When phy_pages is non-zero, a memory region of phy_pages physical pages 1798c2ecf20Sopenharmony_ci * is created and mapped starting at guest physical address 0. The file 1808c2ecf20Sopenharmony_ci * descriptor to control the created VM is created with the permissions 1818c2ecf20Sopenharmony_ci * given by perm (e.g. O_RDWR). 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_cistruct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct kvm_vm *vm; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci pr_debug("%s: mode='%s' pages='%ld' perm='%d'\n", __func__, 1888c2ecf20Sopenharmony_ci vm_guest_mode_string(mode), phy_pages, perm); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci vm = calloc(1, sizeof(*vm)); 1918c2ecf20Sopenharmony_ci TEST_ASSERT(vm != NULL, "Insufficient Memory"); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vm->vcpus); 1948c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vm->userspace_mem_regions); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci vm->mode = mode; 1978c2ecf20Sopenharmony_ci vm->type = 0; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci vm->pa_bits = vm_guest_mode_params[mode].pa_bits; 2008c2ecf20Sopenharmony_ci vm->va_bits = vm_guest_mode_params[mode].va_bits; 2018c2ecf20Sopenharmony_ci vm->page_size = vm_guest_mode_params[mode].page_size; 2028c2ecf20Sopenharmony_ci vm->page_shift = vm_guest_mode_params[mode].page_shift; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* Setup mode specific traits. */ 2058c2ecf20Sopenharmony_ci switch (vm->mode) { 2068c2ecf20Sopenharmony_ci case VM_MODE_P52V48_4K: 2078c2ecf20Sopenharmony_ci vm->pgtable_levels = 4; 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci case VM_MODE_P52V48_64K: 2108c2ecf20Sopenharmony_ci vm->pgtable_levels = 3; 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci case VM_MODE_P48V48_4K: 2138c2ecf20Sopenharmony_ci vm->pgtable_levels = 4; 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci case VM_MODE_P48V48_64K: 2168c2ecf20Sopenharmony_ci vm->pgtable_levels = 3; 2178c2ecf20Sopenharmony_ci break; 2188c2ecf20Sopenharmony_ci case VM_MODE_P40V48_4K: 2198c2ecf20Sopenharmony_ci vm->pgtable_levels = 4; 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci case VM_MODE_P40V48_64K: 2228c2ecf20Sopenharmony_ci vm->pgtable_levels = 3; 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci case VM_MODE_PXXV48_4K: 2258c2ecf20Sopenharmony_ci#ifdef __x86_64__ 2268c2ecf20Sopenharmony_ci kvm_get_cpu_address_width(&vm->pa_bits, &vm->va_bits); 2278c2ecf20Sopenharmony_ci /* 2288c2ecf20Sopenharmony_ci * Ignore KVM support for 5-level paging (vm->va_bits == 57), 2298c2ecf20Sopenharmony_ci * it doesn't take effect unless a CR4.LA57 is set, which it 2308c2ecf20Sopenharmony_ci * isn't for this VM_MODE. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci TEST_ASSERT(vm->va_bits == 48 || vm->va_bits == 57, 2338c2ecf20Sopenharmony_ci "Linear address width (%d bits) not supported", 2348c2ecf20Sopenharmony_ci vm->va_bits); 2358c2ecf20Sopenharmony_ci pr_debug("Guest physical address width detected: %d\n", 2368c2ecf20Sopenharmony_ci vm->pa_bits); 2378c2ecf20Sopenharmony_ci vm->pgtable_levels = 4; 2388c2ecf20Sopenharmony_ci vm->va_bits = 48; 2398c2ecf20Sopenharmony_ci#else 2408c2ecf20Sopenharmony_ci TEST_FAIL("VM_MODE_PXXV48_4K not supported on non-x86 platforms"); 2418c2ecf20Sopenharmony_ci#endif 2428c2ecf20Sopenharmony_ci break; 2438c2ecf20Sopenharmony_ci default: 2448c2ecf20Sopenharmony_ci TEST_FAIL("Unknown guest mode, mode: 0x%x", mode); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci#ifdef __aarch64__ 2488c2ecf20Sopenharmony_ci if (vm->pa_bits != 40) 2498c2ecf20Sopenharmony_ci vm->type = KVM_VM_TYPE_ARM_IPA_SIZE(vm->pa_bits); 2508c2ecf20Sopenharmony_ci#endif 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci vm_open(vm, perm); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* Limit to VA-bit canonical virtual addresses. */ 2558c2ecf20Sopenharmony_ci vm->vpages_valid = sparsebit_alloc(); 2568c2ecf20Sopenharmony_ci sparsebit_set_num(vm->vpages_valid, 2578c2ecf20Sopenharmony_ci 0, (1ULL << (vm->va_bits - 1)) >> vm->page_shift); 2588c2ecf20Sopenharmony_ci sparsebit_set_num(vm->vpages_valid, 2598c2ecf20Sopenharmony_ci (~((1ULL << (vm->va_bits - 1)) - 1)) >> vm->page_shift, 2608c2ecf20Sopenharmony_ci (1ULL << (vm->va_bits - 1)) >> vm->page_shift); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Limit physical addresses to PA-bits. */ 2638c2ecf20Sopenharmony_ci vm->max_gfn = ((1ULL << vm->pa_bits) >> vm->page_shift) - 1; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* Allocate and setup memory for guest. */ 2668c2ecf20Sopenharmony_ci vm->vpages_mapped = sparsebit_alloc(); 2678c2ecf20Sopenharmony_ci if (phy_pages != 0) 2688c2ecf20Sopenharmony_ci vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 2698c2ecf20Sopenharmony_ci 0, 0, phy_pages, 0); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return vm; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/* 2758c2ecf20Sopenharmony_ci * VM Restart 2768c2ecf20Sopenharmony_ci * 2778c2ecf20Sopenharmony_ci * Input Args: 2788c2ecf20Sopenharmony_ci * vm - VM that has been released before 2798c2ecf20Sopenharmony_ci * perm - permission 2808c2ecf20Sopenharmony_ci * 2818c2ecf20Sopenharmony_ci * Output Args: None 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * Reopens the file descriptors associated to the VM and reinstates the 2848c2ecf20Sopenharmony_ci * global state, such as the irqchip and the memory regions that are mapped 2858c2ecf20Sopenharmony_ci * into the guest. 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_civoid kvm_vm_restart(struct kvm_vm *vmp, int perm) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci vm_open(vmp, perm); 2928c2ecf20Sopenharmony_ci if (vmp->has_irqchip) 2938c2ecf20Sopenharmony_ci vm_create_irqchip(vmp); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci list_for_each_entry(region, &vmp->userspace_mem_regions, list) { 2968c2ecf20Sopenharmony_ci int ret = ioctl(vmp->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); 2978c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" 2988c2ecf20Sopenharmony_ci " rc: %i errno: %i\n" 2998c2ecf20Sopenharmony_ci " slot: %u flags: 0x%x\n" 3008c2ecf20Sopenharmony_ci " guest_phys_addr: 0x%llx size: 0x%llx", 3018c2ecf20Sopenharmony_ci ret, errno, region->region.slot, 3028c2ecf20Sopenharmony_ci region->region.flags, 3038c2ecf20Sopenharmony_ci region->region.guest_phys_addr, 3048c2ecf20Sopenharmony_ci region->region.memory_size); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_civoid kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct kvm_dirty_log args = { .dirty_bitmap = log, .slot = slot }; 3118c2ecf20Sopenharmony_ci int ret; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci ret = ioctl(vm->fd, KVM_GET_DIRTY_LOG, &args); 3148c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "%s: KVM_GET_DIRTY_LOG failed: %s", 3158c2ecf20Sopenharmony_ci __func__, strerror(-ret)); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_civoid kvm_vm_clear_dirty_log(struct kvm_vm *vm, int slot, void *log, 3198c2ecf20Sopenharmony_ci uint64_t first_page, uint32_t num_pages) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci struct kvm_clear_dirty_log args = { .dirty_bitmap = log, .slot = slot, 3228c2ecf20Sopenharmony_ci .first_page = first_page, 3238c2ecf20Sopenharmony_ci .num_pages = num_pages }; 3248c2ecf20Sopenharmony_ci int ret; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci ret = ioctl(vm->fd, KVM_CLEAR_DIRTY_LOG, &args); 3278c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "%s: KVM_CLEAR_DIRTY_LOG failed: %s", 3288c2ecf20Sopenharmony_ci __func__, strerror(-ret)); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci/* 3328c2ecf20Sopenharmony_ci * Userspace Memory Region Find 3338c2ecf20Sopenharmony_ci * 3348c2ecf20Sopenharmony_ci * Input Args: 3358c2ecf20Sopenharmony_ci * vm - Virtual Machine 3368c2ecf20Sopenharmony_ci * start - Starting VM physical address 3378c2ecf20Sopenharmony_ci * end - Ending VM physical address, inclusive. 3388c2ecf20Sopenharmony_ci * 3398c2ecf20Sopenharmony_ci * Output Args: None 3408c2ecf20Sopenharmony_ci * 3418c2ecf20Sopenharmony_ci * Return: 3428c2ecf20Sopenharmony_ci * Pointer to overlapping region, NULL if no such region. 3438c2ecf20Sopenharmony_ci * 3448c2ecf20Sopenharmony_ci * Searches for a region with any physical memory that overlaps with 3458c2ecf20Sopenharmony_ci * any portion of the guest physical addresses from start to end 3468c2ecf20Sopenharmony_ci * inclusive. If multiple overlapping regions exist, a pointer to any 3478c2ecf20Sopenharmony_ci * of the regions is returned. Null is returned only when no overlapping 3488c2ecf20Sopenharmony_ci * region exists. 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_cistatic struct userspace_mem_region * 3518c2ecf20Sopenharmony_ciuserspace_mem_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci list_for_each_entry(region, &vm->userspace_mem_regions, list) { 3568c2ecf20Sopenharmony_ci uint64_t existing_start = region->region.guest_phys_addr; 3578c2ecf20Sopenharmony_ci uint64_t existing_end = region->region.guest_phys_addr 3588c2ecf20Sopenharmony_ci + region->region.memory_size - 1; 3598c2ecf20Sopenharmony_ci if (start <= existing_end && end >= existing_start) 3608c2ecf20Sopenharmony_ci return region; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return NULL; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* 3678c2ecf20Sopenharmony_ci * KVM Userspace Memory Region Find 3688c2ecf20Sopenharmony_ci * 3698c2ecf20Sopenharmony_ci * Input Args: 3708c2ecf20Sopenharmony_ci * vm - Virtual Machine 3718c2ecf20Sopenharmony_ci * start - Starting VM physical address 3728c2ecf20Sopenharmony_ci * end - Ending VM physical address, inclusive. 3738c2ecf20Sopenharmony_ci * 3748c2ecf20Sopenharmony_ci * Output Args: None 3758c2ecf20Sopenharmony_ci * 3768c2ecf20Sopenharmony_ci * Return: 3778c2ecf20Sopenharmony_ci * Pointer to overlapping region, NULL if no such region. 3788c2ecf20Sopenharmony_ci * 3798c2ecf20Sopenharmony_ci * Public interface to userspace_mem_region_find. Allows tests to look up 3808c2ecf20Sopenharmony_ci * the memslot datastructure for a given range of guest physical memory. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_cistruct kvm_userspace_memory_region * 3838c2ecf20Sopenharmony_cikvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, 3848c2ecf20Sopenharmony_ci uint64_t end) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci region = userspace_mem_region_find(vm, start, end); 3898c2ecf20Sopenharmony_ci if (!region) 3908c2ecf20Sopenharmony_ci return NULL; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return ®ion->region; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci/* 3968c2ecf20Sopenharmony_ci * VCPU Find 3978c2ecf20Sopenharmony_ci * 3988c2ecf20Sopenharmony_ci * Input Args: 3998c2ecf20Sopenharmony_ci * vm - Virtual Machine 4008c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 4018c2ecf20Sopenharmony_ci * 4028c2ecf20Sopenharmony_ci * Output Args: None 4038c2ecf20Sopenharmony_ci * 4048c2ecf20Sopenharmony_ci * Return: 4058c2ecf20Sopenharmony_ci * Pointer to VCPU structure 4068c2ecf20Sopenharmony_ci * 4078c2ecf20Sopenharmony_ci * Locates a vcpu structure that describes the VCPU specified by vcpuid and 4088c2ecf20Sopenharmony_ci * returns a pointer to it. Returns NULL if the VM doesn't contain a VCPU 4098c2ecf20Sopenharmony_ci * for the specified vcpuid. 4108c2ecf20Sopenharmony_ci */ 4118c2ecf20Sopenharmony_cistruct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci struct vcpu *vcpu; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci list_for_each_entry(vcpu, &vm->vcpus, list) { 4168c2ecf20Sopenharmony_ci if (vcpu->id == vcpuid) 4178c2ecf20Sopenharmony_ci return vcpu; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return NULL; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/* 4248c2ecf20Sopenharmony_ci * VM VCPU Remove 4258c2ecf20Sopenharmony_ci * 4268c2ecf20Sopenharmony_ci * Input Args: 4278c2ecf20Sopenharmony_ci * vcpu - VCPU to remove 4288c2ecf20Sopenharmony_ci * 4298c2ecf20Sopenharmony_ci * Output Args: None 4308c2ecf20Sopenharmony_ci * 4318c2ecf20Sopenharmony_ci * Return: None, TEST_ASSERT failures for all error conditions 4328c2ecf20Sopenharmony_ci * 4338c2ecf20Sopenharmony_ci * Removes a vCPU from a VM and frees its resources. 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_cistatic void vm_vcpu_rm(struct vcpu *vcpu) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci int ret; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci ret = munmap(vcpu->state, sizeof(*vcpu->state)); 4408c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "munmap of VCPU fd failed, rc: %i " 4418c2ecf20Sopenharmony_ci "errno: %i", ret, errno); 4428c2ecf20Sopenharmony_ci close(vcpu->fd); 4438c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "Close of VCPU fd failed, rc: %i " 4448c2ecf20Sopenharmony_ci "errno: %i", ret, errno); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci list_del(&vcpu->list); 4478c2ecf20Sopenharmony_ci free(vcpu); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_civoid kvm_vm_release(struct kvm_vm *vmp) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci struct vcpu *vcpu, *tmp; 4538c2ecf20Sopenharmony_ci int ret; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci list_for_each_entry_safe(vcpu, tmp, &vmp->vcpus, list) 4568c2ecf20Sopenharmony_ci vm_vcpu_rm(vcpu); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci ret = close(vmp->fd); 4598c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "Close of vm fd failed,\n" 4608c2ecf20Sopenharmony_ci " vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci close(vmp->kvm_fd); 4638c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "Close of /dev/kvm fd failed,\n" 4648c2ecf20Sopenharmony_ci " vmp->kvm_fd: %i rc: %i errno: %i", vmp->kvm_fd, ret, errno); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic void __vm_mem_region_delete(struct kvm_vm *vm, 4688c2ecf20Sopenharmony_ci struct userspace_mem_region *region) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci int ret; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci list_del(®ion->list); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci region->region.memory_size = 0; 4758c2ecf20Sopenharmony_ci ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); 4768c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed, " 4778c2ecf20Sopenharmony_ci "rc: %i errno: %i", ret, errno); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci sparsebit_free(®ion->unused_phy_pages); 4808c2ecf20Sopenharmony_ci ret = munmap(region->mmap_start, region->mmap_size); 4818c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "munmap failed, rc: %i errno: %i", ret, errno); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci free(region); 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/* 4878c2ecf20Sopenharmony_ci * Destroys and frees the VM pointed to by vmp. 4888c2ecf20Sopenharmony_ci */ 4898c2ecf20Sopenharmony_civoid kvm_vm_free(struct kvm_vm *vmp) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct userspace_mem_region *region, *tmp; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (vmp == NULL) 4948c2ecf20Sopenharmony_ci return; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* Free userspace_mem_regions. */ 4978c2ecf20Sopenharmony_ci list_for_each_entry_safe(region, tmp, &vmp->userspace_mem_regions, list) 4988c2ecf20Sopenharmony_ci __vm_mem_region_delete(vmp, region); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* Free sparsebit arrays. */ 5018c2ecf20Sopenharmony_ci sparsebit_free(&vmp->vpages_valid); 5028c2ecf20Sopenharmony_ci sparsebit_free(&vmp->vpages_mapped); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci kvm_vm_release(vmp); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* Free the structure describing the VM. */ 5078c2ecf20Sopenharmony_ci free(vmp); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci/* 5118c2ecf20Sopenharmony_ci * Memory Compare, host virtual to guest virtual 5128c2ecf20Sopenharmony_ci * 5138c2ecf20Sopenharmony_ci * Input Args: 5148c2ecf20Sopenharmony_ci * hva - Starting host virtual address 5158c2ecf20Sopenharmony_ci * vm - Virtual Machine 5168c2ecf20Sopenharmony_ci * gva - Starting guest virtual address 5178c2ecf20Sopenharmony_ci * len - number of bytes to compare 5188c2ecf20Sopenharmony_ci * 5198c2ecf20Sopenharmony_ci * Output Args: None 5208c2ecf20Sopenharmony_ci * 5218c2ecf20Sopenharmony_ci * Input/Output Args: None 5228c2ecf20Sopenharmony_ci * 5238c2ecf20Sopenharmony_ci * Return: 5248c2ecf20Sopenharmony_ci * Returns 0 if the bytes starting at hva for a length of len 5258c2ecf20Sopenharmony_ci * are equal the guest virtual bytes starting at gva. Returns 5268c2ecf20Sopenharmony_ci * a value < 0, if bytes at hva are less than those at gva. 5278c2ecf20Sopenharmony_ci * Otherwise a value > 0 is returned. 5288c2ecf20Sopenharmony_ci * 5298c2ecf20Sopenharmony_ci * Compares the bytes starting at the host virtual address hva, for 5308c2ecf20Sopenharmony_ci * a length of len, to the guest bytes starting at the guest virtual 5318c2ecf20Sopenharmony_ci * address given by gva. 5328c2ecf20Sopenharmony_ci */ 5338c2ecf20Sopenharmony_ciint kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, vm_vaddr_t gva, size_t len) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci size_t amt; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* 5388c2ecf20Sopenharmony_ci * Compare a batch of bytes until either a match is found 5398c2ecf20Sopenharmony_ci * or all the bytes have been compared. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_ci for (uintptr_t offset = 0; offset < len; offset += amt) { 5428c2ecf20Sopenharmony_ci uintptr_t ptr1 = (uintptr_t)hva + offset; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* 5458c2ecf20Sopenharmony_ci * Determine host address for guest virtual address 5468c2ecf20Sopenharmony_ci * at offset. 5478c2ecf20Sopenharmony_ci */ 5488c2ecf20Sopenharmony_ci uintptr_t ptr2 = (uintptr_t)addr_gva2hva(vm, gva + offset); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* 5518c2ecf20Sopenharmony_ci * Determine amount to compare on this pass. 5528c2ecf20Sopenharmony_ci * Don't allow the comparsion to cross a page boundary. 5538c2ecf20Sopenharmony_ci */ 5548c2ecf20Sopenharmony_ci amt = len - offset; 5558c2ecf20Sopenharmony_ci if ((ptr1 >> vm->page_shift) != ((ptr1 + amt) >> vm->page_shift)) 5568c2ecf20Sopenharmony_ci amt = vm->page_size - (ptr1 % vm->page_size); 5578c2ecf20Sopenharmony_ci if ((ptr2 >> vm->page_shift) != ((ptr2 + amt) >> vm->page_shift)) 5588c2ecf20Sopenharmony_ci amt = vm->page_size - (ptr2 % vm->page_size); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci assert((ptr1 >> vm->page_shift) == ((ptr1 + amt - 1) >> vm->page_shift)); 5618c2ecf20Sopenharmony_ci assert((ptr2 >> vm->page_shift) == ((ptr2 + amt - 1) >> vm->page_shift)); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* 5648c2ecf20Sopenharmony_ci * Perform the comparison. If there is a difference 5658c2ecf20Sopenharmony_ci * return that result to the caller, otherwise need 5668c2ecf20Sopenharmony_ci * to continue on looking for a mismatch. 5678c2ecf20Sopenharmony_ci */ 5688c2ecf20Sopenharmony_ci int ret = memcmp((void *)ptr1, (void *)ptr2, amt); 5698c2ecf20Sopenharmony_ci if (ret != 0) 5708c2ecf20Sopenharmony_ci return ret; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* 5748c2ecf20Sopenharmony_ci * No mismatch found. Let the caller know the two memory 5758c2ecf20Sopenharmony_ci * areas are equal. 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_ci return 0; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci/* 5818c2ecf20Sopenharmony_ci * VM Userspace Memory Region Add 5828c2ecf20Sopenharmony_ci * 5838c2ecf20Sopenharmony_ci * Input Args: 5848c2ecf20Sopenharmony_ci * vm - Virtual Machine 5858c2ecf20Sopenharmony_ci * backing_src - Storage source for this region. 5868c2ecf20Sopenharmony_ci * NULL to use anonymous memory. 5878c2ecf20Sopenharmony_ci * guest_paddr - Starting guest physical address 5888c2ecf20Sopenharmony_ci * slot - KVM region slot 5898c2ecf20Sopenharmony_ci * npages - Number of physical pages 5908c2ecf20Sopenharmony_ci * flags - KVM memory region flags (e.g. KVM_MEM_LOG_DIRTY_PAGES) 5918c2ecf20Sopenharmony_ci * 5928c2ecf20Sopenharmony_ci * Output Args: None 5938c2ecf20Sopenharmony_ci * 5948c2ecf20Sopenharmony_ci * Return: None 5958c2ecf20Sopenharmony_ci * 5968c2ecf20Sopenharmony_ci * Allocates a memory area of the number of pages specified by npages 5978c2ecf20Sopenharmony_ci * and maps it to the VM specified by vm, at a starting physical address 5988c2ecf20Sopenharmony_ci * given by guest_paddr. The region is created with a KVM region slot 5998c2ecf20Sopenharmony_ci * given by slot, which must be unique and < KVM_MEM_SLOTS_NUM. The 6008c2ecf20Sopenharmony_ci * region is created with the flags given by flags. 6018c2ecf20Sopenharmony_ci */ 6028c2ecf20Sopenharmony_civoid vm_userspace_mem_region_add(struct kvm_vm *vm, 6038c2ecf20Sopenharmony_ci enum vm_mem_backing_src_type src_type, 6048c2ecf20Sopenharmony_ci uint64_t guest_paddr, uint32_t slot, uint64_t npages, 6058c2ecf20Sopenharmony_ci uint32_t flags) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci int ret; 6088c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 6098c2ecf20Sopenharmony_ci size_t huge_page_size = KVM_UTIL_PGS_PER_HUGEPG * vm->page_size; 6108c2ecf20Sopenharmony_ci size_t alignment; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci TEST_ASSERT(vm_adjust_num_guest_pages(vm->mode, npages) == npages, 6138c2ecf20Sopenharmony_ci "Number of guest pages is not compatible with the host. " 6148c2ecf20Sopenharmony_ci "Try npages=%d", vm_adjust_num_guest_pages(vm->mode, npages)); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci TEST_ASSERT((guest_paddr % vm->page_size) == 0, "Guest physical " 6178c2ecf20Sopenharmony_ci "address not on a page boundary.\n" 6188c2ecf20Sopenharmony_ci " guest_paddr: 0x%lx vm->page_size: 0x%x", 6198c2ecf20Sopenharmony_ci guest_paddr, vm->page_size); 6208c2ecf20Sopenharmony_ci TEST_ASSERT((((guest_paddr >> vm->page_shift) + npages) - 1) 6218c2ecf20Sopenharmony_ci <= vm->max_gfn, "Physical range beyond maximum " 6228c2ecf20Sopenharmony_ci "supported physical address,\n" 6238c2ecf20Sopenharmony_ci " guest_paddr: 0x%lx npages: 0x%lx\n" 6248c2ecf20Sopenharmony_ci " vm->max_gfn: 0x%lx vm->page_size: 0x%x", 6258c2ecf20Sopenharmony_ci guest_paddr, npages, vm->max_gfn, vm->page_size); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* 6288c2ecf20Sopenharmony_ci * Confirm a mem region with an overlapping address doesn't 6298c2ecf20Sopenharmony_ci * already exist. 6308c2ecf20Sopenharmony_ci */ 6318c2ecf20Sopenharmony_ci region = (struct userspace_mem_region *) userspace_mem_region_find( 6328c2ecf20Sopenharmony_ci vm, guest_paddr, (guest_paddr + npages * vm->page_size) - 1); 6338c2ecf20Sopenharmony_ci if (region != NULL) 6348c2ecf20Sopenharmony_ci TEST_FAIL("overlapping userspace_mem_region already " 6358c2ecf20Sopenharmony_ci "exists\n" 6368c2ecf20Sopenharmony_ci " requested guest_paddr: 0x%lx npages: 0x%lx " 6378c2ecf20Sopenharmony_ci "page_size: 0x%x\n" 6388c2ecf20Sopenharmony_ci " existing guest_paddr: 0x%lx size: 0x%lx", 6398c2ecf20Sopenharmony_ci guest_paddr, npages, vm->page_size, 6408c2ecf20Sopenharmony_ci (uint64_t) region->region.guest_phys_addr, 6418c2ecf20Sopenharmony_ci (uint64_t) region->region.memory_size); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* Confirm no region with the requested slot already exists. */ 6448c2ecf20Sopenharmony_ci list_for_each_entry(region, &vm->userspace_mem_regions, list) { 6458c2ecf20Sopenharmony_ci if (region->region.slot != slot) 6468c2ecf20Sopenharmony_ci continue; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci TEST_FAIL("A mem region with the requested slot " 6498c2ecf20Sopenharmony_ci "already exists.\n" 6508c2ecf20Sopenharmony_ci " requested slot: %u paddr: 0x%lx npages: 0x%lx\n" 6518c2ecf20Sopenharmony_ci " existing slot: %u paddr: 0x%lx size: 0x%lx", 6528c2ecf20Sopenharmony_ci slot, guest_paddr, npages, 6538c2ecf20Sopenharmony_ci region->region.slot, 6548c2ecf20Sopenharmony_ci (uint64_t) region->region.guest_phys_addr, 6558c2ecf20Sopenharmony_ci (uint64_t) region->region.memory_size); 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci /* Allocate and initialize new mem region structure. */ 6598c2ecf20Sopenharmony_ci region = calloc(1, sizeof(*region)); 6608c2ecf20Sopenharmony_ci TEST_ASSERT(region != NULL, "Insufficient Memory"); 6618c2ecf20Sopenharmony_ci region->mmap_size = npages * vm->page_size; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci#ifdef __s390x__ 6648c2ecf20Sopenharmony_ci /* On s390x, the host address must be aligned to 1M (due to PGSTEs) */ 6658c2ecf20Sopenharmony_ci alignment = 0x100000; 6668c2ecf20Sopenharmony_ci#else 6678c2ecf20Sopenharmony_ci alignment = 1; 6688c2ecf20Sopenharmony_ci#endif 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (src_type == VM_MEM_SRC_ANONYMOUS_THP) 6718c2ecf20Sopenharmony_ci alignment = max(huge_page_size, alignment); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* Add enough memory to align up if necessary */ 6748c2ecf20Sopenharmony_ci if (alignment > 1) 6758c2ecf20Sopenharmony_ci region->mmap_size += alignment; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci region->mmap_start = mmap(NULL, region->mmap_size, 6788c2ecf20Sopenharmony_ci PROT_READ | PROT_WRITE, 6798c2ecf20Sopenharmony_ci MAP_PRIVATE | MAP_ANONYMOUS 6808c2ecf20Sopenharmony_ci | (src_type == VM_MEM_SRC_ANONYMOUS_HUGETLB ? MAP_HUGETLB : 0), 6818c2ecf20Sopenharmony_ci -1, 0); 6828c2ecf20Sopenharmony_ci TEST_ASSERT(region->mmap_start != MAP_FAILED, 6838c2ecf20Sopenharmony_ci "test_malloc failed, mmap_start: %p errno: %i", 6848c2ecf20Sopenharmony_ci region->mmap_start, errno); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* Align host address */ 6878c2ecf20Sopenharmony_ci region->host_mem = align(region->mmap_start, alignment); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* As needed perform madvise */ 6908c2ecf20Sopenharmony_ci if (src_type == VM_MEM_SRC_ANONYMOUS || src_type == VM_MEM_SRC_ANONYMOUS_THP) { 6918c2ecf20Sopenharmony_ci struct stat statbuf; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci ret = stat("/sys/kernel/mm/transparent_hugepage", &statbuf); 6948c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0 || (ret == -1 && errno == ENOENT), 6958c2ecf20Sopenharmony_ci "stat /sys/kernel/mm/transparent_hugepage"); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0 || src_type != VM_MEM_SRC_ANONYMOUS_THP, 6988c2ecf20Sopenharmony_ci "VM_MEM_SRC_ANONYMOUS_THP requires THP to be configured in the host kernel"); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (ret == 0) { 7018c2ecf20Sopenharmony_ci ret = madvise(region->host_mem, npages * vm->page_size, 7028c2ecf20Sopenharmony_ci src_type == VM_MEM_SRC_ANONYMOUS ? MADV_NOHUGEPAGE : MADV_HUGEPAGE); 7038c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "madvise failed, addr: %p length: 0x%lx src_type: %x", 7048c2ecf20Sopenharmony_ci region->host_mem, npages * vm->page_size, src_type); 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci region->unused_phy_pages = sparsebit_alloc(); 7098c2ecf20Sopenharmony_ci sparsebit_set_num(region->unused_phy_pages, 7108c2ecf20Sopenharmony_ci guest_paddr >> vm->page_shift, npages); 7118c2ecf20Sopenharmony_ci region->region.slot = slot; 7128c2ecf20Sopenharmony_ci region->region.flags = flags; 7138c2ecf20Sopenharmony_ci region->region.guest_phys_addr = guest_paddr; 7148c2ecf20Sopenharmony_ci region->region.memory_size = npages * vm->page_size; 7158c2ecf20Sopenharmony_ci region->region.userspace_addr = (uintptr_t) region->host_mem; 7168c2ecf20Sopenharmony_ci ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); 7178c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" 7188c2ecf20Sopenharmony_ci " rc: %i errno: %i\n" 7198c2ecf20Sopenharmony_ci " slot: %u flags: 0x%x\n" 7208c2ecf20Sopenharmony_ci " guest_phys_addr: 0x%lx size: 0x%lx", 7218c2ecf20Sopenharmony_ci ret, errno, slot, flags, 7228c2ecf20Sopenharmony_ci guest_paddr, (uint64_t) region->region.memory_size); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* Add to linked-list of memory regions. */ 7258c2ecf20Sopenharmony_ci list_add(®ion->list, &vm->userspace_mem_regions); 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci/* 7298c2ecf20Sopenharmony_ci * Memslot to region 7308c2ecf20Sopenharmony_ci * 7318c2ecf20Sopenharmony_ci * Input Args: 7328c2ecf20Sopenharmony_ci * vm - Virtual Machine 7338c2ecf20Sopenharmony_ci * memslot - KVM memory slot ID 7348c2ecf20Sopenharmony_ci * 7358c2ecf20Sopenharmony_ci * Output Args: None 7368c2ecf20Sopenharmony_ci * 7378c2ecf20Sopenharmony_ci * Return: 7388c2ecf20Sopenharmony_ci * Pointer to memory region structure that describe memory region 7398c2ecf20Sopenharmony_ci * using kvm memory slot ID given by memslot. TEST_ASSERT failure 7408c2ecf20Sopenharmony_ci * on error (e.g. currently no memory region using memslot as a KVM 7418c2ecf20Sopenharmony_ci * memory slot ID). 7428c2ecf20Sopenharmony_ci */ 7438c2ecf20Sopenharmony_cistruct userspace_mem_region * 7448c2ecf20Sopenharmony_cimemslot2region(struct kvm_vm *vm, uint32_t memslot) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci list_for_each_entry(region, &vm->userspace_mem_regions, list) { 7498c2ecf20Sopenharmony_ci if (region->region.slot == memslot) 7508c2ecf20Sopenharmony_ci return region; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci fprintf(stderr, "No mem region with the requested slot found,\n" 7548c2ecf20Sopenharmony_ci " requested slot: %u\n", memslot); 7558c2ecf20Sopenharmony_ci fputs("---- vm dump ----\n", stderr); 7568c2ecf20Sopenharmony_ci vm_dump(stderr, vm, 2); 7578c2ecf20Sopenharmony_ci TEST_FAIL("Mem region not found"); 7588c2ecf20Sopenharmony_ci return NULL; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci/* 7628c2ecf20Sopenharmony_ci * VM Memory Region Flags Set 7638c2ecf20Sopenharmony_ci * 7648c2ecf20Sopenharmony_ci * Input Args: 7658c2ecf20Sopenharmony_ci * vm - Virtual Machine 7668c2ecf20Sopenharmony_ci * flags - Starting guest physical address 7678c2ecf20Sopenharmony_ci * 7688c2ecf20Sopenharmony_ci * Output Args: None 7698c2ecf20Sopenharmony_ci * 7708c2ecf20Sopenharmony_ci * Return: None 7718c2ecf20Sopenharmony_ci * 7728c2ecf20Sopenharmony_ci * Sets the flags of the memory region specified by the value of slot, 7738c2ecf20Sopenharmony_ci * to the values given by flags. 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_civoid vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci int ret; 7788c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci region = memslot2region(vm, slot); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci region->region.flags = flags; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" 7878c2ecf20Sopenharmony_ci " rc: %i errno: %i slot: %u flags: 0x%x", 7888c2ecf20Sopenharmony_ci ret, errno, slot, flags); 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci/* 7928c2ecf20Sopenharmony_ci * VM Memory Region Move 7938c2ecf20Sopenharmony_ci * 7948c2ecf20Sopenharmony_ci * Input Args: 7958c2ecf20Sopenharmony_ci * vm - Virtual Machine 7968c2ecf20Sopenharmony_ci * slot - Slot of the memory region to move 7978c2ecf20Sopenharmony_ci * new_gpa - Starting guest physical address 7988c2ecf20Sopenharmony_ci * 7998c2ecf20Sopenharmony_ci * Output Args: None 8008c2ecf20Sopenharmony_ci * 8018c2ecf20Sopenharmony_ci * Return: None 8028c2ecf20Sopenharmony_ci * 8038c2ecf20Sopenharmony_ci * Change the gpa of a memory region. 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_civoid vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 8088c2ecf20Sopenharmony_ci int ret; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci region = memslot2region(vm, slot); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci region->region.guest_phys_addr = new_gpa; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci TEST_ASSERT(!ret, "KVM_SET_USER_MEMORY_REGION failed\n" 8178c2ecf20Sopenharmony_ci "ret: %i errno: %i slot: %u new_gpa: 0x%lx", 8188c2ecf20Sopenharmony_ci ret, errno, slot, new_gpa); 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci/* 8228c2ecf20Sopenharmony_ci * VM Memory Region Delete 8238c2ecf20Sopenharmony_ci * 8248c2ecf20Sopenharmony_ci * Input Args: 8258c2ecf20Sopenharmony_ci * vm - Virtual Machine 8268c2ecf20Sopenharmony_ci * slot - Slot of the memory region to delete 8278c2ecf20Sopenharmony_ci * 8288c2ecf20Sopenharmony_ci * Output Args: None 8298c2ecf20Sopenharmony_ci * 8308c2ecf20Sopenharmony_ci * Return: None 8318c2ecf20Sopenharmony_ci * 8328c2ecf20Sopenharmony_ci * Delete a memory region. 8338c2ecf20Sopenharmony_ci */ 8348c2ecf20Sopenharmony_civoid vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci __vm_mem_region_delete(vm, memslot2region(vm, slot)); 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci/* 8408c2ecf20Sopenharmony_ci * VCPU mmap Size 8418c2ecf20Sopenharmony_ci * 8428c2ecf20Sopenharmony_ci * Input Args: None 8438c2ecf20Sopenharmony_ci * 8448c2ecf20Sopenharmony_ci * Output Args: None 8458c2ecf20Sopenharmony_ci * 8468c2ecf20Sopenharmony_ci * Return: 8478c2ecf20Sopenharmony_ci * Size of VCPU state 8488c2ecf20Sopenharmony_ci * 8498c2ecf20Sopenharmony_ci * Returns the size of the structure pointed to by the return value 8508c2ecf20Sopenharmony_ci * of vcpu_state(). 8518c2ecf20Sopenharmony_ci */ 8528c2ecf20Sopenharmony_cistatic int vcpu_mmap_sz(void) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci int dev_fd, ret; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci dev_fd = open(KVM_DEV_PATH, O_RDONLY); 8578c2ecf20Sopenharmony_ci if (dev_fd < 0) 8588c2ecf20Sopenharmony_ci exit(KSFT_SKIP); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci ret = ioctl(dev_fd, KVM_GET_VCPU_MMAP_SIZE, NULL); 8618c2ecf20Sopenharmony_ci TEST_ASSERT(ret >= sizeof(struct kvm_run), 8628c2ecf20Sopenharmony_ci "%s KVM_GET_VCPU_MMAP_SIZE ioctl failed, rc: %i errno: %i", 8638c2ecf20Sopenharmony_ci __func__, ret, errno); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci close(dev_fd); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci return ret; 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci/* 8718c2ecf20Sopenharmony_ci * VM VCPU Add 8728c2ecf20Sopenharmony_ci * 8738c2ecf20Sopenharmony_ci * Input Args: 8748c2ecf20Sopenharmony_ci * vm - Virtual Machine 8758c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 8768c2ecf20Sopenharmony_ci * 8778c2ecf20Sopenharmony_ci * Output Args: None 8788c2ecf20Sopenharmony_ci * 8798c2ecf20Sopenharmony_ci * Return: None 8808c2ecf20Sopenharmony_ci * 8818c2ecf20Sopenharmony_ci * Adds a virtual CPU to the VM specified by vm with the ID given by vcpuid. 8828c2ecf20Sopenharmony_ci * No additional VCPU setup is done. 8838c2ecf20Sopenharmony_ci */ 8848c2ecf20Sopenharmony_civoid vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct vcpu *vcpu; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* Confirm a vcpu with the specified id doesn't already exist. */ 8898c2ecf20Sopenharmony_ci vcpu = vcpu_find(vm, vcpuid); 8908c2ecf20Sopenharmony_ci if (vcpu != NULL) 8918c2ecf20Sopenharmony_ci TEST_FAIL("vcpu with the specified id " 8928c2ecf20Sopenharmony_ci "already exists,\n" 8938c2ecf20Sopenharmony_ci " requested vcpuid: %u\n" 8948c2ecf20Sopenharmony_ci " existing vcpuid: %u state: %p", 8958c2ecf20Sopenharmony_ci vcpuid, vcpu->id, vcpu->state); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* Allocate and initialize new vcpu structure. */ 8988c2ecf20Sopenharmony_ci vcpu = calloc(1, sizeof(*vcpu)); 8998c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "Insufficient Memory"); 9008c2ecf20Sopenharmony_ci vcpu->id = vcpuid; 9018c2ecf20Sopenharmony_ci vcpu->fd = ioctl(vm->fd, KVM_CREATE_VCPU, vcpuid); 9028c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu->fd >= 0, "KVM_CREATE_VCPU failed, rc: %i errno: %i", 9038c2ecf20Sopenharmony_ci vcpu->fd, errno); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->state), "vcpu mmap size " 9068c2ecf20Sopenharmony_ci "smaller than expected, vcpu_mmap_sz: %i expected_min: %zi", 9078c2ecf20Sopenharmony_ci vcpu_mmap_sz(), sizeof(*vcpu->state)); 9088c2ecf20Sopenharmony_ci vcpu->state = (struct kvm_run *) mmap(NULL, sizeof(*vcpu->state), 9098c2ecf20Sopenharmony_ci PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, 0); 9108c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu->state != MAP_FAILED, "mmap vcpu_state failed, " 9118c2ecf20Sopenharmony_ci "vcpu id: %u errno: %i", vcpuid, errno); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* Add to linked-list of VCPUs. */ 9148c2ecf20Sopenharmony_ci list_add(&vcpu->list, &vm->vcpus); 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci/* 9188c2ecf20Sopenharmony_ci * VM Virtual Address Unused Gap 9198c2ecf20Sopenharmony_ci * 9208c2ecf20Sopenharmony_ci * Input Args: 9218c2ecf20Sopenharmony_ci * vm - Virtual Machine 9228c2ecf20Sopenharmony_ci * sz - Size (bytes) 9238c2ecf20Sopenharmony_ci * vaddr_min - Minimum Virtual Address 9248c2ecf20Sopenharmony_ci * 9258c2ecf20Sopenharmony_ci * Output Args: None 9268c2ecf20Sopenharmony_ci * 9278c2ecf20Sopenharmony_ci * Return: 9288c2ecf20Sopenharmony_ci * Lowest virtual address at or below vaddr_min, with at least 9298c2ecf20Sopenharmony_ci * sz unused bytes. TEST_ASSERT failure if no area of at least 9308c2ecf20Sopenharmony_ci * size sz is available. 9318c2ecf20Sopenharmony_ci * 9328c2ecf20Sopenharmony_ci * Within the VM specified by vm, locates the lowest starting virtual 9338c2ecf20Sopenharmony_ci * address >= vaddr_min, that has at least sz unallocated bytes. A 9348c2ecf20Sopenharmony_ci * TEST_ASSERT failure occurs for invalid input or no area of at least 9358c2ecf20Sopenharmony_ci * sz unallocated bytes >= vaddr_min is available. 9368c2ecf20Sopenharmony_ci */ 9378c2ecf20Sopenharmony_cistatic vm_vaddr_t vm_vaddr_unused_gap(struct kvm_vm *vm, size_t sz, 9388c2ecf20Sopenharmony_ci vm_vaddr_t vaddr_min) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci uint64_t pages = (sz + vm->page_size - 1) >> vm->page_shift; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* Determine lowest permitted virtual page index. */ 9438c2ecf20Sopenharmony_ci uint64_t pgidx_start = (vaddr_min + vm->page_size - 1) >> vm->page_shift; 9448c2ecf20Sopenharmony_ci if ((pgidx_start * vm->page_size) < vaddr_min) 9458c2ecf20Sopenharmony_ci goto no_va_found; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* Loop over section with enough valid virtual page indexes. */ 9488c2ecf20Sopenharmony_ci if (!sparsebit_is_set_num(vm->vpages_valid, 9498c2ecf20Sopenharmony_ci pgidx_start, pages)) 9508c2ecf20Sopenharmony_ci pgidx_start = sparsebit_next_set_num(vm->vpages_valid, 9518c2ecf20Sopenharmony_ci pgidx_start, pages); 9528c2ecf20Sopenharmony_ci do { 9538c2ecf20Sopenharmony_ci /* 9548c2ecf20Sopenharmony_ci * Are there enough unused virtual pages available at 9558c2ecf20Sopenharmony_ci * the currently proposed starting virtual page index. 9568c2ecf20Sopenharmony_ci * If not, adjust proposed starting index to next 9578c2ecf20Sopenharmony_ci * possible. 9588c2ecf20Sopenharmony_ci */ 9598c2ecf20Sopenharmony_ci if (sparsebit_is_clear_num(vm->vpages_mapped, 9608c2ecf20Sopenharmony_ci pgidx_start, pages)) 9618c2ecf20Sopenharmony_ci goto va_found; 9628c2ecf20Sopenharmony_ci pgidx_start = sparsebit_next_clear_num(vm->vpages_mapped, 9638c2ecf20Sopenharmony_ci pgidx_start, pages); 9648c2ecf20Sopenharmony_ci if (pgidx_start == 0) 9658c2ecf20Sopenharmony_ci goto no_va_found; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* 9688c2ecf20Sopenharmony_ci * If needed, adjust proposed starting virtual address, 9698c2ecf20Sopenharmony_ci * to next range of valid virtual addresses. 9708c2ecf20Sopenharmony_ci */ 9718c2ecf20Sopenharmony_ci if (!sparsebit_is_set_num(vm->vpages_valid, 9728c2ecf20Sopenharmony_ci pgidx_start, pages)) { 9738c2ecf20Sopenharmony_ci pgidx_start = sparsebit_next_set_num( 9748c2ecf20Sopenharmony_ci vm->vpages_valid, pgidx_start, pages); 9758c2ecf20Sopenharmony_ci if (pgidx_start == 0) 9768c2ecf20Sopenharmony_ci goto no_va_found; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci } while (pgidx_start != 0); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cino_va_found: 9818c2ecf20Sopenharmony_ci TEST_FAIL("No vaddr of specified pages available, pages: 0x%lx", pages); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci /* NOT REACHED */ 9848c2ecf20Sopenharmony_ci return -1; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_civa_found: 9878c2ecf20Sopenharmony_ci TEST_ASSERT(sparsebit_is_set_num(vm->vpages_valid, 9888c2ecf20Sopenharmony_ci pgidx_start, pages), 9898c2ecf20Sopenharmony_ci "Unexpected, invalid virtual page index range,\n" 9908c2ecf20Sopenharmony_ci " pgidx_start: 0x%lx\n" 9918c2ecf20Sopenharmony_ci " pages: 0x%lx", 9928c2ecf20Sopenharmony_ci pgidx_start, pages); 9938c2ecf20Sopenharmony_ci TEST_ASSERT(sparsebit_is_clear_num(vm->vpages_mapped, 9948c2ecf20Sopenharmony_ci pgidx_start, pages), 9958c2ecf20Sopenharmony_ci "Unexpected, pages already mapped,\n" 9968c2ecf20Sopenharmony_ci " pgidx_start: 0x%lx\n" 9978c2ecf20Sopenharmony_ci " pages: 0x%lx", 9988c2ecf20Sopenharmony_ci pgidx_start, pages); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci return pgidx_start * vm->page_size; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci/* 10048c2ecf20Sopenharmony_ci * VM Virtual Address Allocate 10058c2ecf20Sopenharmony_ci * 10068c2ecf20Sopenharmony_ci * Input Args: 10078c2ecf20Sopenharmony_ci * vm - Virtual Machine 10088c2ecf20Sopenharmony_ci * sz - Size in bytes 10098c2ecf20Sopenharmony_ci * vaddr_min - Minimum starting virtual address 10108c2ecf20Sopenharmony_ci * data_memslot - Memory region slot for data pages 10118c2ecf20Sopenharmony_ci * pgd_memslot - Memory region slot for new virtual translation tables 10128c2ecf20Sopenharmony_ci * 10138c2ecf20Sopenharmony_ci * Output Args: None 10148c2ecf20Sopenharmony_ci * 10158c2ecf20Sopenharmony_ci * Return: 10168c2ecf20Sopenharmony_ci * Starting guest virtual address 10178c2ecf20Sopenharmony_ci * 10188c2ecf20Sopenharmony_ci * Allocates at least sz bytes within the virtual address space of the vm 10198c2ecf20Sopenharmony_ci * given by vm. The allocated bytes are mapped to a virtual address >= 10208c2ecf20Sopenharmony_ci * the address given by vaddr_min. Note that each allocation uses a 10218c2ecf20Sopenharmony_ci * a unique set of pages, with the minimum real allocation being at least 10228c2ecf20Sopenharmony_ci * a page. 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_civm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, 10258c2ecf20Sopenharmony_ci uint32_t data_memslot, uint32_t pgd_memslot) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci virt_pgd_alloc(vm, pgd_memslot); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* 10328c2ecf20Sopenharmony_ci * Find an unused range of virtual page addresses of at least 10338c2ecf20Sopenharmony_ci * pages in length. 10348c2ecf20Sopenharmony_ci */ 10358c2ecf20Sopenharmony_ci vm_vaddr_t vaddr_start = vm_vaddr_unused_gap(vm, sz, vaddr_min); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* Map the virtual pages. */ 10388c2ecf20Sopenharmony_ci for (vm_vaddr_t vaddr = vaddr_start; pages > 0; 10398c2ecf20Sopenharmony_ci pages--, vaddr += vm->page_size) { 10408c2ecf20Sopenharmony_ci vm_paddr_t paddr; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci paddr = vm_phy_page_alloc(vm, 10438c2ecf20Sopenharmony_ci KVM_UTIL_MIN_PFN * vm->page_size, data_memslot); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci virt_pg_map(vm, vaddr, paddr, pgd_memslot); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci sparsebit_set(vm->vpages_mapped, 10488c2ecf20Sopenharmony_ci vaddr >> vm->page_shift); 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci return vaddr_start; 10528c2ecf20Sopenharmony_ci} 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci/* 10558c2ecf20Sopenharmony_ci * Map a range of VM virtual address to the VM's physical address 10568c2ecf20Sopenharmony_ci * 10578c2ecf20Sopenharmony_ci * Input Args: 10588c2ecf20Sopenharmony_ci * vm - Virtual Machine 10598c2ecf20Sopenharmony_ci * vaddr - Virtuall address to map 10608c2ecf20Sopenharmony_ci * paddr - VM Physical Address 10618c2ecf20Sopenharmony_ci * npages - The number of pages to map 10628c2ecf20Sopenharmony_ci * pgd_memslot - Memory region slot for new virtual translation tables 10638c2ecf20Sopenharmony_ci * 10648c2ecf20Sopenharmony_ci * Output Args: None 10658c2ecf20Sopenharmony_ci * 10668c2ecf20Sopenharmony_ci * Return: None 10678c2ecf20Sopenharmony_ci * 10688c2ecf20Sopenharmony_ci * Within the VM given by @vm, creates a virtual translation for 10698c2ecf20Sopenharmony_ci * @npages starting at @vaddr to the page range starting at @paddr. 10708c2ecf20Sopenharmony_ci */ 10718c2ecf20Sopenharmony_civoid virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, 10728c2ecf20Sopenharmony_ci unsigned int npages, uint32_t pgd_memslot) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci size_t page_size = vm->page_size; 10758c2ecf20Sopenharmony_ci size_t size = npages * page_size; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci TEST_ASSERT(vaddr + size > vaddr, "Vaddr overflow"); 10788c2ecf20Sopenharmony_ci TEST_ASSERT(paddr + size > paddr, "Paddr overflow"); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci while (npages--) { 10818c2ecf20Sopenharmony_ci virt_pg_map(vm, vaddr, paddr, pgd_memslot); 10828c2ecf20Sopenharmony_ci vaddr += page_size; 10838c2ecf20Sopenharmony_ci paddr += page_size; 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci} 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci/* 10888c2ecf20Sopenharmony_ci * Address VM Physical to Host Virtual 10898c2ecf20Sopenharmony_ci * 10908c2ecf20Sopenharmony_ci * Input Args: 10918c2ecf20Sopenharmony_ci * vm - Virtual Machine 10928c2ecf20Sopenharmony_ci * gpa - VM physical address 10938c2ecf20Sopenharmony_ci * 10948c2ecf20Sopenharmony_ci * Output Args: None 10958c2ecf20Sopenharmony_ci * 10968c2ecf20Sopenharmony_ci * Return: 10978c2ecf20Sopenharmony_ci * Equivalent host virtual address 10988c2ecf20Sopenharmony_ci * 10998c2ecf20Sopenharmony_ci * Locates the memory region containing the VM physical address given 11008c2ecf20Sopenharmony_ci * by gpa, within the VM given by vm. When found, the host virtual 11018c2ecf20Sopenharmony_ci * address providing the memory to the vm physical address is returned. 11028c2ecf20Sopenharmony_ci * A TEST_ASSERT failure occurs if no region containing gpa exists. 11038c2ecf20Sopenharmony_ci */ 11048c2ecf20Sopenharmony_civoid *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci list_for_each_entry(region, &vm->userspace_mem_regions, list) { 11098c2ecf20Sopenharmony_ci if ((gpa >= region->region.guest_phys_addr) 11108c2ecf20Sopenharmony_ci && (gpa <= (region->region.guest_phys_addr 11118c2ecf20Sopenharmony_ci + region->region.memory_size - 1))) 11128c2ecf20Sopenharmony_ci return (void *) ((uintptr_t) region->host_mem 11138c2ecf20Sopenharmony_ci + (gpa - region->region.guest_phys_addr)); 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci TEST_FAIL("No vm physical memory at 0x%lx", gpa); 11178c2ecf20Sopenharmony_ci return NULL; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci/* 11218c2ecf20Sopenharmony_ci * Address Host Virtual to VM Physical 11228c2ecf20Sopenharmony_ci * 11238c2ecf20Sopenharmony_ci * Input Args: 11248c2ecf20Sopenharmony_ci * vm - Virtual Machine 11258c2ecf20Sopenharmony_ci * hva - Host virtual address 11268c2ecf20Sopenharmony_ci * 11278c2ecf20Sopenharmony_ci * Output Args: None 11288c2ecf20Sopenharmony_ci * 11298c2ecf20Sopenharmony_ci * Return: 11308c2ecf20Sopenharmony_ci * Equivalent VM physical address 11318c2ecf20Sopenharmony_ci * 11328c2ecf20Sopenharmony_ci * Locates the memory region containing the host virtual address given 11338c2ecf20Sopenharmony_ci * by hva, within the VM given by vm. When found, the equivalent 11348c2ecf20Sopenharmony_ci * VM physical address is returned. A TEST_ASSERT failure occurs if no 11358c2ecf20Sopenharmony_ci * region containing hva exists. 11368c2ecf20Sopenharmony_ci */ 11378c2ecf20Sopenharmony_civm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci list_for_each_entry(region, &vm->userspace_mem_regions, list) { 11428c2ecf20Sopenharmony_ci if ((hva >= region->host_mem) 11438c2ecf20Sopenharmony_ci && (hva <= (region->host_mem 11448c2ecf20Sopenharmony_ci + region->region.memory_size - 1))) 11458c2ecf20Sopenharmony_ci return (vm_paddr_t) ((uintptr_t) 11468c2ecf20Sopenharmony_ci region->region.guest_phys_addr 11478c2ecf20Sopenharmony_ci + (hva - (uintptr_t) region->host_mem)); 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci TEST_FAIL("No mapping to a guest physical address, hva: %p", hva); 11518c2ecf20Sopenharmony_ci return -1; 11528c2ecf20Sopenharmony_ci} 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci/* 11558c2ecf20Sopenharmony_ci * VM Create IRQ Chip 11568c2ecf20Sopenharmony_ci * 11578c2ecf20Sopenharmony_ci * Input Args: 11588c2ecf20Sopenharmony_ci * vm - Virtual Machine 11598c2ecf20Sopenharmony_ci * 11608c2ecf20Sopenharmony_ci * Output Args: None 11618c2ecf20Sopenharmony_ci * 11628c2ecf20Sopenharmony_ci * Return: None 11638c2ecf20Sopenharmony_ci * 11648c2ecf20Sopenharmony_ci * Creates an interrupt controller chip for the VM specified by vm. 11658c2ecf20Sopenharmony_ci */ 11668c2ecf20Sopenharmony_civoid vm_create_irqchip(struct kvm_vm *vm) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci int ret; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci ret = ioctl(vm->fd, KVM_CREATE_IRQCHIP, 0); 11718c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_CREATE_IRQCHIP IOCTL failed, " 11728c2ecf20Sopenharmony_ci "rc: %i errno: %i", ret, errno); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci vm->has_irqchip = true; 11758c2ecf20Sopenharmony_ci} 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci/* 11788c2ecf20Sopenharmony_ci * VM VCPU State 11798c2ecf20Sopenharmony_ci * 11808c2ecf20Sopenharmony_ci * Input Args: 11818c2ecf20Sopenharmony_ci * vm - Virtual Machine 11828c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 11838c2ecf20Sopenharmony_ci * 11848c2ecf20Sopenharmony_ci * Output Args: None 11858c2ecf20Sopenharmony_ci * 11868c2ecf20Sopenharmony_ci * Return: 11878c2ecf20Sopenharmony_ci * Pointer to structure that describes the state of the VCPU. 11888c2ecf20Sopenharmony_ci * 11898c2ecf20Sopenharmony_ci * Locates and returns a pointer to a structure that describes the 11908c2ecf20Sopenharmony_ci * state of the VCPU with the given vcpuid. 11918c2ecf20Sopenharmony_ci */ 11928c2ecf20Sopenharmony_cistruct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 11958c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci return vcpu->state; 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci/* 12018c2ecf20Sopenharmony_ci * VM VCPU Run 12028c2ecf20Sopenharmony_ci * 12038c2ecf20Sopenharmony_ci * Input Args: 12048c2ecf20Sopenharmony_ci * vm - Virtual Machine 12058c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 12068c2ecf20Sopenharmony_ci * 12078c2ecf20Sopenharmony_ci * Output Args: None 12088c2ecf20Sopenharmony_ci * 12098c2ecf20Sopenharmony_ci * Return: None 12108c2ecf20Sopenharmony_ci * 12118c2ecf20Sopenharmony_ci * Switch to executing the code for the VCPU given by vcpuid, within the VM 12128c2ecf20Sopenharmony_ci * given by vm. 12138c2ecf20Sopenharmony_ci */ 12148c2ecf20Sopenharmony_civoid vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) 12158c2ecf20Sopenharmony_ci{ 12168c2ecf20Sopenharmony_ci int ret = _vcpu_run(vm, vcpuid); 12178c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " 12188c2ecf20Sopenharmony_ci "rc: %i errno: %i", ret, errno); 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ciint _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 12248c2ecf20Sopenharmony_ci int rc; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 12278c2ecf20Sopenharmony_ci do { 12288c2ecf20Sopenharmony_ci rc = ioctl(vcpu->fd, KVM_RUN, NULL); 12298c2ecf20Sopenharmony_ci } while (rc == -1 && errno == EINTR); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci assert_on_unhandled_exception(vm, vcpuid); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci return rc; 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_civoid vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 12398c2ecf20Sopenharmony_ci int ret; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci vcpu->state->immediate_exit = 1; 12448c2ecf20Sopenharmony_ci ret = ioctl(vcpu->fd, KVM_RUN, NULL); 12458c2ecf20Sopenharmony_ci vcpu->state->immediate_exit = 0; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci TEST_ASSERT(ret == -1 && errno == EINTR, 12488c2ecf20Sopenharmony_ci "KVM_RUN IOCTL didn't exit immediately, rc: %i, errno: %i", 12498c2ecf20Sopenharmony_ci ret, errno); 12508c2ecf20Sopenharmony_ci} 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_civoid vcpu_set_guest_debug(struct kvm_vm *vm, uint32_t vcpuid, 12538c2ecf20Sopenharmony_ci struct kvm_guest_debug *debug) 12548c2ecf20Sopenharmony_ci{ 12558c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 12568c2ecf20Sopenharmony_ci int ret = ioctl(vcpu->fd, KVM_SET_GUEST_DEBUG, debug); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_SET_GUEST_DEBUG failed: %d", ret); 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci/* 12628c2ecf20Sopenharmony_ci * VM VCPU Set MP State 12638c2ecf20Sopenharmony_ci * 12648c2ecf20Sopenharmony_ci * Input Args: 12658c2ecf20Sopenharmony_ci * vm - Virtual Machine 12668c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 12678c2ecf20Sopenharmony_ci * mp_state - mp_state to be set 12688c2ecf20Sopenharmony_ci * 12698c2ecf20Sopenharmony_ci * Output Args: None 12708c2ecf20Sopenharmony_ci * 12718c2ecf20Sopenharmony_ci * Return: None 12728c2ecf20Sopenharmony_ci * 12738c2ecf20Sopenharmony_ci * Sets the MP state of the VCPU given by vcpuid, to the state given 12748c2ecf20Sopenharmony_ci * by mp_state. 12758c2ecf20Sopenharmony_ci */ 12768c2ecf20Sopenharmony_civoid vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, 12778c2ecf20Sopenharmony_ci struct kvm_mp_state *mp_state) 12788c2ecf20Sopenharmony_ci{ 12798c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 12808c2ecf20Sopenharmony_ci int ret; 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci ret = ioctl(vcpu->fd, KVM_SET_MP_STATE, mp_state); 12858c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_SET_MP_STATE IOCTL failed, " 12868c2ecf20Sopenharmony_ci "rc: %i errno: %i", ret, errno); 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci/* 12908c2ecf20Sopenharmony_ci * VM VCPU Get Reg List 12918c2ecf20Sopenharmony_ci * 12928c2ecf20Sopenharmony_ci * Input Args: 12938c2ecf20Sopenharmony_ci * vm - Virtual Machine 12948c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 12958c2ecf20Sopenharmony_ci * 12968c2ecf20Sopenharmony_ci * Output Args: 12978c2ecf20Sopenharmony_ci * None 12988c2ecf20Sopenharmony_ci * 12998c2ecf20Sopenharmony_ci * Return: 13008c2ecf20Sopenharmony_ci * A pointer to an allocated struct kvm_reg_list 13018c2ecf20Sopenharmony_ci * 13028c2ecf20Sopenharmony_ci * Get the list of guest registers which are supported for 13038c2ecf20Sopenharmony_ci * KVM_GET_ONE_REG/KVM_SET_ONE_REG calls 13048c2ecf20Sopenharmony_ci */ 13058c2ecf20Sopenharmony_cistruct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci struct kvm_reg_list reg_list_n = { .n = 0 }, *reg_list; 13088c2ecf20Sopenharmony_ci int ret; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci ret = _vcpu_ioctl(vm, vcpuid, KVM_GET_REG_LIST, ®_list_n); 13118c2ecf20Sopenharmony_ci TEST_ASSERT(ret == -1 && errno == E2BIG, "KVM_GET_REG_LIST n=0"); 13128c2ecf20Sopenharmony_ci reg_list = calloc(1, sizeof(*reg_list) + reg_list_n.n * sizeof(__u64)); 13138c2ecf20Sopenharmony_ci reg_list->n = reg_list_n.n; 13148c2ecf20Sopenharmony_ci vcpu_ioctl(vm, vcpuid, KVM_GET_REG_LIST, reg_list); 13158c2ecf20Sopenharmony_ci return reg_list; 13168c2ecf20Sopenharmony_ci} 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci/* 13198c2ecf20Sopenharmony_ci * VM VCPU Regs Get 13208c2ecf20Sopenharmony_ci * 13218c2ecf20Sopenharmony_ci * Input Args: 13228c2ecf20Sopenharmony_ci * vm - Virtual Machine 13238c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 13248c2ecf20Sopenharmony_ci * 13258c2ecf20Sopenharmony_ci * Output Args: 13268c2ecf20Sopenharmony_ci * regs - current state of VCPU regs 13278c2ecf20Sopenharmony_ci * 13288c2ecf20Sopenharmony_ci * Return: None 13298c2ecf20Sopenharmony_ci * 13308c2ecf20Sopenharmony_ci * Obtains the current register state for the VCPU specified by vcpuid 13318c2ecf20Sopenharmony_ci * and stores it at the location given by regs. 13328c2ecf20Sopenharmony_ci */ 13338c2ecf20Sopenharmony_civoid vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 13368c2ecf20Sopenharmony_ci int ret; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci ret = ioctl(vcpu->fd, KVM_GET_REGS, regs); 13418c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_GET_REGS failed, rc: %i errno: %i", 13428c2ecf20Sopenharmony_ci ret, errno); 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci/* 13468c2ecf20Sopenharmony_ci * VM VCPU Regs Set 13478c2ecf20Sopenharmony_ci * 13488c2ecf20Sopenharmony_ci * Input Args: 13498c2ecf20Sopenharmony_ci * vm - Virtual Machine 13508c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 13518c2ecf20Sopenharmony_ci * regs - Values to set VCPU regs to 13528c2ecf20Sopenharmony_ci * 13538c2ecf20Sopenharmony_ci * Output Args: None 13548c2ecf20Sopenharmony_ci * 13558c2ecf20Sopenharmony_ci * Return: None 13568c2ecf20Sopenharmony_ci * 13578c2ecf20Sopenharmony_ci * Sets the regs of the VCPU specified by vcpuid to the values 13588c2ecf20Sopenharmony_ci * given by regs. 13598c2ecf20Sopenharmony_ci */ 13608c2ecf20Sopenharmony_civoid vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 13638c2ecf20Sopenharmony_ci int ret; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci ret = ioctl(vcpu->fd, KVM_SET_REGS, regs); 13688c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_SET_REGS failed, rc: %i errno: %i", 13698c2ecf20Sopenharmony_ci ret, errno); 13708c2ecf20Sopenharmony_ci} 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci#ifdef __KVM_HAVE_VCPU_EVENTS 13738c2ecf20Sopenharmony_civoid vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, 13748c2ecf20Sopenharmony_ci struct kvm_vcpu_events *events) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 13778c2ecf20Sopenharmony_ci int ret; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci ret = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, events); 13828c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_GET_VCPU_EVENTS, failed, rc: %i errno: %i", 13838c2ecf20Sopenharmony_ci ret, errno); 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_civoid vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, 13878c2ecf20Sopenharmony_ci struct kvm_vcpu_events *events) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 13908c2ecf20Sopenharmony_ci int ret; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci ret = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, events); 13958c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i", 13968c2ecf20Sopenharmony_ci ret, errno); 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci#endif 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci#ifdef __x86_64__ 14018c2ecf20Sopenharmony_civoid vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid, 14028c2ecf20Sopenharmony_ci struct kvm_nested_state *state) 14038c2ecf20Sopenharmony_ci{ 14048c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 14058c2ecf20Sopenharmony_ci int ret; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci ret = ioctl(vcpu->fd, KVM_GET_NESTED_STATE, state); 14108c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, 14118c2ecf20Sopenharmony_ci "KVM_SET_NESTED_STATE failed, ret: %i errno: %i", 14128c2ecf20Sopenharmony_ci ret, errno); 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ciint vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, 14168c2ecf20Sopenharmony_ci struct kvm_nested_state *state, bool ignore_error) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 14198c2ecf20Sopenharmony_ci int ret; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci ret = ioctl(vcpu->fd, KVM_SET_NESTED_STATE, state); 14248c2ecf20Sopenharmony_ci if (!ignore_error) { 14258c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, 14268c2ecf20Sopenharmony_ci "KVM_SET_NESTED_STATE failed, ret: %i errno: %i", 14278c2ecf20Sopenharmony_ci ret, errno); 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci return ret; 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci#endif 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci/* 14358c2ecf20Sopenharmony_ci * VM VCPU System Regs Get 14368c2ecf20Sopenharmony_ci * 14378c2ecf20Sopenharmony_ci * Input Args: 14388c2ecf20Sopenharmony_ci * vm - Virtual Machine 14398c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 14408c2ecf20Sopenharmony_ci * 14418c2ecf20Sopenharmony_ci * Output Args: 14428c2ecf20Sopenharmony_ci * sregs - current state of VCPU system regs 14438c2ecf20Sopenharmony_ci * 14448c2ecf20Sopenharmony_ci * Return: None 14458c2ecf20Sopenharmony_ci * 14468c2ecf20Sopenharmony_ci * Obtains the current system register state for the VCPU specified by 14478c2ecf20Sopenharmony_ci * vcpuid and stores it at the location given by sregs. 14488c2ecf20Sopenharmony_ci */ 14498c2ecf20Sopenharmony_civoid vcpu_sregs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 14528c2ecf20Sopenharmony_ci int ret; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci ret = ioctl(vcpu->fd, KVM_GET_SREGS, sregs); 14578c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_GET_SREGS failed, rc: %i errno: %i", 14588c2ecf20Sopenharmony_ci ret, errno); 14598c2ecf20Sopenharmony_ci} 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci/* 14628c2ecf20Sopenharmony_ci * VM VCPU System Regs Set 14638c2ecf20Sopenharmony_ci * 14648c2ecf20Sopenharmony_ci * Input Args: 14658c2ecf20Sopenharmony_ci * vm - Virtual Machine 14668c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 14678c2ecf20Sopenharmony_ci * sregs - Values to set VCPU system regs to 14688c2ecf20Sopenharmony_ci * 14698c2ecf20Sopenharmony_ci * Output Args: None 14708c2ecf20Sopenharmony_ci * 14718c2ecf20Sopenharmony_ci * Return: None 14728c2ecf20Sopenharmony_ci * 14738c2ecf20Sopenharmony_ci * Sets the system regs of the VCPU specified by vcpuid to the values 14748c2ecf20Sopenharmony_ci * given by sregs. 14758c2ecf20Sopenharmony_ci */ 14768c2ecf20Sopenharmony_civoid vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci int ret = _vcpu_sregs_set(vm, vcpuid, sregs); 14798c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " 14808c2ecf20Sopenharmony_ci "rc: %i errno: %i", ret, errno); 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ciint _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) 14848c2ecf20Sopenharmony_ci{ 14858c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); 14908c2ecf20Sopenharmony_ci} 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_civoid vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_fpu *fpu) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci int ret; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci ret = _vcpu_ioctl(vm, vcpuid, KVM_GET_FPU, fpu); 14978c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_GET_FPU failed, rc: %i errno: %i (%s)", 14988c2ecf20Sopenharmony_ci ret, errno, strerror(errno)); 14998c2ecf20Sopenharmony_ci} 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_civoid vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_fpu *fpu) 15028c2ecf20Sopenharmony_ci{ 15038c2ecf20Sopenharmony_ci int ret; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_FPU, fpu); 15068c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_SET_FPU failed, rc: %i errno: %i (%s)", 15078c2ecf20Sopenharmony_ci ret, errno, strerror(errno)); 15088c2ecf20Sopenharmony_ci} 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_civoid vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci int ret; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci ret = _vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, reg); 15158c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_GET_ONE_REG failed, rc: %i errno: %i (%s)", 15168c2ecf20Sopenharmony_ci ret, errno, strerror(errno)); 15178c2ecf20Sopenharmony_ci} 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_civoid vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci int ret; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, reg); 15248c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "KVM_SET_ONE_REG failed, rc: %i errno: %i (%s)", 15258c2ecf20Sopenharmony_ci ret, errno, strerror(errno)); 15268c2ecf20Sopenharmony_ci} 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci/* 15298c2ecf20Sopenharmony_ci * VCPU Ioctl 15308c2ecf20Sopenharmony_ci * 15318c2ecf20Sopenharmony_ci * Input Args: 15328c2ecf20Sopenharmony_ci * vm - Virtual Machine 15338c2ecf20Sopenharmony_ci * vcpuid - VCPU ID 15348c2ecf20Sopenharmony_ci * cmd - Ioctl number 15358c2ecf20Sopenharmony_ci * arg - Argument to pass to the ioctl 15368c2ecf20Sopenharmony_ci * 15378c2ecf20Sopenharmony_ci * Return: None 15388c2ecf20Sopenharmony_ci * 15398c2ecf20Sopenharmony_ci * Issues an arbitrary ioctl on a VCPU fd. 15408c2ecf20Sopenharmony_ci */ 15418c2ecf20Sopenharmony_civoid vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, 15428c2ecf20Sopenharmony_ci unsigned long cmd, void *arg) 15438c2ecf20Sopenharmony_ci{ 15448c2ecf20Sopenharmony_ci int ret; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci ret = _vcpu_ioctl(vm, vcpuid, cmd, arg); 15478c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "vcpu ioctl %lu failed, rc: %i errno: %i (%s)", 15488c2ecf20Sopenharmony_ci cmd, ret, errno, strerror(errno)); 15498c2ecf20Sopenharmony_ci} 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ciint _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, 15528c2ecf20Sopenharmony_ci unsigned long cmd, void *arg) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci struct vcpu *vcpu = vcpu_find(vm, vcpuid); 15558c2ecf20Sopenharmony_ci int ret; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci ret = ioctl(vcpu->fd, cmd, arg); 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci return ret; 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci/* 15658c2ecf20Sopenharmony_ci * VM Ioctl 15668c2ecf20Sopenharmony_ci * 15678c2ecf20Sopenharmony_ci * Input Args: 15688c2ecf20Sopenharmony_ci * vm - Virtual Machine 15698c2ecf20Sopenharmony_ci * cmd - Ioctl number 15708c2ecf20Sopenharmony_ci * arg - Argument to pass to the ioctl 15718c2ecf20Sopenharmony_ci * 15728c2ecf20Sopenharmony_ci * Return: None 15738c2ecf20Sopenharmony_ci * 15748c2ecf20Sopenharmony_ci * Issues an arbitrary ioctl on a VM fd. 15758c2ecf20Sopenharmony_ci */ 15768c2ecf20Sopenharmony_civoid vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) 15778c2ecf20Sopenharmony_ci{ 15788c2ecf20Sopenharmony_ci int ret; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci ret = ioctl(vm->fd, cmd, arg); 15818c2ecf20Sopenharmony_ci TEST_ASSERT(ret == 0, "vm ioctl %lu failed, rc: %i errno: %i (%s)", 15828c2ecf20Sopenharmony_ci cmd, ret, errno, strerror(errno)); 15838c2ecf20Sopenharmony_ci} 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci/* 15868c2ecf20Sopenharmony_ci * VM Dump 15878c2ecf20Sopenharmony_ci * 15888c2ecf20Sopenharmony_ci * Input Args: 15898c2ecf20Sopenharmony_ci * vm - Virtual Machine 15908c2ecf20Sopenharmony_ci * indent - Left margin indent amount 15918c2ecf20Sopenharmony_ci * 15928c2ecf20Sopenharmony_ci * Output Args: 15938c2ecf20Sopenharmony_ci * stream - Output FILE stream 15948c2ecf20Sopenharmony_ci * 15958c2ecf20Sopenharmony_ci * Return: None 15968c2ecf20Sopenharmony_ci * 15978c2ecf20Sopenharmony_ci * Dumps the current state of the VM given by vm, to the FILE stream 15988c2ecf20Sopenharmony_ci * given by stream. 15998c2ecf20Sopenharmony_ci */ 16008c2ecf20Sopenharmony_civoid vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 16038c2ecf20Sopenharmony_ci struct vcpu *vcpu; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci fprintf(stream, "%*smode: 0x%x\n", indent, "", vm->mode); 16068c2ecf20Sopenharmony_ci fprintf(stream, "%*sfd: %i\n", indent, "", vm->fd); 16078c2ecf20Sopenharmony_ci fprintf(stream, "%*spage_size: 0x%x\n", indent, "", vm->page_size); 16088c2ecf20Sopenharmony_ci fprintf(stream, "%*sMem Regions:\n", indent, ""); 16098c2ecf20Sopenharmony_ci list_for_each_entry(region, &vm->userspace_mem_regions, list) { 16108c2ecf20Sopenharmony_ci fprintf(stream, "%*sguest_phys: 0x%lx size: 0x%lx " 16118c2ecf20Sopenharmony_ci "host_virt: %p\n", indent + 2, "", 16128c2ecf20Sopenharmony_ci (uint64_t) region->region.guest_phys_addr, 16138c2ecf20Sopenharmony_ci (uint64_t) region->region.memory_size, 16148c2ecf20Sopenharmony_ci region->host_mem); 16158c2ecf20Sopenharmony_ci fprintf(stream, "%*sunused_phy_pages: ", indent + 2, ""); 16168c2ecf20Sopenharmony_ci sparsebit_dump(stream, region->unused_phy_pages, 0); 16178c2ecf20Sopenharmony_ci } 16188c2ecf20Sopenharmony_ci fprintf(stream, "%*sMapped Virtual Pages:\n", indent, ""); 16198c2ecf20Sopenharmony_ci sparsebit_dump(stream, vm->vpages_mapped, indent + 2); 16208c2ecf20Sopenharmony_ci fprintf(stream, "%*spgd_created: %u\n", indent, "", 16218c2ecf20Sopenharmony_ci vm->pgd_created); 16228c2ecf20Sopenharmony_ci if (vm->pgd_created) { 16238c2ecf20Sopenharmony_ci fprintf(stream, "%*sVirtual Translation Tables:\n", 16248c2ecf20Sopenharmony_ci indent + 2, ""); 16258c2ecf20Sopenharmony_ci virt_dump(stream, vm, indent + 4); 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci fprintf(stream, "%*sVCPUs:\n", indent, ""); 16288c2ecf20Sopenharmony_ci list_for_each_entry(vcpu, &vm->vcpus, list) 16298c2ecf20Sopenharmony_ci vcpu_dump(stream, vm, vcpu->id, indent + 2); 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci/* Known KVM exit reasons */ 16338c2ecf20Sopenharmony_cistatic struct exit_reason { 16348c2ecf20Sopenharmony_ci unsigned int reason; 16358c2ecf20Sopenharmony_ci const char *name; 16368c2ecf20Sopenharmony_ci} exit_reasons_known[] = { 16378c2ecf20Sopenharmony_ci {KVM_EXIT_UNKNOWN, "UNKNOWN"}, 16388c2ecf20Sopenharmony_ci {KVM_EXIT_EXCEPTION, "EXCEPTION"}, 16398c2ecf20Sopenharmony_ci {KVM_EXIT_IO, "IO"}, 16408c2ecf20Sopenharmony_ci {KVM_EXIT_HYPERCALL, "HYPERCALL"}, 16418c2ecf20Sopenharmony_ci {KVM_EXIT_DEBUG, "DEBUG"}, 16428c2ecf20Sopenharmony_ci {KVM_EXIT_HLT, "HLT"}, 16438c2ecf20Sopenharmony_ci {KVM_EXIT_MMIO, "MMIO"}, 16448c2ecf20Sopenharmony_ci {KVM_EXIT_IRQ_WINDOW_OPEN, "IRQ_WINDOW_OPEN"}, 16458c2ecf20Sopenharmony_ci {KVM_EXIT_SHUTDOWN, "SHUTDOWN"}, 16468c2ecf20Sopenharmony_ci {KVM_EXIT_FAIL_ENTRY, "FAIL_ENTRY"}, 16478c2ecf20Sopenharmony_ci {KVM_EXIT_INTR, "INTR"}, 16488c2ecf20Sopenharmony_ci {KVM_EXIT_SET_TPR, "SET_TPR"}, 16498c2ecf20Sopenharmony_ci {KVM_EXIT_TPR_ACCESS, "TPR_ACCESS"}, 16508c2ecf20Sopenharmony_ci {KVM_EXIT_S390_SIEIC, "S390_SIEIC"}, 16518c2ecf20Sopenharmony_ci {KVM_EXIT_S390_RESET, "S390_RESET"}, 16528c2ecf20Sopenharmony_ci {KVM_EXIT_DCR, "DCR"}, 16538c2ecf20Sopenharmony_ci {KVM_EXIT_NMI, "NMI"}, 16548c2ecf20Sopenharmony_ci {KVM_EXIT_INTERNAL_ERROR, "INTERNAL_ERROR"}, 16558c2ecf20Sopenharmony_ci {KVM_EXIT_OSI, "OSI"}, 16568c2ecf20Sopenharmony_ci {KVM_EXIT_PAPR_HCALL, "PAPR_HCALL"}, 16578c2ecf20Sopenharmony_ci#ifdef KVM_EXIT_MEMORY_NOT_PRESENT 16588c2ecf20Sopenharmony_ci {KVM_EXIT_MEMORY_NOT_PRESENT, "MEMORY_NOT_PRESENT"}, 16598c2ecf20Sopenharmony_ci#endif 16608c2ecf20Sopenharmony_ci}; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci/* 16638c2ecf20Sopenharmony_ci * Exit Reason String 16648c2ecf20Sopenharmony_ci * 16658c2ecf20Sopenharmony_ci * Input Args: 16668c2ecf20Sopenharmony_ci * exit_reason - Exit reason 16678c2ecf20Sopenharmony_ci * 16688c2ecf20Sopenharmony_ci * Output Args: None 16698c2ecf20Sopenharmony_ci * 16708c2ecf20Sopenharmony_ci * Return: 16718c2ecf20Sopenharmony_ci * Constant string pointer describing the exit reason. 16728c2ecf20Sopenharmony_ci * 16738c2ecf20Sopenharmony_ci * Locates and returns a constant string that describes the KVM exit 16748c2ecf20Sopenharmony_ci * reason given by exit_reason. If no such string is found, a constant 16758c2ecf20Sopenharmony_ci * string of "Unknown" is returned. 16768c2ecf20Sopenharmony_ci */ 16778c2ecf20Sopenharmony_ciconst char *exit_reason_str(unsigned int exit_reason) 16788c2ecf20Sopenharmony_ci{ 16798c2ecf20Sopenharmony_ci unsigned int n1; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci for (n1 = 0; n1 < ARRAY_SIZE(exit_reasons_known); n1++) { 16828c2ecf20Sopenharmony_ci if (exit_reason == exit_reasons_known[n1].reason) 16838c2ecf20Sopenharmony_ci return exit_reasons_known[n1].name; 16848c2ecf20Sopenharmony_ci } 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci return "Unknown"; 16878c2ecf20Sopenharmony_ci} 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci/* 16908c2ecf20Sopenharmony_ci * Physical Contiguous Page Allocator 16918c2ecf20Sopenharmony_ci * 16928c2ecf20Sopenharmony_ci * Input Args: 16938c2ecf20Sopenharmony_ci * vm - Virtual Machine 16948c2ecf20Sopenharmony_ci * num - number of pages 16958c2ecf20Sopenharmony_ci * paddr_min - Physical address minimum 16968c2ecf20Sopenharmony_ci * memslot - Memory region to allocate page from 16978c2ecf20Sopenharmony_ci * 16988c2ecf20Sopenharmony_ci * Output Args: None 16998c2ecf20Sopenharmony_ci * 17008c2ecf20Sopenharmony_ci * Return: 17018c2ecf20Sopenharmony_ci * Starting physical address 17028c2ecf20Sopenharmony_ci * 17038c2ecf20Sopenharmony_ci * Within the VM specified by vm, locates a range of available physical 17048c2ecf20Sopenharmony_ci * pages at or above paddr_min. If found, the pages are marked as in use 17058c2ecf20Sopenharmony_ci * and their base address is returned. A TEST_ASSERT failure occurs if 17068c2ecf20Sopenharmony_ci * not enough pages are available at or above paddr_min. 17078c2ecf20Sopenharmony_ci */ 17088c2ecf20Sopenharmony_civm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, 17098c2ecf20Sopenharmony_ci vm_paddr_t paddr_min, uint32_t memslot) 17108c2ecf20Sopenharmony_ci{ 17118c2ecf20Sopenharmony_ci struct userspace_mem_region *region; 17128c2ecf20Sopenharmony_ci sparsebit_idx_t pg, base; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci TEST_ASSERT(num > 0, "Must allocate at least one page"); 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci TEST_ASSERT((paddr_min % vm->page_size) == 0, "Min physical address " 17178c2ecf20Sopenharmony_ci "not divisible by page size.\n" 17188c2ecf20Sopenharmony_ci " paddr_min: 0x%lx page_size: 0x%x", 17198c2ecf20Sopenharmony_ci paddr_min, vm->page_size); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci region = memslot2region(vm, memslot); 17228c2ecf20Sopenharmony_ci base = pg = paddr_min >> vm->page_shift; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci do { 17258c2ecf20Sopenharmony_ci for (; pg < base + num; ++pg) { 17268c2ecf20Sopenharmony_ci if (!sparsebit_is_set(region->unused_phy_pages, pg)) { 17278c2ecf20Sopenharmony_ci base = pg = sparsebit_next_set(region->unused_phy_pages, pg); 17288c2ecf20Sopenharmony_ci break; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci } while (pg && pg != base + num); 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci if (pg == 0) { 17348c2ecf20Sopenharmony_ci fprintf(stderr, "No guest physical page available, " 17358c2ecf20Sopenharmony_ci "paddr_min: 0x%lx page_size: 0x%x memslot: %u\n", 17368c2ecf20Sopenharmony_ci paddr_min, vm->page_size, memslot); 17378c2ecf20Sopenharmony_ci fputs("---- vm dump ----\n", stderr); 17388c2ecf20Sopenharmony_ci vm_dump(stderr, vm, 2); 17398c2ecf20Sopenharmony_ci abort(); 17408c2ecf20Sopenharmony_ci } 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci for (pg = base; pg < base + num; ++pg) 17438c2ecf20Sopenharmony_ci sparsebit_clear(region->unused_phy_pages, pg); 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci return base * vm->page_size; 17468c2ecf20Sopenharmony_ci} 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_civm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, 17498c2ecf20Sopenharmony_ci uint32_t memslot) 17508c2ecf20Sopenharmony_ci{ 17518c2ecf20Sopenharmony_ci return vm_phy_pages_alloc(vm, 1, paddr_min, memslot); 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci/* 17558c2ecf20Sopenharmony_ci * Address Guest Virtual to Host Virtual 17568c2ecf20Sopenharmony_ci * 17578c2ecf20Sopenharmony_ci * Input Args: 17588c2ecf20Sopenharmony_ci * vm - Virtual Machine 17598c2ecf20Sopenharmony_ci * gva - VM virtual address 17608c2ecf20Sopenharmony_ci * 17618c2ecf20Sopenharmony_ci * Output Args: None 17628c2ecf20Sopenharmony_ci * 17638c2ecf20Sopenharmony_ci * Return: 17648c2ecf20Sopenharmony_ci * Equivalent host virtual address 17658c2ecf20Sopenharmony_ci */ 17668c2ecf20Sopenharmony_civoid *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva) 17678c2ecf20Sopenharmony_ci{ 17688c2ecf20Sopenharmony_ci return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); 17698c2ecf20Sopenharmony_ci} 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci/* 17728c2ecf20Sopenharmony_ci * Is Unrestricted Guest 17738c2ecf20Sopenharmony_ci * 17748c2ecf20Sopenharmony_ci * Input Args: 17758c2ecf20Sopenharmony_ci * vm - Virtual Machine 17768c2ecf20Sopenharmony_ci * 17778c2ecf20Sopenharmony_ci * Output Args: None 17788c2ecf20Sopenharmony_ci * 17798c2ecf20Sopenharmony_ci * Return: True if the unrestricted guest is set to 'Y', otherwise return false. 17808c2ecf20Sopenharmony_ci * 17818c2ecf20Sopenharmony_ci * Check if the unrestricted guest flag is enabled. 17828c2ecf20Sopenharmony_ci */ 17838c2ecf20Sopenharmony_cibool vm_is_unrestricted_guest(struct kvm_vm *vm) 17848c2ecf20Sopenharmony_ci{ 17858c2ecf20Sopenharmony_ci char val = 'N'; 17868c2ecf20Sopenharmony_ci size_t count; 17878c2ecf20Sopenharmony_ci FILE *f; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci if (vm == NULL) { 17908c2ecf20Sopenharmony_ci /* Ensure that the KVM vendor-specific module is loaded. */ 17918c2ecf20Sopenharmony_ci f = fopen(KVM_DEV_PATH, "r"); 17928c2ecf20Sopenharmony_ci TEST_ASSERT(f != NULL, "Error in opening KVM dev file: %d", 17938c2ecf20Sopenharmony_ci errno); 17948c2ecf20Sopenharmony_ci fclose(f); 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci f = fopen("/sys/module/kvm_intel/parameters/unrestricted_guest", "r"); 17988c2ecf20Sopenharmony_ci if (f) { 17998c2ecf20Sopenharmony_ci count = fread(&val, sizeof(char), 1, f); 18008c2ecf20Sopenharmony_ci TEST_ASSERT(count == 1, "Unable to read from param file."); 18018c2ecf20Sopenharmony_ci fclose(f); 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci return val == 'Y'; 18058c2ecf20Sopenharmony_ci} 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ciunsigned int vm_get_page_size(struct kvm_vm *vm) 18088c2ecf20Sopenharmony_ci{ 18098c2ecf20Sopenharmony_ci return vm->page_size; 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ciunsigned int vm_get_page_shift(struct kvm_vm *vm) 18138c2ecf20Sopenharmony_ci{ 18148c2ecf20Sopenharmony_ci return vm->page_shift; 18158c2ecf20Sopenharmony_ci} 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ciunsigned int vm_get_max_gfn(struct kvm_vm *vm) 18188c2ecf20Sopenharmony_ci{ 18198c2ecf20Sopenharmony_ci return vm->max_gfn; 18208c2ecf20Sopenharmony_ci} 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ciint vm_get_fd(struct kvm_vm *vm) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci return vm->fd; 18258c2ecf20Sopenharmony_ci} 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_cistatic unsigned int vm_calc_num_pages(unsigned int num_pages, 18288c2ecf20Sopenharmony_ci unsigned int page_shift, 18298c2ecf20Sopenharmony_ci unsigned int new_page_shift, 18308c2ecf20Sopenharmony_ci bool ceil) 18318c2ecf20Sopenharmony_ci{ 18328c2ecf20Sopenharmony_ci unsigned int n = 1 << (new_page_shift - page_shift); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci if (page_shift >= new_page_shift) 18358c2ecf20Sopenharmony_ci return num_pages * (1 << (page_shift - new_page_shift)); 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci return num_pages / n + !!(ceil && num_pages % n); 18388c2ecf20Sopenharmony_ci} 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_cistatic inline int getpageshift(void) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci return __builtin_ffs(getpagesize()) - 1; 18438c2ecf20Sopenharmony_ci} 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ciunsigned int 18468c2ecf20Sopenharmony_civm_num_host_pages(enum vm_guest_mode mode, unsigned int num_guest_pages) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci return vm_calc_num_pages(num_guest_pages, 18498c2ecf20Sopenharmony_ci vm_guest_mode_params[mode].page_shift, 18508c2ecf20Sopenharmony_ci getpageshift(), true); 18518c2ecf20Sopenharmony_ci} 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ciunsigned int 18548c2ecf20Sopenharmony_civm_num_guest_pages(enum vm_guest_mode mode, unsigned int num_host_pages) 18558c2ecf20Sopenharmony_ci{ 18568c2ecf20Sopenharmony_ci return vm_calc_num_pages(num_host_pages, getpageshift(), 18578c2ecf20Sopenharmony_ci vm_guest_mode_params[mode].page_shift, false); 18588c2ecf20Sopenharmony_ci} 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ciunsigned int vm_calc_num_guest_pages(enum vm_guest_mode mode, size_t size) 18618c2ecf20Sopenharmony_ci{ 18628c2ecf20Sopenharmony_ci unsigned int n; 18638c2ecf20Sopenharmony_ci n = DIV_ROUND_UP(size, vm_guest_mode_params[mode].page_size); 18648c2ecf20Sopenharmony_ci return vm_adjust_num_guest_pages(mode, n); 18658c2ecf20Sopenharmony_ci} 1866