diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2026-10-16 10:00:21 +0200 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2026-10-16 10:55:33 +0200 |
| commit | 994489f04ebbb56fabcc132d981f0549c6e45be3 (patch) | |
| tree | 85e587407b7143c9cce552cb1153a56b7eacc3af | |
| parent | 7930afcf146df456d9ba17cf11d8269955c694cf (diff) | |
| parent | bef953c069806148ae2f10714b39a08726c9a076 (diff) | |
Merge tag 'kvm-x86-selftests-7.4' of https://github.com/kvm-x86/linux into HEAD
KVM selftests changes and a few KVM x86 fixes for 7.4
- Fix emulation of VMPTRST and VMPTRLD when eVMCS is in-use to match real
Hyper-V's behavior.
- Saturate L2's TSC frequency if stacking L1 and L2 scaling multipliers
exceeds what hardware supports, as attempting to run L2 with an illegal
multiplier will either cause VM-Entry to fail (VMX) or trigger a #GP when
writing MSR_AMD64_TSC_RATIO (SVM). The #GP is thankfully benign in the
grand scheme as even "unsafe" WRMSRs have exception fixup.
- Rework KVM selftest's handling of memory regions so that PPC can force its
page table allocations to be naturally aligned.
- Clean up selftest's VMX instruction helpers, and drop an absurd number of
completely useless return values, e.g. functions that unconditionally
return %true and then have every caller assert success.
- Add selftests support for Zhaoxin CPUs.
- Overhaul the TSC scaling test to add a regression test for the saturation
behavior, and to increase its coverage in general.
- Fix selftests usage various NUMA syscalls to account for an undocumented,
but known since 2007, off-by-one kernel bug. Add helpers to try and avoid
re-introducing the same flaws in the future.
- Automatically run xAPIC IPI migration test (between NUMA nodes) when
possible, as the entire point of the test is verify KVM's handling of page
migration of the APIC backing page.
- Misc cleanups.
70 files changed, 1049 insertions, 957 deletions
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 3b96a4f63637..fd6264f003a4 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -533,6 +533,15 @@ static int svm_check_processor_compat(void) static void __svm_write_tsc_multiplier(u64 multiplier) { + /* + * Fallback to the default ratio if KVM is buggy and tries to program + * an unsupported scaling ratio, e.g. so that the guest has a chance of + * surviving, so that the cache isn't stale/corrupted, and so that KVM + * doesn't leak state across VMs. + */ + if (WARN_ON_ONCE(multiplier & SVM_TSC_RATIO_RSVD)) + multiplier = SVM_TSC_RATIO_DEFAULT; + if (multiplier == __this_cpu_read(current_tsc_ratio)) return; diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index b25216862740..14a0babb3c8d 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -5898,6 +5898,12 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) if (!nested_vmx_check_permission(vcpu)) return 1; + /* Forbid normal VMPTRLD if Enlightened version was used */ + if (nested_vmx_is_evmptr12_valid(vmx)) { + kvm_queue_exception(vcpu, UD_VECTOR); + return 1; + } + if (nested_vmx_get_vmptr(vcpu, &vmptr, &r)) return r; @@ -5907,10 +5913,6 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu) if (vmptr == vmx->nested.vmxon_ptr) return nested_vmx_fail(vcpu, VMXERR_VMPTRLD_VMXON_POINTER); - /* Forbid normal VMPTRLD if Enlightened version was used */ - if (nested_vmx_is_evmptr12_valid(vmx)) - return 1; - if (vmx->nested.current_vmptr != vmptr) { struct gfn_to_hva_cache *ghc = &vmx->nested.vmcs12_cache; struct vmcs_hdr hdr; @@ -5963,7 +5965,7 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) { unsigned long exit_qual = vmx_get_exit_qual(vcpu); u32 instr_info = vmcs_read32(VMX_INSTRUCTION_INFO); - gpa_t current_vmptr = to_vmx(vcpu)->nested.current_vmptr; + gpa_t current_vmptr; struct x86_exception e; gva_t gva; int r; @@ -5971,8 +5973,16 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) if (!nested_vmx_check_permission(vcpu)) return 1; - if (unlikely(nested_vmx_is_evmptr12_valid(to_vmx(vcpu)))) - return 1; + /* + * Hyper-V TLFS does not specify the behavior of VMPTRST when eVMCS is used + * but genuine Hyper-V seems to be returning eVMCS GPA. + */ +#ifdef CONFIG_KVM_HYPERV + if (nested_vmx_is_evmptr12_valid(to_vmx(vcpu))) + current_vmptr = to_vmx(vcpu)->nested.hv_evmcs_vmptr; + else +#endif + current_vmptr = to_vmx(vcpu)->nested.current_vmptr; if (get_vmx_mem_address(vcpu, exit_qual, instr_info, true, sizeof(gpa_t), &gva)) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 50efebf156d5..390cf3512f42 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1200,11 +1200,58 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_calc_nested_tsc_offset); u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier) { - if (l2_multiplier != kvm_caps.default_tsc_scaling_ratio) - return mul_u64_u64_shr(l1_multiplier, l2_multiplier, - kvm_caps.tsc_scaling_ratio_frac_bits); + u8 frac_bits = kvm_caps.tsc_scaling_ratio_frac_bits; + u64 nested_multiplier; - return l1_multiplier; + if (l2_multiplier == kvm_caps.default_tsc_scaling_ratio) + return l1_multiplier; + + /* + * The shift is fixed on both AMD and Intel, and operates on a 64-bit + * value. I.e. a shift greater than 63 is completely nonsensical. + */ + if (WARN_ON_ONCE(frac_bits > 63)) + return l1_multiplier; + + /* + * If the resulting multiplier can't be programmed into hardware, run + * L2 at the minimum/maximum frequency supported by hardware, i.e. + * saturate L2's frequency on both sides. Because L2's frequency needs + * to be distilled down to a single multiplier to get from: + * + * L2 = (((L0 * L1_mult) >> frac) * L2_mult) >> frac) + * + * to: + * + * L2 = (L0 * mult) >> frac + * + * very small/large L1 and L2 multipliers can underflow/overflow the + * minimum/maximum multiplier supported by hardware when combined into + * a single value. + * + * Manually check for the case where the result would overflow a u64, + * i.e. if the multiplier would be silently truncated before the "too + * large" check. Avoid doing the multiply twice in the common case + * where the compiler natively supports 128-bit values. + */ +#ifdef CONFIG_ARCH_SUPPORTS_INT128 + unsigned __int128 m = (unsigned __int128)l1_multiplier * l2_multiplier; + + if (m >> (64 + frac_bits)) + return kvm_caps.max_tsc_scaling_ratio; + + nested_multiplier = m >> frac_bits; +#else + if (mul_u64_u64_shr(l1_multiplier, l2_multiplier, 64 + frac_bits)) + return kvm_caps.max_tsc_scaling_ratio; + + nested_multiplier = mul_u64_u64_shr(l1_multiplier, l2_multiplier, frac_bits); +#endif + if (nested_multiplier > kvm_caps.max_tsc_scaling_ratio) + return kvm_caps.max_tsc_scaling_ratio; + + /* The minimum multiplier is '1' on both AMD and Intel. */ + return nested_multiplier ?: 1; } EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_calc_nested_tsc_multiplier); @@ -3681,7 +3728,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, user_tsc_khz = (u32)arg; if (kvm_caps.has_tsc_control && - user_tsc_khz >= kvm_caps.max_guest_tsc_khz) + user_tsc_khz > kvm_caps.max_guest_tsc_khz) goto out; if (user_tsc_khz == 0) @@ -4648,7 +4695,7 @@ set_pit2_out: user_tsc_khz = (u32)arg; if (kvm_caps.has_tsc_control && - user_tsc_khz >= kvm_caps.max_guest_tsc_khz) + user_tsc_khz > kvm_caps.max_guest_tsc_khz) goto out; if (user_tsc_khz == 0) @@ -7144,7 +7191,8 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops) if (kvm_caps.has_tsc_control) { /* * Make sure the user can only configure tsc_khz values that - * fit into a signed integer. + * fit into a signed integer, otherwise KVM_GET_TSC_KHZ would + * return a negative value and confuse userspace. * A min value is not calculated because it will always * be 1 on all machines. */ diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index b96f1bb23e29..35c7e523361d 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -6,7 +6,6 @@ all: LIBKVM += lib/assert.c LIBKVM += lib/elf.c LIBKVM += lib/guest_modes.c -LIBKVM += lib/io.c LIBKVM += lib/kvm_util.c LIBKVM += lib/lru_gen_util.c LIBKVM += lib/memstress.c diff --git a/tools/testing/selftests/kvm/arm64/hypercalls.c b/tools/testing/selftests/kvm/arm64/hypercalls.c index 391e2ba58b0b..87eade24ac5d 100644 --- a/tools/testing/selftests/kvm/arm64/hypercalls.c +++ b/tools/testing/selftests/kvm/arm64/hypercalls.c @@ -187,7 +187,7 @@ struct st_time { static void steal_time_init(struct kvm_vcpu *vcpu) { - u64 st_ipa = (ulong)ST_GPA_BASE; + u64 st_ipa = (unsigned long)ST_GPA_BASE; unsigned int gpages; gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE); diff --git a/tools/testing/selftests/kvm/arm64/page_fault_test.c b/tools/testing/selftests/kvm/arm64/page_fault_test.c index 6bb3d82906b2..b0e3fc8cd76a 100644 --- a/tools/testing/selftests/kvm/arm64/page_fault_test.c +++ b/tools/testing/selftests/kvm/arm64/page_fault_test.c @@ -597,18 +597,16 @@ static void setup_memslots(struct kvm_vm *vm, struct test_params *p) vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, CODE_AND_DATA_MEMSLOT, code_npages, 0); - vm->memslots[MEM_REGION_CODE] = CODE_AND_DATA_MEMSLOT; - vm->memslots[MEM_REGION_DATA] = CODE_AND_DATA_MEMSLOT; - - vm_userspace_mem_region_add(vm, p->src_type, data_gpa - pt_size, - PAGE_TABLE_MEMSLOT, pt_size / guest_page_size, - p->test_desc->pt_memslot_flags); - vm->memslots[MEM_REGION_PT] = PAGE_TABLE_MEMSLOT; - - vm_userspace_mem_region_add(vm, p->src_type, data_gpa, TEST_DATA_MEMSLOT, - data_size / guest_page_size, - p->test_desc->data_memslot_flags); - vm->memslots[MEM_REGION_TEST_DATA] = TEST_DATA_MEMSLOT; + ____vm_override_mem_region(vm, MEM_REGION_CODE, CODE_AND_DATA_MEMSLOT); + ____vm_override_mem_region(vm, MEM_REGION_DATA, CODE_AND_DATA_MEMSLOT); + + __vm_override_mem_region(vm, MEM_REGION_PT, p->src_type, data_gpa - pt_size, + PAGE_TABLE_MEMSLOT, pt_size / guest_page_size, + p->test_desc->pt_memslot_flags); + + __vm_override_mem_region(vm, MEM_REGION_TEST_DATA, p->src_type, data_gpa, + TEST_DATA_MEMSLOT, data_size / guest_page_size, + p->test_desc->data_memslot_flags); } static void setup_ucall(struct kvm_vm *vm) diff --git a/tools/testing/selftests/kvm/arm64/vgic_its_save.c b/tools/testing/selftests/kvm/arm64/vgic_its_save.c index 864da01539f3..fae8a6c45f88 100644 --- a/tools/testing/selftests/kvm/arm64/vgic_its_save.c +++ b/tools/testing/selftests/kvm/arm64/vgic_its_save.c @@ -279,15 +279,15 @@ static void setup_memslot(size_t sz) size_t pages = sz / vm->page_size; gpa_base = ((vm_compute_max_gfn(vm) + 1) * vm->page_size) - sz; - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, gpa_base, - TEST_MEMSLOT_INDEX, pages, 0); + vm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS, + gpa_base, TEST_MEMSLOT_INDEX, pages); } static gpa_t alloc_64k(size_t nr) { size_t pages_per_64k = vm_calc_num_guest_pages(vm->mode, SZ_64K); - gpa_t gpa = vm_phy_pages_alloc(vm, nr * pages_per_64k, gpa_base, - TEST_MEMSLOT_INDEX); + gpa_t gpa = vm_phy_pages_alloc(vm, nr * pages_per_64k, + MEM_REGION_TEST_EXTRA); TEST_ASSERT(IS_ALIGNED(gpa, SZ_64K), "Allocation at 0x%lx is not 64K aligned, GITS_BASER cannot address it", diff --git a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c index 9a69c439a0f8..45a87ba5a737 100644 --- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c +++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c @@ -23,7 +23,6 @@ #define GIC_LPI_OFFSET 8192 static size_t nr_iterations = 1000; -static gpa_t gpa_base; static struct kvm_vm *vm; static struct kvm_vcpu **vcpus; @@ -143,6 +142,7 @@ static void guest_code(size_t nr_lpis) static void setup_memslot(void) { + gpa_t gpa_base; size_t pages; size_t sz; @@ -164,8 +164,8 @@ static void setup_memslot(void) pages = sz / vm->page_size; gpa_base = ((vm_compute_max_gfn(vm) + 1) * vm->page_size) - sz; - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, gpa_base, - TEST_MEMSLOT_INDEX, pages, 0); + vm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS, + gpa_base, TEST_MEMSLOT_INDEX, pages); } #define LPI_PROP_DEFAULT_PRIO 0xa0 @@ -191,28 +191,25 @@ static void setup_test_data(void) gpa_t cmdq_base; test_data.device_table = vm_phy_pages_alloc(vm, pages_per_64k, - gpa_base, - TEST_MEMSLOT_INDEX); + MEM_REGION_TEST_EXTRA); test_data.collection_table = vm_phy_pages_alloc(vm, pages_per_64k, - gpa_base, - TEST_MEMSLOT_INDEX); + MEM_REGION_TEST_EXTRA); - cmdq_base = vm_phy_pages_alloc(vm, pages_per_64k, gpa_base, - TEST_MEMSLOT_INDEX); + cmdq_base = vm_phy_pages_alloc(vm, pages_per_64k, MEM_REGION_TEST_EXTRA); virt_map(vm, cmdq_base, cmdq_base, pages_per_64k); test_data.cmdq_base = cmdq_base; test_data.cmdq_base_va = (void *)cmdq_base; test_data.itt_tables = vm_phy_pages_alloc(vm, pages_per_64k * nr_devices, - gpa_base, TEST_MEMSLOT_INDEX); + MEM_REGION_TEST_EXTRA); test_data.lpi_prop_table = vm_phy_pages_alloc(vm, pages_per_64k, - gpa_base, TEST_MEMSLOT_INDEX); + MEM_REGION_TEST_EXTRA); configure_lpis(); test_data.lpi_pend_tables = vm_phy_pages_alloc(vm, pages_per_64k * nr_cpus, - gpa_base, TEST_MEMSLOT_INDEX); + MEM_REGION_TEST_EXTRA); sync_global_to_guest(vm, test_data); } diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index f8b3d0b68830..619a0b2be45c 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -297,8 +297,7 @@ int main(int argc, char *argv[]) p.single_uffd = true; break; case 'd': - p.uffd_delay = strtoul(optarg, NULL, 0); - TEST_ASSERT(p.uffd_delay >= 0, "A negative UFFD delay is not supported."); + p.uffd_delay = atoi_non_negative("UFFD delay", optarg); break; case 'b': guest_percpu_mem_size = parse_size(optarg); diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c index 2233d871a38f..cd5df88bc642 100644 --- a/tools/testing/selftests/kvm/guest_memfd_test.c +++ b/tools/testing/selftests/kvm/guest_memfd_test.c @@ -80,7 +80,7 @@ static void test_mbind(int fd, size_t total_size) { const unsigned long nodemask_0 = 1; /* nid: 0 */ unsigned long nodemask = 0; - unsigned long maxnode = BITS_PER_TYPE(nodemask); + unsigned long maxnode = MAXNODE_FOR_MASK(nodemask); int policy; char *mem; int ret; diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 777fa3dbf88d..e3b122719262 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -33,6 +33,8 @@ #define NSEC_PER_SEC 1000000000L +#define KVM_INVALID_MEMSLOT UINT_MAX + struct userspace_mem_region { struct kvm_userspace_memory_region2 region; struct sparsebit *unused_phy_pages; @@ -80,11 +82,45 @@ struct userspace_mem_regions { DECLARE_HASHTABLE(slot_hash, 9); }; +/* + * Memory region types are passed to various page allocators to communicate + * various properties and metadata related to the allocation. Note, the + * descriptions below described the primary usage of each type. Individual + * tests may allocate memory for other purposes. + * + * By default, all regions except TEST_EXTRA are mapped to memslot '0'. The + * TEST_EXTRA region is left unmapped as it's intended to be used only for test + * specific allocations, i.e. should never be used by core/infrastructure code. + * Tests can override the memslot for any or all types, e.g. so that all test + * data is allocated from a curated memslot. + */ enum kvm_mem_region_type { + /* + * The CODE region is used by lib/elf when loading the test's code into + * guest memory. + */ MEM_REGION_CODE, + /* + * The DATA region is used to allocate core data structures, e.g. vCPU + * stacks, VM exception tables, x86's TSS, etc. + */ MEM_REGION_DATA, + /* + * The PT region, a.k.a. Page Table region, is used to allocate page + * table pages. + */ MEM_REGION_PT, + /* + * The TEST_DATA region is used for allocating test data that is either + * test specific, and/or isn't considered a "core" data structure. + */ MEM_REGION_TEST_DATA, + /* + * The TEST_EXTRA region is for special snowflakes, where a test wants + * to create and use a one-off memslot, without impacting "normal" test + * data allocations. + */ + MEM_REGION_TEST_EXTRA, NR_MEM_REGIONS, }; @@ -127,11 +163,6 @@ struct kvm_vm { struct kvm_binary_stats stats; - /* - * KVM region slots. These are the default memslots used by page - * allocators, e.g., lib/elf uses the memslots[MEM_REGION_CODE] - * memslot. - */ u32 memslots[NR_MEM_REGIONS]; }; @@ -169,7 +200,8 @@ memslot2region(struct kvm_vm *vm, u32 memslot); static inline struct userspace_mem_region *vm_get_mem_region(struct kvm_vm *vm, enum kvm_mem_region_type type) { - assert(type < NR_MEM_REGIONS); + TEST_ASSERT(type < NR_MEM_REGIONS, + "Invalid memory region type '%u'", type); return memslot2region(vm, vm->memslots[type]); } @@ -805,6 +837,36 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, gpa_t gpa, u32 slot, u64 npages, u32 flags, int gmem_fd, u64 gmem_offset, u64 gmem_flags); + +static inline void ____vm_override_mem_region(struct kvm_vm *vm, + enum kvm_mem_region_type type, + u32 slot) +{ + TEST_ASSERT(vm->memslots[type] == KVM_INVALID_MEMSLOT, + "Memory region type '%u' was already overridden with slot=%u", + type, vm->memslots[type]); + + vm->memslots[type] = slot; +} + +static inline void __vm_override_mem_region(struct kvm_vm *vm, + enum kvm_mem_region_type type, + enum vm_mem_backing_src_type src_type, + gpa_t gpa, u32 slot, u64 npages, + u32 flags) +{ + ____vm_override_mem_region(vm, type, slot); + vm_userspace_mem_region_add(vm, src_type, gpa, slot, npages, flags); +} + +static inline void vm_override_mem_region(struct kvm_vm *vm, + enum kvm_mem_region_type type, + enum vm_mem_backing_src_type src_type, + gpa_t gpa, u32 slot, u64 npages) +{ + __vm_override_mem_region(vm, type, src_type, gpa, slot, npages, 0); +} + #ifndef vm_arch_has_protected_memory static inline bool vm_arch_has_protected_memory(struct kvm_vm *vm) { @@ -1098,23 +1160,41 @@ void kvm_gsi_routing_write(struct kvm_vm *vm, struct kvm_irq_routing *routing); const char *exit_reason_str(unsigned int exit_reason); -gpa_t vm_phy_page_alloc(struct kvm_vm *vm, gpa_t min_gpa, u32 memslot); -gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, gpa_t min_gpa, - u32 memslot, bool protected); -gpa_t vm_alloc_page_table(struct kvm_vm *vm); +bool kvm_arch_needs_naturally_aligned_page_tables(void); + +gpa_t ____vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages, gpa_t min_gpa, + u32 memslot, bool protected, bool naturally_aligned); +gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages, + enum kvm_mem_region_type type, bool protected); -static inline gpa_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, - gpa_t min_gpa, u32 memslot) +static inline gpa_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages, + enum kvm_mem_region_type type) { /* * By default, allocate memory as protected for VMs that support * protected memory, as the majority of memory for such VMs is * protected, i.e. using shared memory is effectively opt-in. */ - return __vm_phy_pages_alloc(vm, num, min_gpa, memslot, + return __vm_phy_pages_alloc(vm, nr_pages, type, vm_arch_has_protected_memory(vm)); } +static inline gpa_t vm_phy_page_alloc(struct kvm_vm *vm, + enum kvm_mem_region_type type) +{ + return vm_phy_pages_alloc(vm, 1, type); +} + +static inline gpa_t vm_alloc_page_table_pages(struct kvm_vm *vm, size_t nr_pages) +{ + return vm_phy_pages_alloc(vm, nr_pages, MEM_REGION_PT); +} + +static inline gpa_t vm_alloc_page_table(struct kvm_vm *vm) +{ + return vm_alloc_page_table_pages(vm, 1); +} + /* * ____vm_create() does KVM_CREATE_VM and little else. __vm_create() also * loads the test binary into guest memory and creates an IRQ chip (x86 only). diff --git a/tools/testing/selftests/kvm/include/numaif.h b/tools/testing/selftests/kvm/include/numaif.h index 29572a6d789c..0945500c6322 100644 --- a/tools/testing/selftests/kvm/include/numaif.h +++ b/tools/testing/selftests/kvm/include/numaif.h @@ -6,6 +6,7 @@ #include <dirent.h> +#include <linux/bitmap.h> #include <linux/mempolicy.h> #include "kvm_syscalls.h" @@ -30,6 +31,48 @@ KVM_SYSCALL_DEFINE(mbind, 6, void *, addr, unsigned long, size, int, mode, const unsigned long *, nodemask, unsigned long, maxnode, unsigned int, flags); +/* + * Calculate the @maxnode param for the above syscalls given the mask that will + * be passed to the kernel, to account for a longstanding off-by-one bug in the + * kernel that isn't properly documented in the manpages. The manpages say + * that @maxnode is "the maximum node ID plus one", but the kernel's actual + * behavior is "the number of bits in the mask plus one", i.e. "the maximum + * node ID plus two". + */ +#define MAXNODE_FOR_MASK(mask) (BITS_PER_TYPE(mask) + 1) + +static inline int kvm_get_numa_memory_nodes(unsigned long *nodemask) +{ + int r; + + *nodemask = 0; + + r = get_mempolicy(NULL, nodemask, MAXNODE_FOR_MASK(*nodemask), 0, + MPOL_F_MEMS_ALLOWED); + TEST_ASSERT(!r || errno == ENOSYS || errno == EPERM, + "Unexpected get_mempolicy() failure"); + return __builtin_popcountl(*nodemask); +} + +/* + * Return the node ID of the next NUMA node in the mask, starting at @from+1. + * Guarantees a node is found, and that the found node is not @from. Pass -1 + * to find the first node in the mask. + */ +static inline int kvm_get_next_numa_node(unsigned long nodemask, int from) +{ + const unsigned long nr_bits = BITS_PER_TYPE(nodemask); + int to; + + to = find_next_bit(&nodemask, nr_bits, from + 1); + if (to == nr_bits) + to = find_next_bit(&nodemask, nr_bits, 0); + + TEST_ASSERT(to != nr_bits && to != from, + "Unabled to find second NUMA node (from = %d, to = %d)", from, to); + return to; +} + static inline int get_max_numa_node(void) { struct dirent *de; diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index b9c4af6a420d..c80019e24b2d 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -49,10 +49,6 @@ do { \ #define TEST_REQUIRE(f) __TEST_REQUIRE(f, "Requirement not met: %s", #f) -ssize_t test_write(int fd, const void *buf, size_t count); -ssize_t test_read(int fd, void *buf, size_t count); -int test_seq_read(const char *path, char **bufp, size_t *sizep); - void __printf(5, 6) test_assert(bool exp, const char *exp_str, const char *file, unsigned int line, const char *fmt, ...); @@ -243,7 +239,6 @@ static inline u32 atoi_non_negative(const char *name, const char *num_str) } int guest_vsnprintf(char *buf, int n, const char *fmt, va_list args); -__printf(3, 4) int guest_snprintf(char *buf, int n, const char *fmt, ...); char *strdup_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2), nonnull(1))); diff --git a/tools/testing/selftests/kvm/include/x86/evmcs.h b/tools/testing/selftests/kvm/include/x86/evmcs.h index 82a8ea6b661f..491fb8107473 100644 --- a/tools/testing/selftests/kvm/include/x86/evmcs.h +++ b/tools/testing/selftests/kvm/include/x86/evmcs.h @@ -245,32 +245,18 @@ static inline void evmcs_enable(void) enable_evmcs = true; } -static inline int evmcs_vmptrld(u64 vmcs_pa, void *vmcs) +static inline void evmcs_vmptrld(u64 vmcs_pa, void *vmcs) { current_vp_assist->current_nested_vmcs = vmcs_pa; current_vp_assist->enlighten_vmentry = 1; current_evmcs = vmcs; - - return 0; } -static inline bool load_evmcs(struct hyperv_test_pages *hv) +static inline void load_evmcs(struct hyperv_test_pages *hv) { - if (evmcs_vmptrld(hv->enlightened_vmcs_gpa, hv->enlightened_vmcs)) - return false; - + evmcs_vmptrld(hv->enlightened_vmcs_gpa, hv->enlightened_vmcs); current_evmcs->revision_id = EVMCS_VERSION; - - return true; -} - -static inline int evmcs_vmptrst(u64 *value) -{ - *value = current_vp_assist->current_nested_vmcs & - ~HV_X64_MSR_VP_ASSIST_PAGE_ENABLE; - - return 0; } static inline int evmcs_vmread(u64 encoding, u64 *value) @@ -1201,62 +1187,4 @@ static inline int evmcs_vmwrite(u64 encoding, u64 value) return 0; } -static inline int evmcs_vmlaunch(void) -{ - int ret; - - current_evmcs->hv_clean_fields = 0; - - __asm__ __volatile__("push $0;" - "mov %%rsp, (%[host_rsp]);" - "lea 1f(%%rip), %%rax;" - "mov %%rax, (%[host_rip]);" - VMX_SWITCH_GPRS_ASM - "vmlaunch;" - "incq (%%rsp);" - "1: ;" - VMX_SWITCH_GPRS_ASM - "pop %%rax;" - : [ret]"=&a"(ret) - : [host_rsp]"r" - ((u64)¤t_evmcs->host_rsp), - [host_rip]"r" - ((u64)¤t_evmcs->host_rip), - GUEST_REGS_OFFSETS - : "memory", "cc"); - return ret; -} - -/* - * No guest state (e.g. GPRs) is established by this vmresume. - */ -static inline int evmcs_vmresume(void) -{ - int ret; - - /* HOST_RIP */ - current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1; - /* HOST_RSP */ - current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER; - - __asm__ __volatile__("push $0;" - "mov %%rsp, (%[host_rsp]);" - "lea 1f(%%rip), %%rax;" - "mov %%rax, (%[host_rip]);" - VMX_SWITCH_GPRS_ASM - "vmresume;" - "incq (%%rsp);" - "1: ;" - VMX_SWITCH_GPRS_ASM - "pop %%rax;" - : [ret]"=&a"(ret) - : [host_rsp]"r" - ((u64)¤t_evmcs->host_rsp), - [host_rip]"r" - ((u64)¤t_evmcs->host_rip), - GUEST_REGS_OFFSETS - : "memory", "cc"); - return ret; -} - #endif /* !SELFTEST_KVM_EVMCS_H */ diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h index 6f110987c51a..5898a277a2e0 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -23,6 +23,8 @@ extern bool host_cpu_is_intel; extern bool host_cpu_is_amd; extern bool host_cpu_is_hygon; extern bool host_cpu_is_amd_compatible; +extern bool host_cpu_is_zhaoxin; +extern bool host_cpu_is_intel_compatible; extern u64 guest_tsc_khz; extern struct kvm_mmu guest_mmu; @@ -783,6 +785,12 @@ static inline bool this_cpu_is_hygon(void) return this_cpu_vendor_string_is("HygonGenuine"); } +static inline bool this_cpu_is_zhaoxin(void) +{ + return this_cpu_vendor_string_is("CentaurHauls") || + this_cpu_vendor_string_is(" Shanghai "); +} + static inline u32 __this_cpu_has(u32 function, u32 index, u8 reg, u8 lo, u8 hi) { u32 gprs[4]; @@ -1173,7 +1181,6 @@ static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu) void vcpu_set_cpuid_property(struct kvm_vcpu *vcpu, struct kvm_x86_cpu_property property, u32 value); -void vcpu_set_cpuid_maxphyaddr(struct kvm_vcpu *vcpu, u8 maxphyaddr); void vcpu_clear_cpuid_entry(struct kvm_vcpu *vcpu, u32 function); @@ -1319,7 +1326,7 @@ gva_t vm_alloc_stack(struct kvm_vm *vm, int nr_pages); "lea 1f(%%rip), %%r10\n\t" \ "lea 2f(%%rip), %%r11\n\t" \ fep "1: " insn "\n\t" \ - "xor %%r9, %%r9\n\t" \ + "mov $0, %%r9d\n\t" \ "2:\n\t" \ "mov %%r9b, %[vector]\n\t" \ "mov %%r10, %[error_code]\n\t" @@ -1447,7 +1454,7 @@ static inline bool kvm_is_pmu_enabled(void) static inline bool kvm_is_mediated_pmu_enabled(void) { - if (host_cpu_is_intel) + if (host_cpu_is_intel_compatible) return get_kvm_intel_param_bool("enable_mediated_pmu"); return get_kvm_amd_param_bool("enable_mediated_pmu"); diff --git a/tools/testing/selftests/kvm/include/x86/smm.h b/tools/testing/selftests/kvm/include/x86/smm.h index 2d1afa09819b..15faaa060126 100644 --- a/tools/testing/selftests/kvm/include/x86/smm.h +++ b/tools/testing/selftests/kvm/include/x86/smm.h @@ -8,7 +8,7 @@ #define SMRAM_MEMSLOT ((1 << 16) | 1) #define SMRAM_PAGES (SMRAM_SIZE / PAGE_SIZE) -void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, u64 smram_gpa, +void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, gpa_t smram_gpa, const void *smi_handler, size_t handler_size); void inject_smi(struct kvm_vcpu *vcpu); diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/selftests/kvm/include/x86/vmx.h index 04f5e34dea3a..8fd97434eee5 100644 --- a/tools/testing/selftests/kvm/include/x86/vmx.h +++ b/tools/testing/selftests/kvm/include/x86/vmx.h @@ -309,125 +309,67 @@ struct vmx_msr_entry { #include "evmcs.h" -static inline int vmxon(u64 phys) -{ - u8 ret; - - __asm__ __volatile__ ("vmxon %[pa]; setna %[ret]" - : [ret]"=rm"(ret) - : [pa]"m"(phys) - : "cc", "memory"); - - return ret; +#define GUEST_ASSERT_VMX_INSN_SUCCEEDED(insn, __r, __pa) \ + __GUEST_ASSERT(!__r, __stringify(insn) "[0x%lx] hit %s", \ + __pa, __r < 0 ? "VM-Fail" : ex_str(__r)) + +#define BUILD_VMCS_ASM_HELPERS(insn) \ +static inline int __##insn(u64 vmcs_pa) \ +{ \ + u64 error_code; \ + u8 vector; \ + u8 failed; \ + \ + asm volatile(KVM_ASM_SAFE(__stringify(insn) " %[pa]") \ + "\n\tsetna %[failed]" \ + : KVM_ASM_SAFE_OUTPUTS(vector, error_code), \ + [failed]"=qm"(failed) \ + : [pa]"m"(vmcs_pa) \ + : "cc", "memory", KVM_ASM_SAFE_CLOBBERS); \ + \ + return vector ? vector : failed ? -EINVAL : 0; \ +} \ + \ +static inline void insn(u64 vmcs_pa) \ +{ \ + int ret = __##insn(vmcs_pa); \ + \ + GUEST_ASSERT_VMX_INSN_SUCCEEDED(insn, ret, vmcs_pa); \ } +BUILD_VMCS_ASM_HELPERS(vmxon) +BUILD_VMCS_ASM_HELPERS(vmptrld) +BUILD_VMCS_ASM_HELPERS(vmclear) + static inline void vmxoff(void) { __asm__ __volatile__("vmxoff"); } -static inline int vmclear(u64 vmcs_pa) -{ - u8 ret; - - __asm__ __volatile__ ("vmclear %[pa]; setna %[ret]" - : [ret]"=rm"(ret) - : [pa]"m"(vmcs_pa) - : "cc", "memory"); - - return ret; -} - -static inline int vmptrld(u64 vmcs_pa) +static inline u64 vmptrst(void) { + u64 value = 0; u8 ret; - if (enable_evmcs) - return -1; - - __asm__ __volatile__ ("vmptrld %[pa]; setna %[ret]" - : [ret]"=rm"(ret) - : [pa]"m"(vmcs_pa) - : "cc", "memory"); - - return ret; -} - -static inline int vmptrst(u64 *value) -{ - u64 tmp; - u8 ret; - - if (enable_evmcs) - return evmcs_vmptrst(value); - __asm__ __volatile__("vmptrst %[value]; setna %[ret]" - : [value]"=m"(tmp), [ret]"=rm"(ret) + : [value]"=m"(value), [ret]"=rm"(ret) : : "cc", "memory"); - *value = tmp; - return ret; -} - -/* - * A wrapper around vmptrst that ignores errors and returns zero if the - * vmptrst instruction fails. - */ -static inline u64 vmptrstz(void) -{ - u64 value = 0; - vmptrst(&value); + __GUEST_ASSERT(!ret, "vmptrst failed"); return value; } -static inline int vmlaunch(void) -{ - int ret; +int __vmlaunch(void); +int __vmresume(void); - if (enable_evmcs) - return evmcs_vmlaunch(); - - __asm__ __volatile__("push $0;" - "vmwrite %%rsp, %[host_rsp];" - "lea 1f(%%rip), %%rax;" - "vmwrite %%rax, %[host_rip];" - VMX_SWITCH_GPRS_ASM - "vmlaunch;" - "incq (%%rsp);" - "1: ;" - VMX_SWITCH_GPRS_ASM - "pop %%rax;" - : [ret]"=&a"(ret) - : [host_rsp]"r"((u64)HOST_RSP), - [host_rip]"r"((u64)HOST_RIP), - GUEST_REGS_OFFSETS - : "memory", "cc"); - return ret; +static inline void vmlaunch(void) +{ + __GUEST_ASSERT(!__vmlaunch(), "vmlaunch hit VM-Fail"); } -static inline int vmresume(void) +static inline void vmresume(void) { - int ret; - - if (enable_evmcs) - return evmcs_vmresume(); - - __asm__ __volatile__("push $0;" - "vmwrite %%rsp, %[host_rsp];" - "lea 1f(%%rip), %%rax;" - "vmwrite %%rax, %[host_rip];" - VMX_SWITCH_GPRS_ASM - "vmresume;" - "incq (%%rsp);" - "1: ;" - VMX_SWITCH_GPRS_ASM - "pop %%rax;" - : [ret]"=&a"(ret) - : [host_rsp]"r"((u64)HOST_RSP), - [host_rip]"r"((u64)HOST_RIP), - GUEST_REGS_OFFSETS - : "memory", "cc"); - return ret; + __GUEST_ASSERT(!__vmresume(), "vmresume hit VM-Fail"); } static inline void vmcall(void) @@ -444,7 +386,7 @@ static inline void vmcall(void) "r10", "r11", "r12", "r13", "r14", "r15"); } -static inline int vmread(u64 encoding, u64 *value) +static inline int __vmread(u64 encoding, u64 *value) { u64 tmp; u8 ret; @@ -457,22 +399,21 @@ static inline int vmread(u64 encoding, u64 *value) : [encoding]"r"(encoding) : "cc", "memory"); - *value = tmp; + if (!ret) + *value = tmp; return ret; } -/* - * A wrapper around vmread that ignores errors and returns zero if the - * vmread instruction fails. - */ -static inline u64 vmreadz(u64 encoding) +static inline u64 vmread(u64 encoding) { u64 value = 0; - vmread(encoding, &value); + + __GUEST_ASSERT(!__vmread(encoding, &value), + "vmread[0x%lx] hit VM-Fail", encoding); return value; } -static inline int vmwrite(u64 encoding, u64 value) +static __always_inline int __vmwrite(u64 encoding, u64 value) { u8 ret; @@ -487,6 +428,12 @@ static inline int vmwrite(u64 encoding, u64 value) return ret; } +static inline void vmwrite(u64 encoding, u64 value) +{ + __GUEST_ASSERT(!__vmwrite(encoding, value), + "vmwrite[0x%lx] = 0x%lx hit VM-Fail", encoding, value); +} + static inline u32 vmcs_revision(void) { return rdmsr(MSR_IA32_VMX_BASIC); @@ -550,13 +497,24 @@ union vmx_ctrl_msr { }; struct vmx_pages *vcpu_alloc_vmx(struct kvm_vm *vm, gva_t *p_vmx_gva); -bool prepare_for_vmx_operation(struct vmx_pages *vmx); +void prepare_for_vmx_operation(struct vmx_pages *vmx); void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip); -bool load_vmcs(struct vmx_pages *vmx); +void load_vmcs(struct vmx_pages *vmx); bool ept_1g_pages_supported(void); -bool kvm_cpu_has_ept(void); +bool kvm_cpu_has_secondary_exec_control(u32 ctrl); + +static inline bool kvm_cpu_has_ept(void) +{ + return kvm_cpu_has_secondary_exec_control(SECONDARY_EXEC_ENABLE_EPT); +} + +static inline bool kvm_cpu_has_vmx_virtualize_apic_accesses(void) +{ + return kvm_cpu_has_secondary_exec_control(SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES); +} + void vm_enable_ept(struct kvm_vm *vm); void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm); diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index 01325bf4d36f..2dcaa2c4a038 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -115,9 +115,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm) if (vm->mmu.pgd_created) return; - vm->mmu.pgd = vm_phy_pages_alloc(vm, nr_pages, - KVM_GUEST_PAGE_TABLE_MIN_PADDR, - vm->memslots[MEM_REGION_PT]); + vm->mmu.pgd = vm_alloc_page_table_pages(vm, nr_pages); vm->mmu.pgd_created = true; } diff --git a/tools/testing/selftests/kvm/lib/elf.c b/tools/testing/selftests/kvm/lib/elf.c index 1924a9895834..d5adb68fd7c0 100644 --- a/tools/testing/selftests/kvm/lib/elf.c +++ b/tools/testing/selftests/kvm/lib/elf.c @@ -12,6 +12,44 @@ #include "kvm_util.h" +static ssize_t elf_read(int fd, void *buf, size_t count) +{ + ssize_t rc; + ssize_t num_read = 0; + size_t num_left = count; + char *ptr = buf; + + TEST_ASSERT(count, "Count must be non-zero"); + + do { + rc = read(fd, ptr, num_left); + + switch (rc) { + case -1: + TEST_ASSERT(errno == EAGAIN || errno == EINTR, + "Unexpected read failure,\n" + " rc: %zi errno: %i", rc, errno); + break; + + case 0: + TEST_FAIL("Unexpected EOF,\n" + " rc: %zi num_read: %zi num_left: %zu", + rc, num_read, num_left); + break; + + default: + TEST_ASSERT(rc > 0, "Unexpected ret from read,\n" + " rc: %zi errno: %i", rc, errno); + num_read += rc; + num_left -= rc; + ptr += rc; + break; + } + } while (num_read < count); + + return num_read; +} + static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp) { off_t offset_rv; @@ -31,7 +69,7 @@ static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp) * the real size of the ELF header. */ unsigned char ident[EI_NIDENT]; - test_read(fd, ident, sizeof(ident)); + elf_read(fd, ident, sizeof(ident)); TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1) && (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3), "ELF MAGIC Mismatch,\n" @@ -79,7 +117,7 @@ static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp) offset_rv = lseek(fd, 0, SEEK_SET); TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n" " rv: %zi expected: %i", offset_rv, 0); - test_read(fd, hdrp, sizeof(*hdrp)); + elf_read(fd, hdrp, sizeof(*hdrp)); TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr), "Unexpected physical header size,\n" " hdrp->e_phentsize: %x\n" @@ -146,7 +184,7 @@ void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename) /* Read in the program header. */ Elf64_Phdr phdr; - test_read(fd, &phdr, sizeof(phdr)); + elf_read(fd, &phdr, sizeof(phdr)); /* Skip if this header doesn't describe a loadable segment. */ if (phdr.p_type != PT_LOAD) @@ -186,8 +224,8 @@ void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename) " expected: 0x%jx", n1, errno, (intmax_t) offset_rv, (intmax_t) phdr.p_offset); - test_read(fd, addr_gva2hva(vm, phdr.p_vaddr), - phdr.p_filesz); + elf_read(fd, addr_gva2hva(vm, phdr.p_vaddr), + phdr.p_filesz); } } close(fd); diff --git a/tools/testing/selftests/kvm/lib/guest_sprintf.c b/tools/testing/selftests/kvm/lib/guest_sprintf.c index 7a33965349a7..6caebb456f3d 100644 --- a/tools/testing/selftests/kvm/lib/guest_sprintf.c +++ b/tools/testing/selftests/kvm/lib/guest_sprintf.c @@ -300,15 +300,3 @@ repeat: *str = '\0'; return str - buf; } - -int guest_snprintf(char *buf, int n, const char *fmt, ...) -{ - va_list va; - int len; - - va_start(va, fmt); - len = guest_vsnprintf(buf, n, fmt, va); - va_end(va); - - return len; -} diff --git a/tools/testing/selftests/kvm/lib/io.c b/tools/testing/selftests/kvm/lib/io.c deleted file mode 100644 index fedb2a741f0b..000000000000 --- a/tools/testing/selftests/kvm/lib/io.c +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * tools/testing/selftests/kvm/lib/io.c - * - * Copyright (C) 2018, Google LLC. - */ - -#include "test_util.h" - -/* Test Write - * - * A wrapper for write(2), that automatically handles the following - * special conditions: - * - * + Interrupted system call (EINTR) - * + Write of less than requested amount - * + Non-block return (EAGAIN) - * - * For each of the above, an additional write is performed to automatically - * continue writing the requested data. - * There are also many cases where write(2) can return an unexpected - * error (e.g. EIO). Such errors cause a TEST_ASSERT failure. - * - * Note, for function signature compatibility with write(2), this function - * returns the number of bytes written, but that value will always be equal - * to the number of requested bytes. All other conditions in this and - * future enhancements to this function either automatically issue another - * write(2) or cause a TEST_ASSERT failure. - * - * Args: - * fd - Opened file descriptor to file to be written. - * count - Number of bytes to write. - * - * Output: - * buf - Starting address of data to be written. - * - * Return: - * On success, number of bytes written. - * On failure, a TEST_ASSERT failure is caused. - */ -ssize_t test_write(int fd, const void *buf, size_t count) -{ - ssize_t rc; - ssize_t num_written = 0; - size_t num_left = count; - const char *ptr = buf; - - /* Note: Count of zero is allowed (see "RETURN VALUE" portion of - * write(2) manpage for details. - */ - TEST_ASSERT(count >= 0, "Unexpected count, count: %li", count); - - do { - rc = write(fd, ptr, num_left); - - switch (rc) { - case -1: - TEST_ASSERT(errno == EAGAIN || errno == EINTR, - "Unexpected write failure,\n" - " rc: %zi errno: %i", rc, errno); - continue; - - case 0: - TEST_FAIL("Unexpected EOF,\n" - " rc: %zi num_written: %zi num_left: %zu", - rc, num_written, num_left); - break; - - default: - TEST_ASSERT(rc >= 0, "Unexpected ret from write,\n" - " rc: %zi errno: %i", rc, errno); - num_written += rc; - num_left -= rc; - ptr += rc; - break; - } - } while (num_written < count); - - return num_written; -} - -/* Test Read - * - * A wrapper for read(2), that automatically handles the following - * special conditions: - * - * + Interrupted system call (EINTR) - * + Read of less than requested amount - * + Non-block return (EAGAIN) - * - * For each of the above, an additional read is performed to automatically - * continue reading the requested data. - * There are also many cases where read(2) can return an unexpected - * error (e.g. EIO). Such errors cause a TEST_ASSERT failure. Note, - * it is expected that the file opened by fd at the current file position - * contains at least the number of requested bytes to be read. A TEST_ASSERT - * failure is produced if an End-Of-File condition occurs, before all the - * data is read. It is the callers responsibility to assure that sufficient - * data exists. - * - * Note, for function signature compatibility with read(2), this function - * returns the number of bytes read, but that value will always be equal - * to the number of requested bytes. All other conditions in this and - * future enhancements to this function either automatically issue another - * read(2) or cause a TEST_ASSERT failure. - * - * Args: - * fd - Opened file descriptor to file to be read. - * count - Number of bytes to read. - * - * Output: - * buf - Starting address of where to write the bytes read. - * - * Return: - * On success, number of bytes read. - * On failure, a TEST_ASSERT failure is caused. - */ -ssize_t test_read(int fd, void *buf, size_t count) -{ - ssize_t rc; - ssize_t num_read = 0; - size_t num_left = count; - char *ptr = buf; - - /* Note: Count of zero is allowed (see "If count is zero" portion of - * read(2) manpage for details. - */ - TEST_ASSERT(count >= 0, "Unexpected count, count: %li", count); - - do { - rc = read(fd, ptr, num_left); - - switch (rc) { - case -1: - TEST_ASSERT(errno == EAGAIN || errno == EINTR, - "Unexpected read failure,\n" - " rc: %zi errno: %i", rc, errno); - break; - - case 0: - TEST_FAIL("Unexpected EOF,\n" - " rc: %zi num_read: %zi num_left: %zu", - rc, num_read, num_left); - break; - - default: - TEST_ASSERT(rc > 0, "Unexpected ret from read,\n" - " rc: %zi errno: %i", rc, errno); - num_read += rc; - num_left -= rc; - ptr += rc; - break; - } - } while (num_read < count); - - return num_read; -} diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 0c67d964a9aa..e4bbb2f268b7 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -17,6 +17,7 @@ #include <sys/stat.h> #include <time.h> #include <unistd.h> +#include <linux/align.h> #include <linux/kernel.h> #include "../../../../../mm/gup_test.h" @@ -291,6 +292,7 @@ __weak void vm_populate_gva_bitmap(struct kvm_vm *vm) struct kvm_vm *____vm_create(struct vm_shape shape) { struct kvm_vm *vm; + int i; vm = calloc(1, sizeof(*vm)); TEST_ASSERT(vm != NULL, "Insufficient Memory"); @@ -299,6 +301,8 @@ struct kvm_vm *____vm_create(struct vm_shape shape) vm->regions.gpa_tree = RB_ROOT; vm->regions.hva_tree = RB_ROOT; hash_init(vm->regions.slot_hash); + for (i = 0; i < NR_MEM_REGIONS; i++) + vm->memslots[i] = KVM_INVALID_MEMSLOT; vm->mode = shape.mode; vm->type = shape.type; @@ -496,7 +500,7 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus, struct userspace_mem_region *slot0; u64 gmem_flags = 0; struct kvm_vm *vm; - int i, flags; + int flags; kvm_set_files_rlimit(nr_runnable_vcpus); @@ -524,8 +528,10 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus, } vm_mem_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, nr_pages, flags, -1, 0, gmem_flags); - for (i = 0; i < NR_MEM_REGIONS; i++) - vm->memslots[i] = 0; + ____vm_override_mem_region(vm, MEM_REGION_CODE, 0); + ____vm_override_mem_region(vm, MEM_REGION_PT, 0); + ____vm_override_mem_region(vm, MEM_REGION_DATA, 0); + ____vm_override_mem_region(vm, MEM_REGION_TEST_DATA, 0); kvm_vm_elf_load(vm, program_invocation_name); @@ -1249,6 +1255,8 @@ memslot2region(struct kvm_vm *vm, u32 memslot) { struct userspace_mem_region *region; + TEST_ASSERT(memslot != KVM_INVALID_MEMSLOT, "vm->memslots[] unpopulated?"); + hash_for_each_possible(vm->regions.slot_hash, region, slot_node, memslot) if (region->region.slot == memslot) @@ -1518,9 +1526,7 @@ static gva_t ____vm_alloc(struct kvm_vm *vm, size_t sz, gva_t min_gva, u64 pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0); virt_pgd_alloc(vm); - gpa_t gpa = __vm_phy_pages_alloc(vm, pages, - KVM_UTIL_MIN_PFN * vm->page_size, - vm->memslots[type], protected); + gpa_t gpa = __vm_phy_pages_alloc(vm, pages, type, protected); /* * Find an unused range of virtual page addresses of at least @@ -1796,6 +1802,7 @@ struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vcpu *vcpu) TEST_ASSERT(ret == -1 && errno == E2BIG, "KVM_GET_REG_LIST n=0"); reg_list = calloc(1, sizeof(*reg_list) + reg_list_n.n * sizeof(__u64)); + TEST_ASSERT(reg_list, "Failed to allocate reg_list"); reg_list->n = reg_list_n.n; vcpu_ioctl(vcpu, KVM_GET_REG_LIST, reg_list); return reg_list; @@ -2094,33 +2101,21 @@ const char *exit_reason_str(unsigned int exit_reason) } /* - * Physical Contiguous Page Allocator - * - * Input Args: - * vm - Virtual Machine - * num - number of pages - * min_gpa - Physical address minimum - * memslot - Memory region to allocate page from - * protected - True if the pages will be used as protected/private memory + * Allocate contiguous (guest) physical pages in a given memory region, at or + * above the minimum specified GPA. If the memory is protected/private, also + * add the allocated pages to the region's set of protected pages, e.g. so that + * arch code knows which pages need to be encrypted when launching the VM. * - * Output Args: None - * - * Return: - * Starting physical address - * - * Within the VM specified by vm, locates a range of available physical - * pages at or above min_gpa. If found, the pages are marked as in use - * and their base address is returned. A TEST_ASSERT failure occurs if - * not enough pages are available at or above min_gpa. + * Note, success is guaranteed! */ -gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, - gpa_t min_gpa, u32 memslot, - bool protected) +gpa_t ____vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages, gpa_t min_gpa, + u32 memslot, bool protected, bool naturally_aligned) { + size_t alignment = naturally_aligned ? nr_pages : 1; struct userspace_mem_region *region; sparsebit_idx_t pg, base; - TEST_ASSERT(num > 0, "Must allocate at least one page"); + TEST_ASSERT(nr_pages, "Must allocate at least one page"); TEST_ASSERT((min_gpa % vm->page_size) == 0, "Min physical address " "not divisible by page size.\n" @@ -2131,43 +2126,78 @@ gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, TEST_ASSERT(!protected || region->protected_phy_pages, "Region doesn't support protected memory"); - base = pg = min_gpa >> vm->page_shift; - do { - for (; pg < base + num; ++pg) { - if (!sparsebit_is_set(region->unused_phy_pages, pg)) { - base = pg = sparsebit_next_set(region->unused_phy_pages, pg); - break; - } + base = min_gpa >> vm->page_shift; +again: + base = ALIGN(base, alignment); + for (pg = base; pg < base + nr_pages; ++pg) { + if (!sparsebit_is_set(region->unused_phy_pages, pg)) { + base = sparsebit_next_set(region->unused_phy_pages, pg); + if (!base) + goto enomem; + goto again; } - } while (pg && pg != base + num); - - if (pg == 0) { - fprintf(stderr, "No guest physical page available, " - "min_gpa: 0x%lx page_size: 0x%x memslot: %u\n", - min_gpa, vm->page_size, memslot); - fputs("---- vm dump ----\n", stderr); - vm_dump(stderr, vm, 2); - abort(); } - for (pg = base; pg < base + num; ++pg) { + for (pg = base; pg < base + nr_pages; ++pg) { sparsebit_clear(region->unused_phy_pages, pg); if (protected) sparsebit_set(region->protected_phy_pages, pg); } return base * vm->page_size; + +enomem: + fprintf(stderr, "No guest physical page available, min_gpa: 0x%lx page_size: 0x%x memslot: %u\n", + min_gpa, vm->page_size, memslot); + fputs("---- vm dump ----\n", stderr); + vm_dump(stderr, vm, 2); + abort(); + __builtin_unreachable(); } -gpa_t vm_phy_page_alloc(struct kvm_vm *vm, gpa_t min_gpa, u32 memslot) +__weak bool kvm_arch_needs_naturally_aligned_page_tables(void) { - return vm_phy_pages_alloc(vm, 1, min_gpa, memslot); + return false; } -gpa_t vm_alloc_page_table(struct kvm_vm *vm) +gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages, + enum kvm_mem_region_type type, bool protected) { - return vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, - vm->memslots[MEM_REGION_PT]); + struct userspace_mem_region *region = vm_get_mem_region(vm, type); + bool naturally_aligned = false; + gpa_t min_gpa; + + TEST_ASSERT(region, "No region for type '%u', memslot '%u'", + type, vm->memslots[type]); + + switch (type) { + case MEM_REGION_CODE: + case MEM_REGION_DATA: + case MEM_REGION_TEST_DATA: + /* + * If the region is backed by the default memslot (id=0), use + * selftests' hardcoded minimum PFN, otherwise use the base of + * the custom memory slot that backs the region. + */ + if (!vm->memslots[type]) + min_gpa = KVM_UTIL_MIN_PFN * vm->page_size; + else + min_gpa = region->region.guest_phys_addr; + break; + case MEM_REGION_PT: + min_gpa = KVM_GUEST_PAGE_TABLE_MIN_PADDR; + naturally_aligned = kvm_arch_needs_naturally_aligned_page_tables(); + break; + case MEM_REGION_TEST_EXTRA: + min_gpa = region->region.guest_phys_addr; + break; + default: + TEST_FAIL("Invalid memory region type '%u'", type); + break; + } + + return ____vm_phy_pages_alloc(vm, nr_pages, min_gpa, vm->memslots[type], + protected, naturally_aligned); } /* diff --git a/tools/testing/selftests/kvm/lib/loongarch/processor.c b/tools/testing/selftests/kvm/lib/loongarch/processor.c index 2b5a742a8939..83e53ff705ca 100644 --- a/tools/testing/selftests/kvm/lib/loongarch/processor.c +++ b/tools/testing/selftests/kvm/lib/loongarch/processor.c @@ -9,7 +9,6 @@ #include "processor.h" #include "ucall_common.h" -#define LOONGARCH_PAGE_TABLE_PHYS_MIN 0x200000 #define LOONGARCH_GUEST_STACK_VADDR_MIN 0x200000 static gpa_t invalid_pgtable[4]; @@ -57,9 +56,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm) child = table = 0; for (i = 0; i < vm->mmu.pgtable_levels; i++) { invalid_pgtable[i] = child; - table = vm_phy_page_alloc(vm, LOONGARCH_PAGE_TABLE_PHYS_MIN, - vm->memslots[MEM_REGION_PT]); - TEST_ASSERT(table, "Fail to allocate page tale at level %d\n", i); + table = vm_alloc_page_table(vm); virt_set_pgtable(vm, table, child); child = table; } diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index ded5429f3448..c175dcd14114 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -69,9 +69,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm) if (vm->mmu.pgd_created) return; - vm->mmu.pgd = vm_phy_pages_alloc(vm, nr_pages, - KVM_GUEST_PAGE_TABLE_MIN_PADDR, - vm->memslots[MEM_REGION_PT]); + vm->mmu.pgd = vm_alloc_page_table_pages(vm, nr_pages); vm->mmu.pgd_created = true; } diff --git a/tools/testing/selftests/kvm/lib/s390/processor.c b/tools/testing/selftests/kvm/lib/s390/processor.c index a9adb3782b35..33f49d743b5f 100644 --- a/tools/testing/selftests/kvm/lib/s390/processor.c +++ b/tools/testing/selftests/kvm/lib/s390/processor.c @@ -20,9 +20,7 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm) if (vm->mmu.pgd_created) return; - gpa = vm_phy_pages_alloc(vm, PAGES_PER_REGION, - KVM_GUEST_PAGE_TABLE_MIN_PADDR, - vm->memslots[MEM_REGION_PT]); + gpa = vm_alloc_page_table_pages(vm, PAGES_PER_REGION); memset(addr_gpa2hva(vm, gpa), 0xff, PAGES_PER_REGION * vm->page_size); vm->mmu.pgd = gpa; @@ -38,8 +36,7 @@ static u64 virt_alloc_region(struct kvm_vm *vm, int ri) { u64 taddr; - taddr = vm_phy_pages_alloc(vm, ri < 4 ? PAGES_PER_REGION : 1, - KVM_GUEST_PAGE_TABLE_MIN_PADDR, 0); + taddr = vm_alloc_page_table_pages(vm, ri < 4 ? PAGES_PER_REGION : 1); memset(addr_gpa2hva(vm, taddr), 0xff, PAGES_PER_REGION * vm->page_size); return (taddr & REGION_ENTRY_ORIGIN) diff --git a/tools/testing/selftests/kvm/lib/userfaultfd_util.c b/tools/testing/selftests/kvm/lib/userfaultfd_util.c index f7ce5a6ddcc2..49eff05b7d39 100644 --- a/tools/testing/selftests/kvm/lib/userfaultfd_util.c +++ b/tools/testing/selftests/kvm/lib/userfaultfd_util.c @@ -119,13 +119,13 @@ struct uffd_desc *uffd_setup_demand_paging(int uffd_mode, useconds_t delay, uffd_desc = malloc(sizeof(struct uffd_desc)); TEST_ASSERT(uffd_desc, "Failed to malloc uffd descriptor"); - uffd_desc->pipefds = calloc(sizeof(int), num_readers); + uffd_desc->pipefds = calloc(num_readers, sizeof(int)); TEST_ASSERT(uffd_desc->pipefds, "Failed to alloc pipes"); - uffd_desc->readers = calloc(sizeof(pthread_t), num_readers); + uffd_desc->readers = calloc(num_readers, sizeof(pthread_t)); TEST_ASSERT(uffd_desc->readers, "Failed to alloc reader threads"); - uffd_desc->reader_args = calloc(sizeof(struct uffd_reader_args), num_readers); + uffd_desc->reader_args = calloc(num_readers, sizeof(struct uffd_reader_args)); TEST_ASSERT(uffd_desc->reader_args, "Failed to alloc reader_args"); uffd_desc->num_readers = num_readers; diff --git a/tools/testing/selftests/kvm/lib/x86/memstress.c b/tools/testing/selftests/kvm/lib/x86/memstress.c index e19e8b5a09c5..9bfea36144a7 100644 --- a/tools/testing/selftests/kvm/lib/x86/memstress.c +++ b/tools/testing/selftests/kvm/lib/x86/memstress.c @@ -33,15 +33,15 @@ __asm__( static void l1_vmx_code(struct vmx_pages *vmx, u64 vcpu_id) { GUEST_ASSERT(vmx->vmcs_gpa); - GUEST_ASSERT(prepare_for_vmx_operation(vmx)); - GUEST_ASSERT(load_vmcs(vmx)); + prepare_for_vmx_operation(vmx); + load_vmcs(vmx); GUEST_ASSERT(ept_1g_pages_supported()); *(u64 *)vmx->stack = vcpu_id; prepare_vmcs(vmx, memstress_l2_guest_entry); - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_VMCALL); + vmlaunch(); + GUEST_ASSERT_EQ(vmread(VM_EXIT_REASON), EXIT_REASON_VMCALL); GUEST_DONE(); } diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index d31fa81ea075..8374afd08baf 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -26,6 +26,8 @@ bool host_cpu_is_amd; bool host_cpu_is_intel; bool host_cpu_is_hygon; bool host_cpu_is_amd_compatible; +bool host_cpu_is_zhaoxin; +bool host_cpu_is_intel_compatible; bool is_forced_emulation_enabled; u64 guest_tsc_khz; struct kvm_mmu guest_mmu; @@ -158,7 +160,7 @@ static void sregs_dump(FILE *stream, struct kvm_sregs *sregs, u8 indent) bool kvm_is_tdp_enabled(void) { - if (host_cpu_is_intel) + if (host_cpu_is_intel_compatible) return get_kvm_intel_param_bool("ept"); else return get_kvm_amd_param_bool("npt"); @@ -529,7 +531,10 @@ void tdp_identity_map_default_memslots(struct kvm_vm *vm) /* Only memslot 0 is mapped here, ensure it's the only one being used */ for (s = 0; s < NR_MEM_REGIONS; s++) - TEST_ASSERT_EQ(vm->memslots[s], 0); + TEST_ASSERT(!vm->memslots[s] || + vm->memslots[s] == KVM_INVALID_MEMSLOT, + "Unhandled memslot '%u' for type '%u'", + vm->memslots[s], s); i = (region->region.guest_phys_addr >> vm->page_shift) - 1; last = i + (region->region.memory_size >> vm->page_shift); @@ -819,6 +824,8 @@ void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus) sync_global_to_guest(vm, host_cpu_is_amd); sync_global_to_guest(vm, host_cpu_is_hygon); sync_global_to_guest(vm, host_cpu_is_amd_compatible); + sync_global_to_guest(vm, host_cpu_is_zhaoxin); + sync_global_to_guest(vm, host_cpu_is_intel_compatible); sync_global_to_guest(vm, is_forced_emulation_enabled); sync_global_to_guest(vm, pmu_errata_mask); @@ -1444,6 +1451,8 @@ void kvm_selftest_arch_init(void) host_cpu_is_amd = this_cpu_is_amd(); host_cpu_is_hygon = this_cpu_is_hygon(); host_cpu_is_amd_compatible = host_cpu_is_amd || host_cpu_is_hygon; + host_cpu_is_zhaoxin = this_cpu_is_zhaoxin(); + host_cpu_is_intel_compatible = host_cpu_is_intel || host_cpu_is_zhaoxin; is_forced_emulation_enabled = kvm_is_forced_emulation_enabled(); kvm_init_pmu_errata(); @@ -1465,13 +1474,13 @@ bool kvm_arch_has_default_irqchip(void) return true; } -void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, u64 smram_gpa, +void setup_smram(struct kvm_vm *vm, struct kvm_vcpu *vcpu, gpa_t smram_gpa, const void *smi_handler, size_t handler_size) { - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, smram_gpa, - SMRAM_MEMSLOT, SMRAM_PAGES, 0); - TEST_ASSERT(vm_phy_pages_alloc(vm, SMRAM_PAGES, smram_gpa, - SMRAM_MEMSLOT) == smram_gpa, + vm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS, + smram_gpa, SMRAM_MEMSLOT, SMRAM_PAGES); + + TEST_ASSERT(vm_phy_pages_alloc(vm, SMRAM_PAGES, MEM_REGION_TEST_EXTRA) == smram_gpa, "Could not allocate guest physical addresses for SMRAM"); memset(addr_gpa2hva(vm, smram_gpa), 0x0, SMRAM_SIZE); diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c index 089e1a8af53f..5a06746ebea4 100644 --- a/tools/testing/selftests/kvm/lib/x86/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86/vmx.c @@ -125,7 +125,7 @@ vcpu_alloc_vmx(struct kvm_vm *vm, gva_t *p_vmx_gva) return vmx; } -bool prepare_for_vmx_operation(struct vmx_pages *vmx) +void prepare_for_vmx_operation(struct vmx_pages *vmx) { u64 feature_control; u64 required; @@ -163,28 +163,75 @@ bool prepare_for_vmx_operation(struct vmx_pages *vmx) /* Enter VMX root operation. */ *(u32 *)(vmx->vmxon) = vmcs_revision(); - if (vmxon(vmx->vmxon_gpa)) - return false; - - return true; + vmxon(vmx->vmxon_gpa); } -bool load_vmcs(struct vmx_pages *vmx) +void load_vmcs(struct vmx_pages *vmx) { /* Load a VMCS. */ *(u32 *)(vmx->vmcs) = vmcs_revision(); - if (vmclear(vmx->vmcs_gpa)) - return false; + vmclear(vmx->vmcs_gpa); - if (vmptrld(vmx->vmcs_gpa)) - return false; + vmptrld(vmx->vmcs_gpa); /* Setup shadow VMCS, do not load it yet. */ *(u32 *)(vmx->shadow_vmcs) = vmcs_revision() | 0x80000000ul; - if (vmclear(vmx->shadow_vmcs_gpa)) - return false; + vmclear(vmx->shadow_vmcs_gpa); +} + +#define __BUILD_VMX_VM_ENTRY_HELPER(insn, prefix, vmwrite_insn, vmwrite_operand, \ + __host_rsp, __host_rip) \ +static int __##prefix##_##insn(void) \ +{ \ + int ret; \ + \ + __asm__ __volatile__("push $0;" \ + __stringify(vmwrite_insn) " %%rsp, %[host_rsp];" \ + "lea 1f(%%rip), %%rax;" \ + __stringify(vmwrite_insn) " %%rax, %[host_rip];" \ + VMX_SWITCH_GPRS_ASM \ + __stringify(insn)";" \ + "incq (%%rsp);" \ + "1: ;" \ + VMX_SWITCH_GPRS_ASM \ + "pop %%rax;" \ + : [ret]"=&a"(ret) \ + : [host_rsp]__stringify(vmwrite_operand)(__host_rsp), \ + [host_rip]__stringify(vmwrite_operand)(__host_rip), \ + GUEST_REGS_OFFSETS \ + : "memory", "cc"); \ + return ret; \ +} + +#define BUILD_VMX_VM_ENTRY_HELPER(insn) \ + __BUILD_VMX_VM_ENTRY_HELPER(insn, _, vmwrite, r, (u64)HOST_RSP, (u64)HOST_RIP) \ + __BUILD_VMX_VM_ENTRY_HELPER(insn, __evmcs, mov, m, \ + current_evmcs->host_rsp, current_evmcs->host_rip) + +BUILD_VMX_VM_ENTRY_HELPER(vmlaunch) +BUILD_VMX_VM_ENTRY_HELPER(vmresume) + +int __vmlaunch(void) +{ + if (enable_evmcs) { + current_evmcs->hv_clean_fields = 0; + return ____evmcs_vmlaunch(); + } + + return ____vmlaunch(); +} + +int __vmresume(void) +{ + if (enable_evmcs) { + /* HOST_RIP */ + current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_GRP1; + /* HOST_RSP */ + current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_HOST_POINTER; + return ____evmcs_vmresume(); + } - return true; + return ____vmresume(); } static bool ept_vpid_cap_supported(u64 mask) @@ -204,8 +251,8 @@ static inline void init_vmcs_control_fields(struct vmx_pages *vmx) { u32 sec_exec_ctl = 0; - vmwrite(VIRTUAL_PROCESSOR_ID, 0); - vmwrite(POSTED_INTR_NV, 0); + __vmwrite(VIRTUAL_PROCESSOR_ID, 0); + __vmwrite(POSTED_INTR_NV, 0); vmwrite(PIN_BASED_VM_EXEC_CONTROL, rdmsr(MSR_IA32_VMX_TRUE_PINBASED_CTLS)); @@ -222,7 +269,7 @@ static inline void init_vmcs_control_fields(struct vmx_pages *vmx) sec_exec_ctl |= SECONDARY_EXEC_ENABLE_EPT; } - if (!vmwrite(SECONDARY_VM_EXEC_CONTROL, sec_exec_ctl)) + if (!__vmwrite(SECONDARY_VM_EXEC_CONTROL, sec_exec_ctl)) vmwrite(CPU_BASED_VM_EXEC_CONTROL, rdmsr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS) | CPU_BASED_ACTIVATE_SECONDARY_CONTROLS); else { @@ -242,16 +289,16 @@ static inline void init_vmcs_control_fields(struct vmx_pages *vmx) VM_ENTRY_IA32E_MODE); /* 64-bit guest */ vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0); vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0); - vmwrite(TPR_THRESHOLD, 0); + __vmwrite(TPR_THRESHOLD, 0); vmwrite(CR0_GUEST_HOST_MASK, 0); vmwrite(CR4_GUEST_HOST_MASK, 0); vmwrite(CR0_READ_SHADOW, get_cr0()); vmwrite(CR4_READ_SHADOW, get_cr4()); - vmwrite(MSR_BITMAP, vmx->msr_gpa); - vmwrite(VMREAD_BITMAP, vmx->vmread_gpa); - vmwrite(VMWRITE_BITMAP, vmx->vmwrite_gpa); + __vmwrite(MSR_BITMAP, vmx->msr_gpa); + __vmwrite(VMREAD_BITMAP, vmx->vmread_gpa); + __vmwrite(VMWRITE_BITMAP, vmx->vmwrite_gpa); } /* @@ -261,7 +308,7 @@ static inline void init_vmcs_control_fields(struct vmx_pages *vmx) */ static inline void init_vmcs_host_state(void) { - u32 exit_controls = vmreadz(VM_EXIT_CONTROLS); + u32 exit_controls = vmread(VM_EXIT_CONTROLS); vmwrite(HOST_ES_SELECTOR, get_es()); vmwrite(HOST_CS_SELECTOR, get_cs()); @@ -301,23 +348,23 @@ static inline void init_vmcs_host_state(void) */ static inline void init_vmcs_guest_state(void *rip, void *rsp) { - vmwrite(GUEST_ES_SELECTOR, vmreadz(HOST_ES_SELECTOR)); - vmwrite(GUEST_CS_SELECTOR, vmreadz(HOST_CS_SELECTOR)); - vmwrite(GUEST_SS_SELECTOR, vmreadz(HOST_SS_SELECTOR)); - vmwrite(GUEST_DS_SELECTOR, vmreadz(HOST_DS_SELECTOR)); - vmwrite(GUEST_FS_SELECTOR, vmreadz(HOST_FS_SELECTOR)); - vmwrite(GUEST_GS_SELECTOR, vmreadz(HOST_GS_SELECTOR)); + vmwrite(GUEST_ES_SELECTOR, vmread(HOST_ES_SELECTOR)); + vmwrite(GUEST_CS_SELECTOR, vmread(HOST_CS_SELECTOR)); + vmwrite(GUEST_SS_SELECTOR, vmread(HOST_SS_SELECTOR)); + vmwrite(GUEST_DS_SELECTOR, vmread(HOST_DS_SELECTOR)); + vmwrite(GUEST_FS_SELECTOR, vmread(HOST_FS_SELECTOR)); + vmwrite(GUEST_GS_SELECTOR, vmread(HOST_GS_SELECTOR)); vmwrite(GUEST_LDTR_SELECTOR, 0); - vmwrite(GUEST_TR_SELECTOR, vmreadz(HOST_TR_SELECTOR)); - vmwrite(GUEST_INTR_STATUS, 0); - vmwrite(GUEST_PML_INDEX, 0); + vmwrite(GUEST_TR_SELECTOR, vmread(HOST_TR_SELECTOR)); + __vmwrite(GUEST_INTR_STATUS, 0); + __vmwrite(GUEST_PML_INDEX, 0); vmwrite(VMCS_LINK_POINTER, -1ll); vmwrite(GUEST_IA32_DEBUGCTL, 0); - vmwrite(GUEST_IA32_PAT, vmreadz(HOST_IA32_PAT)); - vmwrite(GUEST_IA32_EFER, vmreadz(HOST_IA32_EFER)); - vmwrite(GUEST_IA32_PERF_GLOBAL_CTRL, - vmreadz(HOST_IA32_PERF_GLOBAL_CTRL)); + __vmwrite(GUEST_IA32_PAT, vmread(HOST_IA32_PAT)); + __vmwrite(GUEST_IA32_EFER, vmread(HOST_IA32_EFER)); + __vmwrite(GUEST_IA32_PERF_GLOBAL_CTRL, + vmread(HOST_IA32_PERF_GLOBAL_CTRL)); vmwrite(GUEST_ES_LIMIT, -1); vmwrite(GUEST_CS_LIMIT, -1); @@ -330,42 +377,42 @@ static inline void init_vmcs_guest_state(void *rip, void *rsp) vmwrite(GUEST_GDTR_LIMIT, 0xffff); vmwrite(GUEST_IDTR_LIMIT, 0xffff); vmwrite(GUEST_ES_AR_BYTES, - vmreadz(GUEST_ES_SELECTOR) == 0 ? 0x10000 : 0xc093); + vmread(GUEST_ES_SELECTOR) == 0 ? 0x10000 : 0xc093); vmwrite(GUEST_CS_AR_BYTES, 0xa09b); vmwrite(GUEST_SS_AR_BYTES, 0xc093); vmwrite(GUEST_DS_AR_BYTES, - vmreadz(GUEST_DS_SELECTOR) == 0 ? 0x10000 : 0xc093); + vmread(GUEST_DS_SELECTOR) == 0 ? 0x10000 : 0xc093); vmwrite(GUEST_FS_AR_BYTES, - vmreadz(GUEST_FS_SELECTOR) == 0 ? 0x10000 : 0xc093); + vmread(GUEST_FS_SELECTOR) == 0 ? 0x10000 : 0xc093); vmwrite(GUEST_GS_AR_BYTES, - vmreadz(GUEST_GS_SELECTOR) == 0 ? 0x10000 : 0xc093); + vmread(GUEST_GS_SELECTOR) == 0 ? 0x10000 : 0xc093); vmwrite(GUEST_LDTR_AR_BYTES, 0x10000); vmwrite(GUEST_TR_AR_BYTES, 0x8b); vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); vmwrite(GUEST_ACTIVITY_STATE, 0); - vmwrite(GUEST_SYSENTER_CS, vmreadz(HOST_IA32_SYSENTER_CS)); - vmwrite(VMX_PREEMPTION_TIMER_VALUE, 0); + vmwrite(GUEST_SYSENTER_CS, vmread(HOST_IA32_SYSENTER_CS)); + __vmwrite(VMX_PREEMPTION_TIMER_VALUE, 0); - vmwrite(GUEST_CR0, vmreadz(HOST_CR0)); - vmwrite(GUEST_CR3, vmreadz(HOST_CR3)); - vmwrite(GUEST_CR4, vmreadz(HOST_CR4)); + vmwrite(GUEST_CR0, vmread(HOST_CR0)); + vmwrite(GUEST_CR3, vmread(HOST_CR3)); + vmwrite(GUEST_CR4, vmread(HOST_CR4)); vmwrite(GUEST_ES_BASE, 0); vmwrite(GUEST_CS_BASE, 0); vmwrite(GUEST_SS_BASE, 0); vmwrite(GUEST_DS_BASE, 0); - vmwrite(GUEST_FS_BASE, vmreadz(HOST_FS_BASE)); - vmwrite(GUEST_GS_BASE, vmreadz(HOST_GS_BASE)); + vmwrite(GUEST_FS_BASE, vmread(HOST_FS_BASE)); + vmwrite(GUEST_GS_BASE, vmread(HOST_GS_BASE)); vmwrite(GUEST_LDTR_BASE, 0); - vmwrite(GUEST_TR_BASE, vmreadz(HOST_TR_BASE)); - vmwrite(GUEST_GDTR_BASE, vmreadz(HOST_GDTR_BASE)); - vmwrite(GUEST_IDTR_BASE, vmreadz(HOST_IDTR_BASE)); + vmwrite(GUEST_TR_BASE, vmread(HOST_TR_BASE)); + vmwrite(GUEST_GDTR_BASE, vmread(HOST_GDTR_BASE)); + vmwrite(GUEST_IDTR_BASE, vmread(HOST_IDTR_BASE)); vmwrite(GUEST_DR7, 0x400); vmwrite(GUEST_RSP, (u64)rsp); vmwrite(GUEST_RIP, (u64)rip); vmwrite(GUEST_RFLAGS, X86_EFLAGS_FIXED); vmwrite(GUEST_PENDING_DBG_EXCEPTIONS, 0); - vmwrite(GUEST_SYSENTER_ESP, vmreadz(HOST_IA32_SYSENTER_ESP)); - vmwrite(GUEST_SYSENTER_EIP, vmreadz(HOST_IA32_SYSENTER_EIP)); + vmwrite(GUEST_SYSENTER_ESP, vmread(HOST_IA32_SYSENTER_ESP)); + vmwrite(GUEST_SYSENTER_EIP, vmread(HOST_IA32_SYSENTER_EIP)); } void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip) @@ -375,19 +422,19 @@ void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip) init_vmcs_guest_state(guest_rip, vmx->stack); } -bool kvm_cpu_has_ept(void) +bool kvm_cpu_has_secondary_exec_control(u32 ctrl) { - u64 ctrl; + u64 ctrl_msr; if (!kvm_cpu_has(X86_FEATURE_VMX)) return false; - ctrl = kvm_get_feature_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS) >> 32; - if (!(ctrl & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)) + ctrl_msr = kvm_get_feature_msr(MSR_IA32_VMX_TRUE_PROCBASED_CTLS) >> 32; + if (!(ctrl_msr & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS)) return false; - ctrl = kvm_get_feature_msr(MSR_IA32_VMX_PROCBASED_CTLS2) >> 32; - return ctrl & SECONDARY_EXEC_ENABLE_EPT; + ctrl_msr = kvm_get_feature_msr(MSR_IA32_VMX_PROCBASED_CTLS2) >> 32; + return ctrl_msr & ctrl; } void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm) diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c index e1299611be32..1e241390e11e 100644 --- a/tools/testing/selftests/kvm/memslot_perf_test.c +++ b/tools/testing/selftests/kvm/memslot_perf_test.c @@ -152,7 +152,7 @@ static void *vcpu_worker(void *__data) case UCALL_SYNC: TEST_ASSERT(uc.args[1] == 0, "Unexpected sync ucall, got %lx", - (ulong)uc.args[1]); + (unsigned long)uc.args[1]); sem_post(&vcpu_ready); continue; case UCALL_NONE: @@ -339,7 +339,8 @@ static bool prepare_vm(struct vm_data *data, int nslots, u64 *maxslots, if (slot == data->nslots) npages += rempages; - gpa = vm_phy_pages_alloc(data->vm, npages, guest_addr, slot); + gpa = ____vm_phy_pages_alloc(data->vm, npages, guest_addr, slot, + false, false); TEST_ASSERT(gpa == guest_addr, "vm_phy_pages_alloc() failed"); diff --git a/tools/testing/selftests/kvm/s390/cmma_test.c b/tools/testing/selftests/kvm/s390/cmma_test.c index 15d81b2ed7ad..73387cc3bca7 100644 --- a/tools/testing/selftests/kvm/s390/cmma_test.c +++ b/tools/testing/selftests/kvm/s390/cmma_test.c @@ -102,24 +102,17 @@ static void guest_dirty_test_data(void) static void create_main_memslot(struct kvm_vm *vm) { - int i; - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0, 0, MAIN_PAGE_COUNT, 0); - /* set the array of memslots to zero like __vm_create does */ - for (i = 0; i < NR_MEM_REGIONS; i++) - vm->memslots[i] = 0; + ____vm_override_mem_region(vm, MEM_REGION_CODE, 0); + ____vm_override_mem_region(vm, MEM_REGION_PT, 0); + ____vm_override_mem_region(vm, MEM_REGION_DATA, 0); } static void create_test_memslot(struct kvm_vm *vm) { - vm_userspace_mem_region_add(vm, - VM_MEM_SRC_ANONYMOUS, - TEST_DATA_START_GFN << vm->page_shift, - TEST_DATA_MEMSLOT, - TEST_DATA_PAGE_COUNT, - 0 - ); - vm->memslots[MEM_REGION_TEST_DATA] = TEST_DATA_MEMSLOT; + vm_override_mem_region(vm, MEM_REGION_TEST_DATA, VM_MEM_SRC_ANONYMOUS, + TEST_DATA_START_GFN << vm->page_shift, + TEST_DATA_MEMSLOT, TEST_DATA_PAGE_COUNT); } static void create_memslots(struct kvm_vm *vm) diff --git a/tools/testing/selftests/kvm/s390/irq_routing.c b/tools/testing/selftests/kvm/s390/irq_routing.c index f3839284ac08..cd26cc1aed80 100644 --- a/tools/testing/selftests/kvm/s390/irq_routing.c +++ b/tools/testing/selftests/kvm/s390/irq_routing.c @@ -36,7 +36,7 @@ static void test(void) }; vm = vm_create_with_one_vcpu(&vcpu, guest_code); - mem = vm_phy_pages_alloc(vm, 2, 4096 * 42, 0); + mem = ____vm_phy_pages_alloc(vm, 2, 4096 * 42, 0, false, false); routing = kvm_gsi_routing_create(); routing->nr = 1; diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index dffe9654f45b..bfa5ac8ce029 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -116,15 +116,15 @@ static struct kvm_vm *spawn_vm(struct kvm_vcpu **vcpu, pthread_t *vcpu_thread, vm = vm_create_with_one_vcpu(vcpu, guest_code); - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS_THP, - MEM_REGION_GPA, MEM_REGION_SLOT, - MEM_REGION_SIZE / getpagesize(), 0); + vm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS_THP, + MEM_REGION_GPA, MEM_REGION_SLOT, + MEM_REGION_SIZE / getpagesize()); /* * Allocate and map two pages so that the GPA accessed by guest_code() * stays valid across the memslot move. */ - gpa = vm_phy_pages_alloc(vm, 2, MEM_REGION_GPA, MEM_REGION_SLOT); + gpa = vm_phy_pages_alloc(vm, 2, MEM_REGION_TEST_EXTRA); TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc\n"); virt_map(vm, MEM_REGION_GPA, MEM_REGION_GPA, 2); diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index 785d19f9ee8f..82b94a82dd03 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -76,12 +76,12 @@ static void steal_time_init(struct kvm_vcpu *vcpu, u32 i) WRITE_AND_SYNC_TO_GUEST(vcpu->vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE)); - vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_MSR_ENABLED); + vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, (unsigned long)st_gva[i] | KVM_MSR_ENABLED); } static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx) { - struct kvm_steal_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); + struct kvm_steal_time *st = addr_gva2hva(vm, (unsigned long)st_gva[vcpu_idx]); ksft_print_msg("VCPU%d:\n", vcpu_idx); ksft_print_msg(" steal: %lld\n", st->steal); @@ -105,7 +105,7 @@ static void check_steal_time_uapi(void) vm = vm_create_with_one_vcpu(&vcpu, NULL); ret = _vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, - (ulong)ST_GPA_BASE | KVM_STEAL_RESERVED_MASK); + (unsigned long)ST_GPA_BASE | KVM_STEAL_RESERVED_MASK); TEST_ASSERT(ret == 0, "Bad GPA didn't fail"); kvm_vm_free(vm); @@ -154,7 +154,7 @@ static void guest_code(int cpu) status = smccc(PV_TIME_ST, 0); GUEST_ASSERT_NE(status, -1); - GUEST_ASSERT_EQ(status, (ulong)st_gva[cpu]); + GUEST_ASSERT_EQ(status, (unsigned long)st_gva[cpu]); st = (struct st_time *)status; GUEST_SYNC(0); @@ -192,13 +192,13 @@ static void steal_time_init(struct kvm_vcpu *vcpu, u32 i) /* ST_GPA_BASE is identity mapped */ WRITE_AND_SYNC_TO_GUEST(vm, st_gva[i], (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE)); - st_ipa = (ulong)st_gva[i]; + st_ipa = (unsigned long)st_gva[i]; vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); } static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx) { - struct st_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); + struct st_time *st = addr_gva2hva(vm, (unsigned long)st_gva[vcpu_idx]); ksft_print_msg("VCPU%d:\n", vcpu_idx); ksft_print_msg(" rev: %d\n", st->rev); @@ -222,11 +222,11 @@ static void check_steal_time_uapi(void) vm = vm_create_steal_time(1, NULL, &vcpu); vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev); - st_ipa = (ulong)ST_GPA_BASE | 1; + st_ipa = (unsigned long)ST_GPA_BASE | 1; ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); TEST_ASSERT(ret == -1 && errno == EINVAL, "Bad IPA didn't report EINVAL"); - st_ipa = (ulong)ST_GPA_BASE; + st_ipa = (unsigned long)ST_GPA_BASE; vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); @@ -315,7 +315,7 @@ static void steal_time_init(struct kvm_vcpu *vcpu, u32 i) static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx) { - struct sta_struct *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); + struct sta_struct *st = addr_gva2hva(vm, (unsigned long)st_gva[vcpu_idx]); int i; pr_info("VCPU%d:\n", vcpu_idx); @@ -451,7 +451,7 @@ static void steal_time_init(struct kvm_vcpu *vcpu, u32 i) static void steal_time_dump(struct kvm_vm *vm, u32 vcpu_idx) { - struct kvm_steal_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); + struct kvm_steal_time *st = addr_gva2hva(vm, (unsigned long)st_gva[vcpu_idx]); ksft_print_msg("VCPU%d:\n", vcpu_idx); ksft_print_msg(" steal: %lld\n", st->steal); diff --git a/tools/testing/selftests/kvm/x86/amx_test.c b/tools/testing/selftests/kvm/x86/amx_test.c index 4e63da2b1889..66b6e442c41c 100644 --- a/tools/testing/selftests/kvm/x86/amx_test.c +++ b/tools/testing/selftests/kvm/x86/amx_test.c @@ -325,7 +325,7 @@ int main(int argc, char *argv[]) vcpu_regs_get(vcpu, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", - (ulong) regs2.rdi, (ulong) regs2.rsi); + (unsigned long)regs2.rdi, (unsigned long)regs2.rsi); } break; case UCALL_DONE: diff --git a/tools/testing/selftests/kvm/x86/aperfmperf_test.c b/tools/testing/selftests/kvm/x86/aperfmperf_test.c index 845cb685f174..1ca6495a446f 100644 --- a/tools/testing/selftests/kvm/x86/aperfmperf_test.c +++ b/tools/testing/selftests/kvm/x86/aperfmperf_test.c @@ -70,8 +70,8 @@ static void l1_svm_code(struct svm_test_data *svm) static void l1_vmx_code(struct vmx_pages *vmx) { - GUEST_ASSERT_EQ(prepare_for_vmx_operation(vmx), true); - GUEST_ASSERT_EQ(load_vmcs(vmx), true); + prepare_for_vmx_operation(vmx); + load_vmcs(vmx); prepare_vmcs(vmx, NULL); @@ -80,10 +80,10 @@ static void l1_vmx_code(struct vmx_pages *vmx) * in the VMCS by prepare_vmcs()), as MSR exiting mandatory on Intel. */ vmwrite(CPU_BASED_VM_EXEC_CONTROL, - vmreadz(CPU_BASED_VM_EXEC_CONTROL) | CPU_BASED_USE_MSR_BITMAPS); + vmread(CPU_BASED_VM_EXEC_CONTROL) | CPU_BASED_USE_MSR_BITMAPS); - GUEST_ASSERT(!vmwrite(GUEST_RIP, (u64)l2_guest_code)); - GUEST_ASSERT(!vmlaunch()); + vmwrite(GUEST_RIP, (u64)l2_guest_code); + vmlaunch(); } static void guest_code(void *nested_test_data) diff --git a/tools/testing/selftests/kvm/x86/cpuid_test.c b/tools/testing/selftests/kvm/x86/cpuid_test.c index ef0ddd240887..dcd99a0501ee 100644 --- a/tools/testing/selftests/kvm/x86/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86/cpuid_test.c @@ -128,7 +128,7 @@ static void run_vcpu(struct kvm_vcpu *vcpu, int stage) TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage + 1, "Stage %d: Unexpected register values vmexit, got %lx", - stage + 1, (ulong)uc.args[1]); + stage + 1, (unsigned long)uc.args[1]); return; case UCALL_DONE: return; diff --git a/tools/testing/selftests/kvm/x86/evmcs_smm_controls_test.c b/tools/testing/selftests/kvm/x86/evmcs_smm_controls_test.c index aa7f3b405fd3..4a65eb02349c 100644 --- a/tools/testing/selftests/kvm/x86/evmcs_smm_controls_test.c +++ b/tools/testing/selftests/kvm/x86/evmcs_smm_controls_test.c @@ -55,11 +55,11 @@ static void guest_code(struct vmx_pages *vmx_pages, enable_vp_assist(hv_pages->vp_assist_gpa, hv_pages->vp_assist); evmcs_enable(); - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_evmcs(hv_pages)); + prepare_for_vmx_operation(vmx_pages); + load_evmcs(hv_pages); prepare_vmcs(vmx_pages, l2_guest_code); - GUEST_ASSERT(!vmlaunch()); + vmlaunch(); /* L2 exits via vmcall if test fails */ sync_with_host(2); diff --git a/tools/testing/selftests/kvm/x86/feature_msrs_test.c b/tools/testing/selftests/kvm/x86/feature_msrs_test.c index 158550701771..d56d0ddb3a57 100644 --- a/tools/testing/selftests/kvm/x86/feature_msrs_test.c +++ b/tools/testing/selftests/kvm/x86/feature_msrs_test.c @@ -59,7 +59,7 @@ static void test_feature_msr(u32 msr) * but initializes the vCPU's revision ID to an arbitrary value. */ if (msr == MSR_IA32_UCODE_REV) - reset_value = host_cpu_is_intel ? 0x100000000ULL : 0x01000065; + reset_value = host_cpu_is_intel_compatible ? 0x100000000ULL : 0x01000065; /* * For quirked MSRs, KVM's ABI is to initialize the vCPU's value to the diff --git a/tools/testing/selftests/kvm/x86/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86/fix_hypercall_test.c index 4931ec22768e..f11fcc520f24 100644 --- a/tools/testing/selftests/kvm/x86/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86/fix_hypercall_test.c @@ -48,7 +48,7 @@ static void guest_main(void) const u8 *other_hypercall_insn; u64 ret; - if (host_cpu_is_intel) { + if (host_cpu_is_intel_compatible) { native_hypercall_insn = vmx_vmcall; other_hypercall_insn = svm_vmmcall; } else if (host_cpu_is_amd_compatible) { diff --git a/tools/testing/selftests/kvm/x86/hyperv_clock.c b/tools/testing/selftests/kvm/x86/hyperv_clock.c index d5d779623cc6..7a1b3b5d1e62 100644 --- a/tools/testing/selftests/kvm/x86/hyperv_clock.c +++ b/tools/testing/selftests/kvm/x86/hyperv_clock.c @@ -248,7 +248,7 @@ int main(void) TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx", - stage, (ulong)uc.args[1]); + stage, (unsigned long)uc.args[1]); /* Reset kvmclock triggering TSC page update */ if (stage == 7 || stage == 8 || stage == 10) { diff --git a/tools/testing/selftests/kvm/x86/hyperv_evmcs.c b/tools/testing/selftests/kvm/x86/hyperv_evmcs.c index 63ea1533e4ea..c81f2dd4f2a1 100644 --- a/tools/testing/selftests/kvm/x86/hyperv_evmcs.c +++ b/tools/testing/selftests/kvm/x86/hyperv_evmcs.c @@ -23,7 +23,11 @@ static int ud_count; static void guest_ud_handler(struct ex_regs *regs) { ud_count++; - regs->rip += 3; /* VMLAUNCH */ + /* + * VMLAUNCH insn can't be easily covered by KVM_ASM_SAFE framework but + * luckily the instruction is always three bytes. + */ + regs->rip += 3; } static void guest_nmi_handler(struct ex_regs *regs) @@ -89,24 +93,23 @@ void guest_code(struct vmx_pages *vmx_pages, struct hyperv_test_pages *hv_pages, enable_vp_assist(hv_pages->vp_assist_gpa, hv_pages->vp_assist); evmcs_enable(); - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); GUEST_SYNC(3); - GUEST_ASSERT(load_evmcs(hv_pages)); - GUEST_ASSERT(vmptrstz() == hv_pages->enlightened_vmcs_gpa); + load_evmcs(hv_pages); + /* VMPTRST returns -1 until VMLAUNCH with eVMCS ptr set */ + GUEST_ASSERT(vmptrst() == -1); GUEST_SYNC(4); - GUEST_ASSERT(vmptrstz() == hv_pages->enlightened_vmcs_gpa); prepare_vmcs(vmx_pages, l2_guest_code); GUEST_SYNC(5); - GUEST_ASSERT(vmptrstz() == hv_pages->enlightened_vmcs_gpa); current_evmcs->revision_id = -1u; - GUEST_ASSERT(vmlaunch()); + GUEST_ASSERT(__vmlaunch()); current_evmcs->revision_id = EVMCS_VERSION; GUEST_SYNC(6); - vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmreadz(PIN_BASED_VM_EXEC_CONTROL) | + vmwrite(PIN_BASED_VM_EXEC_CONTROL, vmread(PIN_BASED_VM_EXEC_CONTROL) | PIN_BASED_NMI_EXITING); /* L2 TLB flush setup */ @@ -117,71 +120,79 @@ void guest_code(struct vmx_pages *vmx_pages, struct hyperv_test_pages *hv_pages, current_vp_assist->nested_control.features.directhypercall = 1; *(u32 *)(hv_pages->partition_assist) = 0; - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_EXCEPTION_NMI); - GUEST_ASSERT_EQ((vmreadz(VM_EXIT_INTR_INFO) & 0xff), NMI_VECTOR); - GUEST_ASSERT(vmptrstz() == hv_pages->enlightened_vmcs_gpa); + vmlaunch(); + GUEST_ASSERT_EQ(vmread(VM_EXIT_REASON), EXIT_REASON_EXCEPTION_NMI); + GUEST_ASSERT_EQ((vmread(VM_EXIT_INTR_INFO) & 0xff), NMI_VECTOR); + GUEST_ASSERT(vmptrst() == hv_pages->enlightened_vmcs_gpa); /* * NMI forces L2->L1 exit, resuming L2 and hope that EVMCS is * up-to-date (RIP points where it should and not at the beginning * of l2_guest_code(). GUEST_SYNC(9) checks that. */ - GUEST_ASSERT(!vmresume()); + vmresume(); GUEST_SYNC(10); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); current_evmcs->guest_rip += 3; /* vmcall */ /* Intercept RDMSR 0xc0000100 */ - vmwrite(CPU_BASED_VM_EXEC_CONTROL, vmreadz(CPU_BASED_VM_EXEC_CONTROL) | + vmwrite(CPU_BASED_VM_EXEC_CONTROL, vmread(CPU_BASED_VM_EXEC_CONTROL) | CPU_BASED_USE_MSR_BITMAPS); __set_bit(MSR_FS_BASE & 0x1fff, vmx_pages->msr + 0x400); - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_MSR_READ); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_MSR_READ); current_evmcs->guest_rip += 2; /* rdmsr */ /* Enable enlightened MSR bitmap */ current_evmcs->hv_enlightenments_control.msr_bitmap = 1; - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_MSR_READ); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_MSR_READ); current_evmcs->guest_rip += 2; /* rdmsr */ /* Intercept RDMSR 0xc0000101 without telling KVM about it */ __set_bit(MSR_GS_BASE & 0x1fff, vmx_pages->msr + 0x400); /* Make sure HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP is set */ current_evmcs->hv_clean_fields |= HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP; - GUEST_ASSERT(!vmresume()); + vmresume(); /* Make sure we don't see EXIT_REASON_MSR_READ here so eMSR bitmap works */ - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); current_evmcs->guest_rip += 3; /* vmcall */ /* Now tell KVM we've changed MSR-Bitmap */ current_evmcs->hv_clean_fields &= ~HV_VMX_ENLIGHTENED_CLEAN_FIELD_MSR_BITMAP; - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_MSR_READ); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_MSR_READ); current_evmcs->guest_rip += 2; /* rdmsr */ /* * L2 TLB flush test. First VMCALL should be handled directly by L0, * no VMCALL exit expected. */ - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_MSR_READ); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_MSR_READ); current_evmcs->guest_rip += 2; /* rdmsr */ /* Enable synthetic vmexit */ *(u32 *)(hv_pages->partition_assist) = 1; - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == HV_VMX_SYNTHETIC_EXIT_REASON_TRAP_AFTER_FLUSH); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == HV_VMX_SYNTHETIC_EXIT_REASON_TRAP_AFTER_FLUSH); - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); GUEST_SYNC(11); - /* Try enlightened vmptrld with an incorrect GPA */ + /* VMPTRLD instruction causes #UD after enlightened VMLAUNCH */ + GUEST_ASSERT(__vmptrld(hv_pages->enlightened_vmcs_gpa) == UD_VECTOR); + + /* + * Try enlightened vmptrld with an incorrect GPA. GUEST_SYNC(12) signals + * the host to enable guest_ud_handler() which cannot be enabled beforehand + * to not override the default fixup handler from KVM_ASM_SAFE(). + */ + GUEST_SYNC(12); evmcs_vmptrld(0xdeadbeef, hv_pages->enlightened_vmcs); - GUEST_ASSERT(vmlaunch()); + GUEST_ASSERT(__vmlaunch()); GUEST_ASSERT(ud_count == 1); GUEST_DONE(); } @@ -221,7 +232,7 @@ static struct kvm_vcpu *save_restore_vm(struct kvm_vm *vm, vcpu_regs_get(vcpu, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", - (ulong) regs2.rdi, (ulong) regs2.rsi); + (unsigned long)regs2.rdi, (unsigned long)regs2.rsi); return vcpu; } @@ -253,7 +264,6 @@ int main(int argc, char *argv[]) vcpu_args_set(vcpu, 3, vmx_pages_gva, hv_pages_gva, addr_gva2gpa(vm, hcall_page)); vcpu_set_msr(vcpu, HV_X64_MSR_VP_INDEX, vcpu->id); - vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler); pr_info("Running L1 which uses EVMCS to run L2\n"); @@ -277,13 +287,13 @@ int main(int argc, char *argv[]) /* UCALL_SYNC is handled here. */ TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx", - stage, (ulong)uc.args[1]); + stage, (unsigned long)uc.args[1]); vcpu = save_restore_vm(vm, vcpu); /* Force immediate L2->L1 exit before resuming */ if (stage == 8) { - pr_info("Injecting NMI into L1 before L2 had a chance to run after restore\n"); + pr_debug("Injecting NMI into L1 before L2 had a chance to run after restore\n"); inject_nmi(vcpu); } @@ -293,9 +303,14 @@ int main(int argc, char *argv[]) * KVM_STATE_NESTED_EVMCS is not lost. */ if (stage == 9) { - pr_info("Trying extra KVM_GET_NESTED_STATE/KVM_SET_NESTED_STATE cycle\n"); + pr_debug("Trying extra KVM_GET_NESTED_STATE/KVM_SET_NESTED_STATE cycle\n"); vcpu = save_restore_vm(vm, vcpu); } + + if (stage == 12) { + pr_debug("Trying enlightened VMLAUNCH with an invalid PTR\n"); + vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); + } } done: diff --git a/tools/testing/selftests/kvm/x86/hyperv_svm_test.c b/tools/testing/selftests/kvm/x86/hyperv_svm_test.c index 1f74b0fa9b83..3a3dc31072e8 100644 --- a/tools/testing/selftests/kvm/x86/hyperv_svm_test.c +++ b/tools/testing/selftests/kvm/x86/hyperv_svm_test.c @@ -186,7 +186,7 @@ int main(int argc, char *argv[]) /* UCALL_SYNC is handled here. */ TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx", - stage, (ulong)uc.args[1]); + stage, (unsigned long)uc.args[1]); } diff --git a/tools/testing/selftests/kvm/x86/kvm_buslock_test.c b/tools/testing/selftests/kvm/x86/kvm_buslock_test.c index 25a182be00a9..e1d2730b16ba 100644 --- a/tools/testing/selftests/kvm/x86/kvm_buslock_test.c +++ b/tools/testing/selftests/kvm/x86/kvm_buslock_test.c @@ -42,13 +42,13 @@ static void l1_svm_code(struct svm_test_data *svm) static void l1_vmx_code(struct vmx_pages *vmx) { - GUEST_ASSERT_EQ(prepare_for_vmx_operation(vmx), true); - GUEST_ASSERT_EQ(load_vmcs(vmx), true); + prepare_for_vmx_operation(vmx); + load_vmcs(vmx); prepare_vmcs(vmx, NULL); - GUEST_ASSERT(!vmwrite(GUEST_RIP, (u64)l2_guest_code)); - GUEST_ASSERT(!vmlaunch()); + vmwrite(GUEST_RIP, (u64)l2_guest_code); + vmlaunch(); } static void guest_code(void *test_data) diff --git a/tools/testing/selftests/kvm/x86/nested_close_kvm_test.c b/tools/testing/selftests/kvm/x86/nested_close_kvm_test.c index b974cfb347d6..1f4a5e44a6ef 100644 --- a/tools/testing/selftests/kvm/x86/nested_close_kvm_test.c +++ b/tools/testing/selftests/kvm/x86/nested_close_kvm_test.c @@ -30,13 +30,13 @@ static void l2_guest_code(void) static void l1_vmx_code(struct vmx_pages *vmx_pages) { - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); + load_vmcs(vmx_pages); /* Prepare the VMCS for L2 execution. */ prepare_vmcs(vmx_pages, l2_guest_code); - GUEST_ASSERT(!vmlaunch()); + vmlaunch(); GUEST_ASSERT(0); } diff --git a/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c b/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c index 26b474bf1353..7e5f9ae1cb00 100644 --- a/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c @@ -93,8 +93,8 @@ void l1_vmx_code(struct vmx_pages *vmx) void *l2_rip; GUEST_ASSERT(vmx->vmcs_gpa); - GUEST_ASSERT(prepare_for_vmx_operation(vmx)); - GUEST_ASSERT(load_vmcs(vmx)); + prepare_for_vmx_operation(vmx); + load_vmcs(vmx); if (vmx->eptp_gpa) l2_rip = l2_guest_code_tdp_enabled; @@ -104,9 +104,9 @@ void l1_vmx_code(struct vmx_pages *vmx) prepare_vmcs(vmx, l2_rip); GUEST_SYNC(TEST_SYNC_NO_FAULT); - GUEST_ASSERT(!vmlaunch()); + vmlaunch(); GUEST_SYNC(TEST_SYNC_NO_FAULT); - GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_VMCALL); + GUEST_ASSERT_EQ(vmread(VM_EXIT_REASON), EXIT_REASON_VMCALL); GUEST_DONE(); } diff --git a/tools/testing/selftests/kvm/x86/nested_emulation_test.c b/tools/testing/selftests/kvm/x86/nested_emulation_test.c index e08c6b0697e5..68d9ce9dc6ba 100644 --- a/tools/testing/selftests/kvm/x86/nested_emulation_test.c +++ b/tools/testing/selftests/kvm/x86/nested_emulation_test.c @@ -66,15 +66,15 @@ static void guest_code(void *test_data) BIT_ULL(INTERCEPT_HLT); vmcb->control.intercept_exceptions = 0; } else { - GUEST_ASSERT(prepare_for_vmx_operation(test_data)); - GUEST_ASSERT(load_vmcs(test_data)); + prepare_for_vmx_operation(test_data); + load_vmcs(test_data); prepare_vmcs(test_data, NULL); - GUEST_ASSERT(!vmwrite(GUEST_IDTR_LIMIT, 0)); - GUEST_ASSERT(!vmwrite(GUEST_RIP, (u64)l2_guest_code)); - GUEST_ASSERT(!vmwrite(EXCEPTION_BITMAP, 0)); + vmwrite(GUEST_IDTR_LIMIT, 0); + vmwrite(GUEST_RIP, (u64)l2_guest_code); + vmwrite(EXCEPTION_BITMAP, 0); - vmwrite(CPU_BASED_VM_EXEC_CONTROL, vmreadz(CPU_BASED_VM_EXEC_CONTROL) | + vmwrite(CPU_BASED_VM_EXEC_CONTROL, vmread(CPU_BASED_VM_EXEC_CONTROL) | CPU_BASED_PAUSE_EXITING | CPU_BASED_HLT_EXITING); } @@ -102,10 +102,13 @@ static void guest_code(void *test_data) exit_insn_len = vmcb->control.next_rip - vmcb->save.rip; GUEST_ASSERT_EQ(vmcb->save.rip, (u64)l2_instruction); } else { - GUEST_ASSERT_EQ(i ? vmresume() : vmlaunch(), 0); - exit_reason = vmreadz(VM_EXIT_REASON); - exit_insn_len = vmreadz(VM_EXIT_INSTRUCTION_LEN); - GUEST_ASSERT_EQ(vmreadz(GUEST_RIP), (u64)l2_instruction); + if (!i) + vmlaunch(); + else + vmresume(); + exit_reason = vmread(VM_EXIT_REASON); + exit_insn_len = vmread(VM_EXIT_INSTRUCTION_LEN); + GUEST_ASSERT_EQ(vmread(GUEST_RIP), (u64)l2_instruction); } __GUEST_ASSERT(exit_reason == insn->exit_reason[f], diff --git a/tools/testing/selftests/kvm/x86/nested_exceptions_test.c b/tools/testing/selftests/kvm/x86/nested_exceptions_test.c index aeec3121c8e8..f47432526ea1 100644 --- a/tools/testing/selftests/kvm/x86/nested_exceptions_test.c +++ b/tools/testing/selftests/kvm/x86/nested_exceptions_test.c @@ -38,6 +38,7 @@ */ #define GP_ERROR_CODE_AMD ((SS_VECTOR * 8) | ERROR_CODE_IDT_FLAG) #define GP_ERROR_CODE_INTEL ((SS_VECTOR * 8) | ERROR_CODE_IDT_FLAG | ERROR_CODE_EXT_FLAG) +#define GP_ERROR_CODE_ZHAOXIN ((SS_VECTOR * 8) | ERROR_CODE_IDT_FLAG) /* * Intel and AMD both shove '0' into the error code on #DF, regardless of what @@ -110,43 +111,47 @@ static void l1_svm_code(struct svm_test_data *svm) static void vmx_run_l2(void *l2_code, int vector, u32 error_code) { - GUEST_ASSERT(!vmwrite(GUEST_RIP, (u64)l2_code)); + vmwrite(GUEST_RIP, (u64)l2_code); - GUEST_ASSERT_EQ(vector == SS_VECTOR ? vmlaunch() : vmresume(), 0); + if (vector == SS_VECTOR) + vmlaunch(); + else + vmresume(); if (vector == FAKE_TRIPLE_FAULT_VECTOR) return; - GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_EXCEPTION_NMI); - GUEST_ASSERT_EQ((vmreadz(VM_EXIT_INTR_INFO) & 0xff), vector); - GUEST_ASSERT_EQ(vmreadz(VM_EXIT_INTR_ERROR_CODE), error_code); - GUEST_ASSERT(!vmreadz(GUEST_INTERRUPTIBILITY_INFO)); + GUEST_ASSERT_EQ(vmread(VM_EXIT_REASON), EXIT_REASON_EXCEPTION_NMI); + GUEST_ASSERT_EQ((vmread(VM_EXIT_INTR_INFO) & 0xff), vector); + GUEST_ASSERT_EQ(vmread(VM_EXIT_INTR_ERROR_CODE), error_code); + GUEST_ASSERT(!vmread(GUEST_INTERRUPTIBILITY_INFO)); } static void l1_vmx_code(struct vmx_pages *vmx) { - GUEST_ASSERT_EQ(prepare_for_vmx_operation(vmx), true); + prepare_for_vmx_operation(vmx); - GUEST_ASSERT_EQ(load_vmcs(vmx), true); + load_vmcs(vmx); prepare_vmcs(vmx, NULL); - GUEST_ASSERT_EQ(vmwrite(GUEST_IDTR_LIMIT, 0), 0); + vmwrite(GUEST_IDTR_LIMIT, 0); /* * VMX disallows injecting an exception with error_code[31:16] != 0, * and hardware will never generate a VM-Exit with bits 31:16 set. * KVM should likewise truncate the "bad" userspace value. */ - GUEST_ASSERT_EQ(vmwrite(EXCEPTION_BITMAP, INTERCEPT_SS_GP_DF), 0); + vmwrite(EXCEPTION_BITMAP, INTERCEPT_SS_GP_DF); vmx_run_l2(l2_ss_pending_test, SS_VECTOR, (u16)SS_ERROR_CODE); - vmx_run_l2(l2_ss_injected_gp_test, GP_VECTOR, GP_ERROR_CODE_INTEL); + vmx_run_l2(l2_ss_injected_gp_test, GP_VECTOR, + host_cpu_is_zhaoxin ? GP_ERROR_CODE_ZHAOXIN : GP_ERROR_CODE_INTEL); - GUEST_ASSERT_EQ(vmwrite(EXCEPTION_BITMAP, INTERCEPT_SS_DF), 0); + vmwrite(EXCEPTION_BITMAP, INTERCEPT_SS_DF); vmx_run_l2(l2_ss_injected_df_test, DF_VECTOR, DF_ERROR_CODE); - GUEST_ASSERT_EQ(vmwrite(EXCEPTION_BITMAP, INTERCEPT_SS), 0); + vmwrite(EXCEPTION_BITMAP, INTERCEPT_SS); vmx_run_l2(l2_ss_injected_tf_test, FAKE_TRIPLE_FAULT_VECTOR, 0); - GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_TRIPLE_FAULT); + GUEST_ASSERT_EQ(vmread(VM_EXIT_REASON), EXIT_REASON_TRIPLE_FAULT); GUEST_DONE(); } diff --git a/tools/testing/selftests/kvm/x86/nested_invalid_cr3_test.c b/tools/testing/selftests/kvm/x86/nested_invalid_cr3_test.c index 8c2ba9674558..6e147826bc90 100644 --- a/tools/testing/selftests/kvm/x86/nested_invalid_cr3_test.c +++ b/tools/testing/selftests/kvm/x86/nested_invalid_cr3_test.c @@ -40,22 +40,22 @@ static void l1_vmx_code(struct vmx_pages *vmx_pages) { uintptr_t save_cr3; - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); + load_vmcs(vmx_pages); prepare_vmcs(vmx_pages, l2_guest_code); /* Try to run L2 with invalid CR3 and make sure it fails */ - save_cr3 = vmreadz(GUEST_CR3); + save_cr3 = vmread(GUEST_CR3); vmwrite(GUEST_CR3, -1ull); - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == + vmlaunch(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == (EXIT_REASON_FAILED_VMENTRY | EXIT_REASON_INVALID_STATE)); /* Now restore CR3 and make sure L2 runs successfully */ vmwrite(GUEST_CR3, save_cr3); - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + vmlaunch(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); GUEST_DONE(); } diff --git a/tools/testing/selftests/kvm/x86/nested_tdp_fault_test.c b/tools/testing/selftests/kvm/x86/nested_tdp_fault_test.c index 2e04563790ff..fae77d843b13 100644 --- a/tools/testing/selftests/kvm/x86/nested_tdp_fault_test.c +++ b/tools/testing/selftests/kvm/x86/nested_tdp_fault_test.c @@ -55,25 +55,25 @@ static void l1_vmx_code(struct vmx_pages *vmx, u64 expected_fault_gpa, u64 exit_qual; GUEST_ASSERT(vmx->vmcs_gpa); - GUEST_ASSERT(prepare_for_vmx_operation(vmx)); - GUEST_ASSERT(load_vmcs(vmx)); + prepare_for_vmx_operation(vmx); + load_vmcs(vmx); prepare_vmcs(vmx, l2_entry); - GUEST_ASSERT(!vmlaunch()); + vmlaunch(); /* Verify we got an EPT violation exit */ - __GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_EPT_VIOLATION, + __GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_EPT_VIOLATION, "Expected EPT violation (0x%x), got 0x%lx", EXIT_REASON_EPT_VIOLATION, - vmreadz(VM_EXIT_REASON)); + vmread(VM_EXIT_REASON)); - __GUEST_ASSERT(vmreadz(GUEST_PHYSICAL_ADDRESS) == expected_fault_gpa, + __GUEST_ASSERT(vmread(GUEST_PHYSICAL_ADDRESS) == expected_fault_gpa, "Expected guest_physical_address = 0x%lx, got 0x%lx", expected_fault_gpa, - vmreadz(GUEST_PHYSICAL_ADDRESS)); + vmread(GUEST_PHYSICAL_ADDRESS)); - exit_qual = vmreadz(EXIT_QUALIFICATION); + exit_qual = vmread(EXIT_QUALIFICATION); /* * Note, EPT page table accesses are always read+write, e.g. so that diff --git a/tools/testing/selftests/kvm/x86/nested_tsc_adjust_test.c b/tools/testing/selftests/kvm/x86/nested_tsc_adjust_test.c index cb79d7b9619c..6a1a88e926f8 100644 --- a/tools/testing/selftests/kvm/x86/nested_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86/nested_tsc_adjust_test.c @@ -86,17 +86,17 @@ static void l1_guest_code(void *data) struct vmx_pages *vmx_pages = data; u32 control; - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); + load_vmcs(vmx_pages); prepare_vmcs(vmx_pages, l2_guest_code); - control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); + control = vmread(CPU_BASED_VM_EXEC_CONTROL); control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_USE_TSC_OFFSETTING; vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); vmwrite(TSC_OFFSET, TSC_OFFSET_VALUE); - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + vmlaunch(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); } else { struct svm_test_data *svm = data; diff --git a/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c index 18f765835bf4..bfb1ff441c78 100644 --- a/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c @@ -1,14 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * vmx_nested_tsc_scaling_test - * * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * This test case verifies that nested TSC scaling behaves as expected when - * both L1 and L2 are scaled using different ratios. For this test we scale - * L1 down and scale L2 up. + * both L1 and L2 are scaled using different ratios. */ - +#include <linux/math64.h> #include <time.h> #include "kvm_util.h" @@ -16,16 +13,11 @@ #include "svm_util.h" #include "kselftest.h" -/* L2 is scaled up (from L1's perspective) by this factor */ -#define L2_SCALE_FACTOR 4ULL - -#define TSC_OFFSET_L2 ((u64)-33125236320908) -#define TSC_MULTIPLIER_L2 (L2_SCALE_FACTOR << 48) - -enum { USLEEP, UCHECK_L1, UCHECK_L2 }; -#define GUEST_SLEEP(sec) ucall(UCALL_SYNC, 2, USLEEP, sec) -#define GUEST_CHECK(level, freq) ucall(UCALL_SYNC, 2, level, freq) +/* L2's TSC multiplier and offset, relative to L1. */ +static u64 l2_multiplier; +static u64 l2_offset; +enum ucall_cmd { UCALL_SLEEP, UCALL_CHECK_L1, UCALL_CHECK_L2 }; /* * This function checks whether the "actual" TSC frequency of a guest matches @@ -33,25 +25,20 @@ enum { USLEEP, UCHECK_L1, UCHECK_L2 }; * measurements, a difference of 1% between the actual and the expected value * is tolerated. */ -static void compare_tsc_freq(u64 actual, u64 expected) +static void host_check_tsc_freq(int level, u64 actual, u64 expected) { u64 tolerance, thresh_low, thresh_high; - tolerance = expected / 100; + tolerance = max(expected / 100, (u64)1); thresh_low = expected - tolerance; thresh_high = expected + tolerance; - TEST_ASSERT(thresh_low < actual, - "TSC freq is expected to be between %"PRIu64" and %"PRIu64 - " but it actually is %"PRIu64, - thresh_low, thresh_high, actual); - TEST_ASSERT(thresh_high > actual, - "TSC freq is expected to be between %"PRIu64" and %"PRIu64 - " but it actually is %"PRIu64, - thresh_low, thresh_high, actual); + TEST_ASSERT(thresh_low <= actual && thresh_high >= actual, + "L%u TSC freq is '%lu', expected to be between %lu and %lu", + level, actual, thresh_low, thresh_high); } -static void check_tsc_freq(int level) +static void guest_check_tsc_freq(enum ucall_cmd check_level) { u64 tsc_start, tsc_end, tsc_freq; @@ -62,17 +49,17 @@ static void check_tsc_freq(int level) * be good enough for the purposes of this test. */ tsc_start = rdmsr(MSR_IA32_TSC); - GUEST_SLEEP(1); + GUEST_SYNC2(UCALL_SLEEP, 1); tsc_end = rdmsr(MSR_IA32_TSC); tsc_freq = tsc_end - tsc_start; - GUEST_CHECK(level, tsc_freq); + GUEST_SYNC2(check_level, tsc_freq); } static void l2_guest_code(void) { - check_tsc_freq(UCHECK_L2); + guest_check_tsc_freq(UCALL_CHECK_L2); /* exit to L1 */ __asm__ __volatile__("vmcall"); @@ -81,19 +68,20 @@ static void l2_guest_code(void) static void l1_svm_code(struct svm_test_data *svm) { /* check that L1's frequency looks alright before launching L2 */ - check_tsc_freq(UCHECK_L1); + guest_check_tsc_freq(UCALL_CHECK_L1); generic_svm_setup(svm, l2_guest_code); + svm->vmcb->control.tsc_offset = l2_offset; /* enable TSC scaling for L2 */ - wrmsr(MSR_AMD64_TSC_RATIO, L2_SCALE_FACTOR << 32); + wrmsr(MSR_AMD64_TSC_RATIO, l2_multiplier); /* launch L2 */ run_guest(svm->vmcb, svm->vmcb_gpa); GUEST_ASSERT(svm->vmcb->control.exit_code == SVM_EXIT_VMMCALL); /* check that L1's frequency still looks good */ - check_tsc_freq(UCHECK_L1); + guest_check_tsc_freq(UCALL_CHECK_L1); GUEST_DONE(); } @@ -103,33 +91,32 @@ static void l1_vmx_code(struct vmx_pages *vmx_pages) u32 control; /* check that L1's frequency looks alright before launching L2 */ - check_tsc_freq(UCHECK_L1); + guest_check_tsc_freq(UCALL_CHECK_L1); - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); + load_vmcs(vmx_pages); /* prepare the VMCS for L2 execution */ prepare_vmcs(vmx_pages, l2_guest_code); /* enable TSC offsetting and TSC scaling for L2 */ - control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); + control = vmread(CPU_BASED_VM_EXEC_CONTROL); control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_USE_TSC_OFFSETTING; vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); - control = vmreadz(SECONDARY_VM_EXEC_CONTROL); + control = vmread(SECONDARY_VM_EXEC_CONTROL); control |= SECONDARY_EXEC_TSC_SCALING; vmwrite(SECONDARY_VM_EXEC_CONTROL, control); - vmwrite(TSC_OFFSET, TSC_OFFSET_L2); - vmwrite(TSC_MULTIPLIER, TSC_MULTIPLIER_L2); - vmwrite(TSC_MULTIPLIER_HIGH, TSC_MULTIPLIER_L2 >> 32); + vmwrite(TSC_OFFSET, l2_offset); + vmwrite(TSC_MULTIPLIER, l2_multiplier); /* launch L2 */ - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + vmlaunch(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); /* check that L1's frequency still looks good */ - check_tsc_freq(UCHECK_L1); + guest_check_tsc_freq(UCALL_CHECK_L1); GUEST_DONE(); } @@ -142,43 +129,23 @@ static void l1_guest_code(void *data) l1_svm_code(data); } -int main(int argc, char *argv[]) +static void test_tsc_scaling(u64 l0_tsc_freq, u64 l1_tsc_freq, u64 l2_tsc_freq, + u64 __l2_multiplier) { struct kvm_vcpu *vcpu; struct kvm_vm *vm; - gva_t guest_gva = 0; - - u64 tsc_start, tsc_end; - u64 tsc_khz; - u64 l1_scale_factor; - u64 l0_tsc_freq = 0; - u64 l1_tsc_freq = 0; - u64 l2_tsc_freq = 0; - - TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || - kvm_cpu_has(X86_FEATURE_SVM)); - TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL)); - TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); + gva_t guest_gva; - /* - * We set L1's scale factor to be a random number from 2 to 10. - * Ideally we would do the same for L2's factor but that one is - * referenced by both main() and l1_guest_code() and using a global - * variable does not work. - */ - srand(time(NULL)); - l1_scale_factor = (rand() % 9) + 2; - printf("L1's scale down factor is: %"PRIu64"\n", l1_scale_factor); - printf("L2's scale up factor is: %llu\n", L2_SCALE_FACTOR); + printf("Testing L0 freq = %lu, L1 freq = %lu, L2 freq = %lu, L2 mult = 0x%lx\n", + l0_tsc_freq, l1_tsc_freq, l2_tsc_freq, __l2_multiplier); - tsc_start = rdtsc(); - sleep(1); - tsc_end = rdtsc(); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); - l0_tsc_freq = tsc_end - tsc_start; - printf("real TSC frequency is around: %"PRIu64"\n", l0_tsc_freq); + l2_offset = kvm_random_u64(&kvm_rng); + sync_global_to_guest(vm, l2_offset); - vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); + l2_multiplier = __l2_multiplier; + sync_global_to_guest(vm, l2_multiplier); if (kvm_cpu_has(X86_FEATURE_VMX)) vcpu_alloc_vmx(vm, &guest_gva); @@ -187,11 +154,7 @@ int main(int argc, char *argv[]) vcpu_args_set(vcpu, 1, guest_gva); - tsc_khz = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL); - TEST_ASSERT(tsc_khz != -1, "vcpu ioctl KVM_GET_TSC_KHZ failed"); - - /* scale down L1's TSC frequency */ - vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *) (tsc_khz / l1_scale_factor)); + vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *)(l1_tsc_freq / 1000)); for (;;) { struct ucall uc; @@ -204,24 +167,16 @@ int main(int argc, char *argv[]) REPORT_GUEST_ASSERT(uc); case UCALL_SYNC: switch (uc.args[0]) { - case USLEEP: + case UCALL_SLEEP: sleep(uc.args[1]); break; - case UCHECK_L1: - l1_tsc_freq = uc.args[1]; - printf("L1's TSC frequency is around: %"PRIu64 - "\n", l1_tsc_freq); - - compare_tsc_freq(l1_tsc_freq, - l0_tsc_freq / l1_scale_factor); + case UCALL_CHECK_L1: + printf("L1's observed TSC frequency: %lu\n", uc.args[1]); + host_check_tsc_freq(1, uc.args[1], l1_tsc_freq); break; - case UCHECK_L2: - l2_tsc_freq = uc.args[1]; - printf("L2's TSC frequency is around: %"PRIu64 - "\n", l2_tsc_freq); - - compare_tsc_freq(l2_tsc_freq, - l1_tsc_freq * L2_SCALE_FACTOR); + case UCALL_CHECK_L2: + printf("L2's observed TSC frequency: %lu\n", uc.args[1]); + host_check_tsc_freq(2, uc.args[1], l2_tsc_freq); break; } break; @@ -234,5 +189,108 @@ int main(int argc, char *argv[]) done: kvm_vm_free(vm); +} + +int main(int argc, char *argv[]) +{ + u64 min_freq, min_multiplier, max_freq, max_multiplier, l1_max_freq, l1_min_freq; + u64 l0_tsc_freq, tsc_start, tsc_end, l1_scale, l2_scale; + u8 frac_bits = kvm_cpu_has(X86_FEATURE_VMX) ? 48 : 32; + struct kvm_vm *vm; + + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || + kvm_cpu_has(X86_FEATURE_SVM)); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL)); + TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); + + /* + * Create a dummy VM to get KVM's default TSC frequency. All CPUs that + * support TSC scaling should have a constant TSC, i.e. there's no need + * to calibrate the "real" TSC. But do sanity check that the observed + * TSC is within range of KVM's reported TSC frequency. + */ + vm = vm_create_barebones(); + l0_tsc_freq = (u64)__vm_ioctl(vm, KVM_GET_TSC_KHZ, NULL) * 1000; + TEST_ASSERT(l0_tsc_freq, "vcpu ioctl KVM_GET_TSC_KHZ failed"); + kvm_vm_free(vm); + + printf("L0 TSC frequency is: %lu\n", l0_tsc_freq); + + tsc_start = rdtsc(); + sleep(1); + tsc_end = rdtsc(); + host_check_tsc_freq(0, tsc_end - tsc_start, l0_tsc_freq); + + /* Sanity check the frequency reported by KVM_GET_TSC_KHZ. */ + test_tsc_scaling(l0_tsc_freq, l0_tsc_freq, l0_tsc_freq, BIT_ULL(frac_bits)); + + /* + * Scale L1 and L2 up and down at random factors from 2 to 10. Current + * CPUs have two full orders of magnitude of "breathing room" before an + * ultrafast L0 TSC frequency multiplied by 10x will encounter KVM's + * signed 32-bit limit on L1's frequency, and it's highly unlikely a + * CPU that supports TSC scaling will show up running at 100MHz, i.e. + * underflowing KVM's minimum 1KHz frequency is extremely unlikely. + * + * For L2, the frequency is limited only by what hardware can support, + * not by KVM's limits. SVM provides 8 bits of integer scale up, and + * 32 bits of fractional scale down, i.e. can scale up 255x and down a + * comical amount, so scaling up 100x and down 1/100 is well within + * hardware's capabilities (VMX provides 16 bits of "up" and 48 bits of + * "down"). + */ + l1_scale = (kvm_random_u32(&kvm_rng) % 9) + 2; + l2_scale = (kvm_random_u32(&kvm_rng) % 9) + 2; + + test_tsc_scaling(l0_tsc_freq, l0_tsc_freq / l1_scale, + mul_u64_u64_div64(l0_tsc_freq, l2_scale, l1_scale), + (l2_scale << frac_bits)); + + test_tsc_scaling(l0_tsc_freq, l0_tsc_freq * l1_scale, + mul_u64_u64_div64(l0_tsc_freq, l1_scale, l2_scale), + (1ull << frac_bits) / l2_scale); + + test_tsc_scaling(l0_tsc_freq, l0_tsc_freq / l1_scale, + l0_tsc_freq / l1_scale / l2_scale, + (1ull << frac_bits) / l2_scale); + + test_tsc_scaling(l0_tsc_freq, l0_tsc_freq * l1_scale, + l0_tsc_freq * l1_scale * l2_scale, + (l2_scale << frac_bits)); + + /* + * Test that KVM saturates L2's frequency on both ends if the resulting + * L2 TSC frequency would be below or above what hardware can support. + * Because L2 = L0 * (L1_mult >> frac) * (L2_mult >> frac) needs to be + * distilled down to a single multiplier, very small/large multipliers + * will underflow/overflow the minimum/maximum multiplier supported by + * hardware when L1 and L2 multipliers are combined. KVM's behavior is + * saturate on {under,over}flow, i.e. to run at the min/max frequency. + * + * Note, userspace can only program L1's frequency in KHz, i.e. can't + * specify an exact multiplier. As a result, the minimum and maximum + * frequencies are different for L1 vs L2, because L1 is constrained by + * hardware *and* KVM, whereas L2 is constrained only by hardware. + */ + min_multiplier = 1; + min_freq = mul_u64_u64_div64(l0_tsc_freq, min_multiplier, BIT_ULL(frac_bits)); + min_freq = max(min_freq, (u64)1); + l1_min_freq = max(min_freq, (u64)1 * 1000); + test_tsc_scaling(l0_tsc_freq, l1_min_freq, min_freq, 1); + + /* + * SVM takes a 40-bit value (right shifted by 32), while VMX takes a + * 64-bit value (right shifted by 48). mul_u64_u64_shr() isn't (yet) + * available in selftests, but mul_u64_u64_div64() does nicely since, + * albeit more slowly (performance is obviously not a concern). Note, + * because KVM_GET_TSC_KHZ returns a signed 32-bit integer, KVM limits + * KVM_SET_TSC_KHZ to INT_MAX, even though hardware (both SVM and VMX) + * supports much higher frequencies. + */ + max_multiplier = kvm_cpu_has(X86_FEATURE_VMX) ? -1ull : GENMASK_U64(39, 0); + max_freq = mul_u64_u64_div64(l0_tsc_freq, max_multiplier, BIT_ULL(frac_bits)); + l1_max_freq = min(max_freq, (u64)INT32_MAX * 1000); + test_tsc_scaling(l0_tsc_freq, l1_max_freq, max_freq, max_multiplier); + return 0; } diff --git a/tools/testing/selftests/kvm/x86/nested_x2apic_test.c b/tools/testing/selftests/kvm/x86/nested_x2apic_test.c index ce204ce29a9c..bba301cfc0b5 100644 --- a/tools/testing/selftests/kvm/x86/nested_x2apic_test.c +++ b/tools/testing/selftests/kvm/x86/nested_x2apic_test.c @@ -61,57 +61,55 @@ static void l1_vmx_code(struct vmx_pages *vmx, struct hyperv_test_pages *hv_page evmcs_enable(); } - GUEST_ASSERT_EQ(prepare_for_vmx_operation(vmx), true); + prepare_for_vmx_operation(vmx); if (hv_pages) { - GUEST_ASSERT(load_evmcs(hv_pages)); + load_evmcs(hv_pages); current_evmcs->hv_enlightenments_control.msr_bitmap = 1; } else { - GUEST_ASSERT(load_vmcs(vmx)); + load_vmcs(vmx); } prepare_vmcs(vmx, NULL); - GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, (unsigned long)l2_guest_code), 0); + vmwrite(GUEST_RIP, (unsigned long)l2_guest_code); - control = vmreadz(PIN_BASED_VM_EXEC_CONTROL); + control = vmread(PIN_BASED_VM_EXEC_CONTROL); control |= PIN_BASED_EXT_INTR_MASK; vmwrite(PIN_BASED_VM_EXEC_CONTROL, control); - control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); + control = vmread(CPU_BASED_VM_EXEC_CONTROL); control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_TPR_SHADOW; - GUEST_ASSERT_EQ(vmwrite(CPU_BASED_VM_EXEC_CONTROL, control), 0); + vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); - control = vmreadz(SECONDARY_VM_EXEC_CONTROL); + control = vmread(SECONDARY_VM_EXEC_CONTROL); control |= SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | SECONDARY_EXEC_APIC_REGISTER_VIRT | SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY; control &= (rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2) >> 32); - GUEST_ASSERT_EQ(vmwrite(SECONDARY_VM_EXEC_CONTROL, control), 0); + vmwrite(SECONDARY_VM_EXEC_CONTROL, control), 0; - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_CPUID); - GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, - vmreadz(GUEST_RIP) + vmreadz(VM_EXIT_INSTRUCTION_LEN)), 0); + vmlaunch(); + GUEST_ASSERT_EQ(vmread(VM_EXIT_REASON), EXIT_REASON_CPUID); + vmwrite(GUEST_RIP, vmread(GUEST_RIP) + vmread(VM_EXIT_INSTRUCTION_LEN)); } static void l1_vmx_code_part2(void) { u64 control; - control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); + control = vmread(CPU_BASED_VM_EXEC_CONTROL); control &= ~CPU_BASED_TPR_SHADOW; - GUEST_ASSERT_EQ(vmwrite(CPU_BASED_VM_EXEC_CONTROL, control), 0); + vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); - control = vmreadz(SECONDARY_VM_EXEC_CONTROL); + control = vmread(SECONDARY_VM_EXEC_CONTROL); control &= ~(SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | SECONDARY_EXEC_APIC_REGISTER_VIRT | SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); - GUEST_ASSERT_EQ(vmwrite(SECONDARY_VM_EXEC_CONTROL, control), 0); + vmwrite(SECONDARY_VM_EXEC_CONTROL, control); - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_CPUID); - GUEST_ASSERT_EQ(vmwrite(GUEST_RIP, - vmreadz(GUEST_RIP) + vmreadz(VM_EXIT_INSTRUCTION_LEN)), 0); + vmresume(); + GUEST_ASSERT_EQ(vmread(VM_EXIT_REASON), EXIT_REASON_CPUID); + vmwrite(GUEST_RIP, vmread(GUEST_RIP) + vmread(VM_EXIT_INSTRUCTION_LEN)); } static void l1_test_x2apic_intercepts(void) diff --git a/tools/testing/selftests/kvm/x86/nx_huge_pages_test.c b/tools/testing/selftests/kvm/x86/nx_huge_pages_test.c index 70950067b989..e3b20033a884 100644 --- a/tools/testing/selftests/kvm/x86/nx_huge_pages_test.c +++ b/tools/testing/selftests/kvm/x86/nx_huge_pages_test.c @@ -120,7 +120,7 @@ void run_test(int reclaim_period_ms, bool disable_nx_huge_pages, } else { TEST_ASSERT(r == -1 && errno == EPERM, "This process should not have permission to disable NX huge pages"); - return; + goto done; } } @@ -213,6 +213,7 @@ void run_test(int reclaim_period_ms, bool disable_nx_huge_pages, check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 2); check_split_count(vm, 0); +done: kvm_vm_free(vm); } diff --git a/tools/testing/selftests/kvm/x86/save_restore_pf_stress_test.c b/tools/testing/selftests/kvm/x86/save_restore_pf_stress_test.c index 507391ab2c93..24056921110c 100644 --- a/tools/testing/selftests/kvm/x86/save_restore_pf_stress_test.c +++ b/tools/testing/selftests/kvm/x86/save_restore_pf_stress_test.c @@ -98,17 +98,17 @@ static void l1_svm_code(struct svm_test_data *svm) static void l1_vmx_code(struct vmx_pages *vmx) { - GUEST_ASSERT(prepare_for_vmx_operation(vmx)); - GUEST_ASSERT(load_vmcs(vmx)); + prepare_for_vmx_operation(vmx); + load_vmcs(vmx); prepare_vmcs(vmx, guest_access_memory); - GUEST_ASSERT(!vmwrite(EXCEPTION_BITMAP, BIT(UD_VECTOR))); + vmwrite(EXCEPTION_BITMAP, BIT(UD_VECTOR)); - GUEST_ASSERT(!vmlaunch()); + vmlaunch(); while (1) { - GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_EXCEPTION_NMI); - GUEST_ASSERT_EQ(vmreadz(VM_EXIT_INTR_INFO) & 0xff, UD_VECTOR); - GUEST_ASSERT(!vmresume()); + GUEST_ASSERT_EQ(vmread(VM_EXIT_REASON), EXIT_REASON_EXCEPTION_NMI); + GUEST_ASSERT_EQ(vmread(VM_EXIT_INTR_INFO) & 0xff, UD_VECTOR); + vmresume(); } } diff --git a/tools/testing/selftests/kvm/x86/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86/set_boot_cpu_id.c index 8e3898646c69..909cd9e83fda 100644 --- a/tools/testing/selftests/kvm/x86/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86/set_boot_cpu_id.c @@ -69,7 +69,7 @@ static void run_vcpu(struct kvm_vcpu *vcpu) TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage + 1, "Stage %d: Unexpected register values vmexit, got %lx", - stage + 1, (ulong)uc.args[1]); + stage + 1, (unsigned long)uc.args[1]); test_set_bsp_busy(vcpu, "while running vm"); break; case UCALL_DONE: diff --git a/tools/testing/selftests/kvm/x86/sev_dbg_test.c b/tools/testing/selftests/kvm/x86/sev_dbg_test.c index eaa8201b937d..0277e38e3556 100644 --- a/tools/testing/selftests/kvm/x86/sev_dbg_test.c +++ b/tools/testing/selftests/kvm/x86/sev_dbg_test.c @@ -14,9 +14,11 @@ static u8 *data; static u8 src[BUFFER_SIZE] __aligned(PAGE_SIZE); static u8 dst[BUFFER_SIZE] __aligned(PAGE_SIZE); -static void validate_dst(int i, int nr_bytes, u8 pattern) +static void validate_dst(int offset, int nr_bytes, u8 pattern) { - for ( ; i < nr_bytes; i++) + int i; + + for (i = offset; i < offset + nr_bytes; i++) TEST_ASSERT(dst[i] == pattern, "Expected 0x%x at byte %u, got 0x%x", pattern, i, dst[i]); diff --git a/tools/testing/selftests/kvm/x86/sev_smoke_test.c b/tools/testing/selftests/kvm/x86/sev_smoke_test.c index bf27b6187afa..19f76f7d8ca6 100644 --- a/tools/testing/selftests/kvm/x86/sev_smoke_test.c +++ b/tools/testing/selftests/kvm/x86/sev_smoke_test.c @@ -178,7 +178,7 @@ static void test_sev(void *guest_code, u32 type, u64 policy) case UCALL_SYNC: continue; case UCALL_DONE: - return; + goto done; case UCALL_ABORT: REPORT_GUEST_ASSERT(uc); default: @@ -187,6 +187,7 @@ static void test_sev(void *guest_code, u32 type, u64 policy) } } +done: kvm_vm_free(vm); } diff --git a/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c b/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c index 3dca85e95478..8d1822717abd 100644 --- a/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c +++ b/tools/testing/selftests/kvm/x86/smaller_maxphyaddr_emulation_test.c @@ -62,11 +62,12 @@ int main(int argc, char *argv[]) TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable"); vm_enable_cap(vm, KVM_CAP_EXIT_ON_EMULATION_FAILURE, 1); - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, - MEM_REGION_GPA, MEM_REGION_SLOT, - MEM_REGION_SIZE / PAGE_SIZE, 0); + vm_override_mem_region(vm, MEM_REGION_TEST_EXTRA, VM_MEM_SRC_ANONYMOUS, + MEM_REGION_GPA, MEM_REGION_SLOT, + MEM_REGION_SIZE / PAGE_SIZE); + gpa = vm_phy_pages_alloc(vm, MEM_REGION_SIZE / PAGE_SIZE, - MEM_REGION_GPA, MEM_REGION_SLOT); + MEM_REGION_TEST_EXTRA); TEST_ASSERT(gpa == MEM_REGION_GPA, "Failed vm_phy_pages_alloc"); virt_map(vm, MEM_REGION_GVA, MEM_REGION_GPA, 1); hva = addr_gpa2hva(vm, MEM_REGION_GPA); diff --git a/tools/testing/selftests/kvm/x86/smm_test.c b/tools/testing/selftests/kvm/x86/smm_test.c index d1edafd5af75..377df09e582a 100644 --- a/tools/testing/selftests/kvm/x86/smm_test.c +++ b/tools/testing/selftests/kvm/x86/smm_test.c @@ -78,8 +78,8 @@ static void guest_code(void *arg) if (this_cpu_has(X86_FEATURE_SVM)) { generic_svm_setup(svm, l2_guest_code); } else { - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); + load_vmcs(vmx_pages); prepare_vmcs(vmx_pages, l2_guest_code); } diff --git a/tools/testing/selftests/kvm/x86/state_test.c b/tools/testing/selftests/kvm/x86/state_test.c index 4a1056a6cb8d..500b09762555 100644 --- a/tools/testing/selftests/kvm/x86/state_test.c +++ b/tools/testing/selftests/kvm/x86/state_test.c @@ -59,13 +59,13 @@ void vmx_l2_guest_code(void) vmcall(); /* L1 has now set up a shadow VMCS for us. */ - GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); + GUEST_ASSERT(vmread(GUEST_RIP) == 0xc0ffee); GUEST_SYNC(10); - GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); - GUEST_ASSERT(!vmwrite(GUEST_RIP, 0xc0fffee)); + GUEST_ASSERT(vmread(GUEST_RIP) == 0xc0ffee); + vmwrite(GUEST_RIP, 0xc0fffee); GUEST_SYNC(11); - GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0fffee); - GUEST_ASSERT(!vmwrite(GUEST_RIP, 0xc0ffffee)); + GUEST_ASSERT(vmread(GUEST_RIP) == 0xc0fffee); + vmwrite(GUEST_RIP, 0xc0ffffee); GUEST_SYNC(12); /* Done, exit to L1 and never come back. */ @@ -75,61 +75,61 @@ void vmx_l2_guest_code(void) static void vmx_l1_guest_code(struct vmx_pages *vmx_pages) { GUEST_ASSERT(vmx_pages->vmcs_gpa); - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); GUEST_SYNC(3); - GUEST_ASSERT(load_vmcs(vmx_pages)); - GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); + load_vmcs(vmx_pages); + GUEST_ASSERT(vmptrst() == vmx_pages->vmcs_gpa); GUEST_SYNC(4); - GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); + GUEST_ASSERT(vmptrst() == vmx_pages->vmcs_gpa); prepare_vmcs(vmx_pages, vmx_l2_guest_code); GUEST_SYNC(5); - GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + GUEST_ASSERT(vmptrst() == vmx_pages->vmcs_gpa); + vmlaunch(); + GUEST_ASSERT(vmptrst() == vmx_pages->vmcs_gpa); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); /* Check that the launched state is preserved. */ - GUEST_ASSERT(vmlaunch()); + GUEST_ASSERT(__vmlaunch()); - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); GUEST_SYNC(7); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); - vmwrite(GUEST_RIP, vmreadz(GUEST_RIP) + 3); + vmwrite(GUEST_RIP, vmread(GUEST_RIP) + 3); vmwrite(SECONDARY_VM_EXEC_CONTROL, SECONDARY_EXEC_SHADOW_VMCS); vmwrite(VMCS_LINK_POINTER, vmx_pages->shadow_vmcs_gpa); - GUEST_ASSERT(!vmptrld(vmx_pages->shadow_vmcs_gpa)); - GUEST_ASSERT(vmlaunch()); + vmptrld(vmx_pages->shadow_vmcs_gpa); + GUEST_ASSERT(__vmlaunch()); GUEST_SYNC(8); - GUEST_ASSERT(vmlaunch()); - GUEST_ASSERT(vmresume()); + GUEST_ASSERT(__vmlaunch()); + GUEST_ASSERT(__vmresume()); vmwrite(GUEST_RIP, 0xc0ffee); GUEST_SYNC(9); - GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffee); + GUEST_ASSERT(vmread(GUEST_RIP) == 0xc0ffee); - GUEST_ASSERT(!vmptrld(vmx_pages->vmcs_gpa)); - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + vmptrld(vmx_pages->vmcs_gpa); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); - GUEST_ASSERT(!vmptrld(vmx_pages->shadow_vmcs_gpa)); - GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffffee); - GUEST_ASSERT(vmlaunch()); - GUEST_ASSERT(vmresume()); + vmptrld(vmx_pages->shadow_vmcs_gpa); + GUEST_ASSERT(vmread(GUEST_RIP) == 0xc0ffffee); + GUEST_ASSERT(__vmlaunch()); + GUEST_ASSERT(__vmresume()); GUEST_SYNC(13); - GUEST_ASSERT(vmreadz(GUEST_RIP) == 0xc0ffffee); - GUEST_ASSERT(vmlaunch()); - GUEST_ASSERT(vmresume()); + GUEST_ASSERT(vmread(GUEST_RIP) == 0xc0ffffee); + GUEST_ASSERT(__vmlaunch()); + GUEST_ASSERT(__vmresume()); } static void __attribute__((__flatten__)) guest_code(void *arg) @@ -296,7 +296,7 @@ int main(int argc, char *argv[]) /* UCALL_SYNC is handled here. */ TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx", - stage, (ulong)uc.args[1]); + stage, (unsigned long)uc.args[1]); state = vcpu_save_state(vcpu); memset(®s1, 0, sizeof(regs1)); @@ -343,7 +343,7 @@ int main(int argc, char *argv[]) vcpu_regs_get(vcpu, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", - (ulong) regs2.rdi, (ulong) regs2.rsi); + (unsigned long)regs2.rdi, (unsigned long)regs2.rsi); } done: diff --git a/tools/testing/selftests/kvm/x86/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86/triple_fault_event_test.c index 0d83516f4bd0..b2b796fd9ffb 100644 --- a/tools/testing/selftests/kvm/x86/triple_fault_event_test.c +++ b/tools/testing/selftests/kvm/x86/triple_fault_event_test.c @@ -25,14 +25,14 @@ void l1_guest_code_vmx(struct vmx_pages *vmx) { GUEST_ASSERT(vmx->vmcs_gpa); - GUEST_ASSERT(prepare_for_vmx_operation(vmx)); - GUEST_ASSERT(load_vmcs(vmx)); + prepare_for_vmx_operation(vmx); + load_vmcs(vmx); prepare_vmcs(vmx, l2_guest_code); - GUEST_ASSERT(!vmlaunch()); + vmlaunch(); /* L2 should triple fault after a triple fault event injected. */ - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_TRIPLE_FAULT); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_TRIPLE_FAULT); GUEST_DONE(); } diff --git a/tools/testing/selftests/kvm/x86/tsc_msrs_test.c b/tools/testing/selftests/kvm/x86/tsc_msrs_test.c index 91583969a14f..55779773614b 100644 --- a/tools/testing/selftests/kvm/x86/tsc_msrs_test.c +++ b/tools/testing/selftests/kvm/x86/tsc_msrs_test.c @@ -78,7 +78,7 @@ static void run_vcpu(struct kvm_vcpu *vcpu, int stage) else ksft_test_result_fail( "stage %d: Unexpected register values vmexit, got %lx", - stage + 1, (ulong)uc.args[1]); + stage + 1, (unsigned long)uc.args[1]); return; case UCALL_DONE: ksft_test_result_pass("stage %d passed\n", stage + 1); diff --git a/tools/testing/selftests/kvm/x86/vmx_apic_access_test.c b/tools/testing/selftests/kvm/x86/vmx_apic_access_test.c index 463f73aa9159..1d7a529c8297 100644 --- a/tools/testing/selftests/kvm/x86/vmx_apic_access_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_apic_access_test.c @@ -38,30 +38,30 @@ static void l1_guest_code(struct vmx_pages *vmx_pages, unsigned long high_gpa) { u32 control; - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); + load_vmcs(vmx_pages); /* Prepare the VMCS for L2 execution. */ prepare_vmcs(vmx_pages, l2_guest_code); - control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); + control = vmread(CPU_BASED_VM_EXEC_CONTROL); control |= CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); - control = vmreadz(SECONDARY_VM_EXEC_CONTROL); + control = vmread(SECONDARY_VM_EXEC_CONTROL); control |= SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES; vmwrite(SECONDARY_VM_EXEC_CONTROL, control); vmwrite(APIC_ACCESS_ADDR, vmx_pages->apic_access_gpa); /* Try to launch L2 with the memory-backed APIC-access address. */ - GUEST_SYNC(vmreadz(APIC_ACCESS_ADDR)); - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + GUEST_SYNC(vmread(APIC_ACCESS_ADDR)); + vmlaunch(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); vmwrite(APIC_ACCESS_ADDR, high_gpa); /* Try to resume L2 with the unbacked APIC-access address. */ - GUEST_SYNC(vmreadz(APIC_ACCESS_ADDR)); - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + GUEST_SYNC(vmread(APIC_ACCESS_ADDR)); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); GUEST_DONE(); } @@ -77,7 +77,7 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu; struct kvm_vm *vm; - TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + TEST_REQUIRE(kvm_cpu_has_vmx_virtualize_apic_accesses()); vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); diff --git a/tools/testing/selftests/kvm/x86/vmx_apicv_updates_test.c b/tools/testing/selftests/kvm/x86/vmx_apicv_updates_test.c index f9b88a6f6113..cda9e43e8599 100644 --- a/tools/testing/selftests/kvm/x86/vmx_apicv_updates_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_apicv_updates_test.c @@ -33,12 +33,12 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) { u32 control; - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); + load_vmcs(vmx_pages); /* Prepare the VMCS for L2 execution. */ prepare_vmcs(vmx_pages, l2_guest_code); - control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); + control = vmread(CPU_BASED_VM_EXEC_CONTROL); control |= CPU_BASED_USE_MSR_BITMAPS; vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); @@ -62,9 +62,9 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) * Run L2 to switch to x2APIC mode, which in turn will uninhibit APICv, * as KVM should force the APIC ID back to its default. */ - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); - vmwrite(GUEST_RIP, vmreadz(GUEST_RIP) + vmreadz(VM_EXIT_INSTRUCTION_LEN)); + vmlaunch(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + vmwrite(GUEST_RIP, vmread(GUEST_RIP) + vmread(VM_EXIT_INSTRUCTION_LEN)); GUEST_ASSERT(rdmsr(MSR_IA32_APICBASE) & MSR_IA32_APICBASE_EXTD); /* @@ -90,8 +90,8 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) * handles the x2APIC => xAPIC transition and inhibits APICv while L2 * is active. */ - GUEST_ASSERT(!vmresume()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + vmresume(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); GUEST_ASSERT(!(rdmsr(MSR_IA32_APICBASE) & MSR_IA32_APICBASE_EXTD)); xapic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_DM_FIXED | GOOD_IPI_VECTOR); diff --git a/tools/testing/selftests/kvm/x86/vmx_exception_with_invalid_guest_state.c b/tools/testing/selftests/kvm/x86/vmx_exception_with_invalid_guest_state.c index 2cae86d9d5e2..08a0caa9c52d 100644 --- a/tools/testing/selftests/kvm/x86/vmx_exception_with_invalid_guest_state.c +++ b/tools/testing/selftests/kvm/x86/vmx_exception_with_invalid_guest_state.c @@ -109,7 +109,7 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu; struct kvm_vm *vm; - TEST_REQUIRE(host_cpu_is_intel); + TEST_REQUIRE(host_cpu_is_intel_compatible); TEST_REQUIRE(!kvm_is_unrestricted_guest_enabled()); vm = vm_create_with_one_vcpu(&vcpu, guest_code); diff --git a/tools/testing/selftests/kvm/x86/vmx_invalid_nested_guest_state.c b/tools/testing/selftests/kvm/x86/vmx_invalid_nested_guest_state.c index c8379124b317..bbd188949412 100644 --- a/tools/testing/selftests/kvm/x86/vmx_invalid_nested_guest_state.c +++ b/tools/testing/selftests/kvm/x86/vmx_invalid_nested_guest_state.c @@ -41,8 +41,8 @@ static void l2_guest_code(void) static void l1_guest_code(struct vmx_pages *vmx_pages) { - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); + load_vmcs(vmx_pages); /* Prepare the VMCS for L2 execution. */ prepare_vmcs(vmx_pages, l2_guest_code); @@ -52,13 +52,13 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) * library hasn't enabled it. Because KVM selftests jump directly to * 64-bit mode, unrestricted guest support isn't required. */ - GUEST_ASSERT(!(vmreadz(CPU_BASED_VM_EXEC_CONTROL) & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) || - !(vmreadz(SECONDARY_VM_EXEC_CONTROL) & SECONDARY_EXEC_UNRESTRICTED_GUEST)); + GUEST_ASSERT(!(vmread(CPU_BASED_VM_EXEC_CONTROL) & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) || + !(vmread(SECONDARY_VM_EXEC_CONTROL) & SECONDARY_EXEC_UNRESTRICTED_GUEST)); - GUEST_ASSERT(!vmlaunch()); + vmlaunch(); /* L2 should triple fault after main() stuffs invalid guest state. */ - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_TRIPLE_FAULT); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_TRIPLE_FAULT); GUEST_DONE(); } diff --git a/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c b/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c index 75073efa926d..7dcee11877ea 100644 --- a/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c @@ -37,8 +37,8 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_ASSERT(rdmsr(MSR_GS_BASE) == LA57_GS_BASE); GUEST_ASSERT(vmx_pages->vmcs_gpa); - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); + prepare_for_vmx_operation(vmx_pages); + load_vmcs(vmx_pages); prepare_vmcs(vmx_pages, l2_guest_code); @@ -52,13 +52,13 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) pml4_pa = pml5[0] & PHYSICAL_PAGE_MASK; vmwrite(GUEST_CR3, pml4_pa); - guest_cr4 = vmreadz(GUEST_CR4); + guest_cr4 = vmread(GUEST_CR4); guest_cr4 &= ~X86_CR4_LA57; vmwrite(GUEST_CR4, guest_cr4); - GUEST_ASSERT(!vmlaunch()); + vmlaunch(); - exit_reason = vmreadz(VM_EXIT_REASON); + exit_reason = vmread(VM_EXIT_REASON); GUEST_ASSERT(exit_reason == EXIT_REASON_VMCALL); } @@ -109,7 +109,7 @@ int main(int argc, char *argv[]) } TEST_ASSERT(uc.args[1] == stage, - "Expected stage %d, got stage %lu", stage, (ulong)uc.args[1]); + "Expected stage %d, got stage %lu", stage, (unsigned long)uc.args[1]); if (stage == 1) { pr_info("L2 is active; performing save/restore.\n"); state = vcpu_save_state(vcpu); diff --git a/tools/testing/selftests/kvm/x86/vmx_preemption_timer_test.c b/tools/testing/selftests/kvm/x86/vmx_preemption_timer_test.c index eb8021c33cd4..b9ee9d3c1da4 100644 --- a/tools/testing/selftests/kvm/x86/vmx_preemption_timer_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_preemption_timer_test.c @@ -71,9 +71,9 @@ void l1_guest_code(struct vmx_pages *vmx_pages) u64 l1_tsc_deadline, l2_tsc_deadline; GUEST_ASSERT(vmx_pages->vmcs_gpa); - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); - GUEST_ASSERT(vmptrstz() == vmx_pages->vmcs_gpa); + prepare_for_vmx_operation(vmx_pages); + load_vmcs(vmx_pages); + GUEST_ASSERT(vmptrst() == vmx_pages->vmcs_gpa); prepare_vmcs(vmx_pages, l2_guest_code); @@ -90,19 +90,17 @@ void l1_guest_code(struct vmx_pages *vmx_pages) !(ctrl_exit_rev.clr & VM_EXIT_SAVE_VMX_PREEMPTION_TIMER)) return; - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); - vmwrite(GUEST_RIP, vmreadz(GUEST_RIP) + vmreadz(VM_EXIT_INSTRUCTION_LEN)); + vmlaunch(); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + vmwrite(GUEST_RIP, vmread(GUEST_RIP) + vmread(VM_EXIT_INSTRUCTION_LEN)); /* * Turn on PIN control and resume the guest */ - GUEST_ASSERT(!vmwrite(PIN_BASED_VM_EXEC_CONTROL, - vmreadz(PIN_BASED_VM_EXEC_CONTROL) | - PIN_BASED_VMX_PREEMPTION_TIMER)); + vmwrite(PIN_BASED_VM_EXEC_CONTROL, + vmread(PIN_BASED_VM_EXEC_CONTROL) | PIN_BASED_VMX_PREEMPTION_TIMER); - GUEST_ASSERT(!vmwrite(VMX_PREEMPTION_TIMER_VALUE, - PREEMPTION_TIMER_VALUE)); + vmwrite(VMX_PREEMPTION_TIMER_VALUE, PREEMPTION_TIMER_VALUE); vmx_pt_rate = rdmsr(MSR_IA32_VMX_MISC) & 0x1F; @@ -110,7 +108,7 @@ void l1_guest_code(struct vmx_pages *vmx_pages) l1_vmx_pt_start = (rdtsc() >> vmx_pt_rate) << vmx_pt_rate; - GUEST_ASSERT(!vmresume()); + vmresume(); l1_vmx_pt_finish = rdtsc(); @@ -123,7 +121,7 @@ void l1_guest_code(struct vmx_pages *vmx_pages) /* * Ensure the exit from L2 is due to preemption timer expiry */ - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_PREEMPTION_TIMER); + GUEST_ASSERT(vmread(VM_EXIT_REASON) == EXIT_REASON_PREEMPTION_TIMER); l1_tsc_deadline = l1_vmx_pt_start + (PREEMPTION_TIMER_VALUE << vmx_pt_rate); @@ -193,7 +191,7 @@ int main(int argc, char *argv[]) /* UCALL_SYNC is handled here. */ TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx", - stage, (ulong)uc.args[1]); + stage, (unsigned long)uc.args[1]); /* * If this stage 2 then we should verify the vmx pt expiry * is as expected. @@ -234,7 +232,7 @@ int main(int argc, char *argv[]) vcpu_regs_get(vcpu, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", - (ulong) regs2.rdi, (ulong) regs2.rsi); + (unsigned long)regs2.rdi, (unsigned long)regs2.rsi); } done: diff --git a/tools/testing/selftests/kvm/x86/xapic_ipi_test.c b/tools/testing/selftests/kvm/x86/xapic_ipi_test.c index 469e3ab16460..2362bf272e80 100644 --- a/tools/testing/selftests/kvm/x86/xapic_ipi_test.c +++ b/tools/testing/selftests/kvm/x86/xapic_ipi_test.c @@ -233,13 +233,10 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs, { long pages_not_moved; unsigned long nodemask = 0; - unsigned long nodemasks[sizeof(nodemask) * 8]; int nodes = 0; time_t start_time, last_update, now; time_t interval_secs = 1; - int i; int from, to; - unsigned long bit; u64 hlt_count; u64 wake_count; u64 ipis_sent; @@ -247,32 +244,19 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs, fprintf(stderr, "Calling migrate_pages every %d microseconds\n", delay_usecs); - /* Get set of first 64 numa nodes available */ - kvm_get_mempolicy(NULL, &nodemask, sizeof(nodemask) * 8, - 0, MPOL_F_MEMS_ALLOWED); + nodes = kvm_get_numa_memory_nodes(&nodemask); + TEST_ASSERT(nodes > 1, + "NUMA nodes disappeared? nodemask = 0x%lx", nodemask); fprintf(stderr, "Numa nodes found amongst first %lu possible nodes " "(each 1-bit indicates node is present): %#lx\n", - sizeof(nodemask) * 8, nodemask); - - /* Init array of masks containing a single-bit in each, one for each - * available node. migrate_pages called below requires specifying nodes - * as bit masks. - */ - for (i = 0, bit = 1; i < sizeof(nodemask) * 8; i++, bit <<= 1) { - if (nodemask & bit) { - nodemasks[nodes] = nodemask & bit; - nodes++; - } - } - - TEST_ASSERT(nodes > 1, - "Did not find at least 2 numa nodes. Can't do migration"); + BITS_PER_TYPE(nodemask), nodemask); fprintf(stderr, "Migrating amongst %d nodes found\n", nodes); - from = 0; - to = 1; + from = kvm_get_next_numa_node(nodemask, -1); + to = kvm_get_next_numa_node(nodemask, from); + start_time = time(NULL); last_update = start_time; @@ -281,6 +265,9 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs, wake_count = data->wake_count; while ((int)(time(NULL) - start_time) < run_secs) { + unsigned long from_mask = BIT(from); + unsigned long to_mask = BIT(to); + data->migrations_attempted++; /* @@ -291,9 +278,8 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs, * KVM_CREATE_VCPU ioctl. If that assumption ever changes this * test may break or give a false positive signal. */ - pages_not_moved = migrate_pages(0, sizeof(nodemasks[from]), - &nodemasks[from], - &nodemasks[to]); + pages_not_moved = migrate_pages(0, MAXNODE_FOR_MASK(from_mask), + &from_mask, &to_mask); if (pages_not_moved < 0) fprintf(stderr, "migrate_pages failed, errno=%d\n", errno); @@ -305,9 +291,7 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs, data->migrations_completed++; from = to; - to++; - if (to == nodes) - to = 0; + to = kvm_get_next_numa_node(nodemask, from); now = time(NULL); if (((now - start_time) % interval_secs == 0) && @@ -366,26 +350,17 @@ void get_cmdline_args(int argc, char *argv[], int *run_secs, } } -int main(int argc, char *argv[]) +static void test_xapic_ipi(int run_secs, int delay_usecs, bool migrate) { int wait_secs; const int max_halter_wait = 10; - int run_secs = 0; - int delay_usecs = 0; struct test_data_page *data; gva_t test_data_page_gva; - bool migrate = false; pthread_t threads[2]; struct thread_params params[2]; struct kvm_vm *vm; u64 *pipis_rcvd; - get_cmdline_args(argc, argv, &run_secs, &migrate, &delay_usecs); - if (run_secs <= 0) - run_secs = DEFAULT_RUN_SECS; - if (delay_usecs <= 0) - delay_usecs = DEFAULT_DELAY_USECS; - vm = vm_create_with_one_vcpu(¶ms[0].vcpu, halter_guest_code); vm_install_exception_handler(vm, IPI_VECTOR, guest_ipi_handler); @@ -473,5 +448,30 @@ int main(int argc, char *argv[]) kvm_vm_free(vm); +} + +int main(int argc, char *argv[]) +{ + bool force_migrate = false; + unsigned long nodemask; + int run_secs = 0; + int delay_usecs = 0; + + get_cmdline_args(argc, argv, &run_secs, &force_migrate, &delay_usecs); + if (run_secs <= 0) + run_secs = DEFAULT_RUN_SECS; + if (delay_usecs <= 0) + delay_usecs = DEFAULT_DELAY_USECS; + + if (!force_migrate) + test_xapic_ipi(run_secs, delay_usecs, false); + + if (kvm_get_numa_memory_nodes(&nodemask) > 1) + test_xapic_ipi(run_secs, delay_usecs, true); + else + __TEST_REQUIRE(!force_migrate, + "Need at least 2 NUMA nodes to do migration (nodemask = 0x%lx)", + nodemask); + return 0; } |
