Loading tools/testing/selftests/kvm/.gitignore +1 −0 Original line number Diff line number Diff line cr4_cpuid_sync_test platform_info_test set_sregs_test sync_regs_test vmx_tsc_adjust_test Loading tools/testing/selftests/kvm/Makefile +2 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,8 @@ UNAME_M := $(shell uname -m) LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c LIBKVM_x86_64 = lib/x86.c lib/vmx.c TEST_GEN_PROGS_x86_64 = set_sregs_test TEST_GEN_PROGS_x86_64 = platform_info_test TEST_GEN_PROGS_x86_64 += set_sregs_test TEST_GEN_PROGS_x86_64 += sync_regs_test TEST_GEN_PROGS_x86_64 += vmx_tsc_adjust_test TEST_GEN_PROGS_x86_64 += cr4_cpuid_sync_test Loading tools/testing/selftests/kvm/include/kvm_util.h +4 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ enum vm_mem_backing_src_type { }; int kvm_check_cap(long cap); int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap); struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); void kvm_vm_free(struct kvm_vm *vmp); Loading Loading @@ -108,6 +109,9 @@ void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_events *events); void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_events *events); uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index); void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, uint64_t msr_value); const char *exit_reason_str(unsigned int exit_reason); Loading tools/testing/selftests/kvm/lib/kvm_util.c +89 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,29 @@ int kvm_check_cap(long cap) return ret; } /* VM Enable Capability * * Input Args: * vm - Virtual Machine * cap - Capability * * Output Args: None * * Return: On success, 0. On failure a TEST_ASSERT failure is produced. * * Enables a capability (KVM_CAP_*) on the VM. */ int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) { int ret; ret = ioctl(vm->fd, KVM_ENABLE_CAP, cap); TEST_ASSERT(ret == 0, "KVM_ENABLE_CAP IOCTL failed,\n" " rc: %i errno: %i", ret, errno); return ret; } static void vm_open(struct kvm_vm *vm, int perm) { vm->kvm_fd = open(KVM_DEV_PATH, perm); Loading Loading @@ -1220,6 +1243,72 @@ void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, ret, errno); } /* VCPU Get MSR * * Input Args: * vm - Virtual Machine * vcpuid - VCPU ID * msr_index - Index of MSR * * Output Args: None * * Return: On success, value of the MSR. On failure a TEST_ASSERT is produced. * * Get value of MSR for VCPU. */ uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); struct { struct kvm_msrs header; struct kvm_msr_entry entry; } buffer = {}; int r; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); buffer.header.nmsrs = 1; buffer.entry.index = msr_index; r = ioctl(vcpu->fd, KVM_GET_MSRS, &buffer.header); TEST_ASSERT(r == 1, "KVM_GET_MSRS IOCTL failed,\n" " rc: %i errno: %i", r, errno); return buffer.entry.data; } /* VCPU Set MSR * * Input Args: * vm - Virtual Machine * vcpuid - VCPU ID * msr_index - Index of MSR * msr_value - New value of MSR * * Output Args: None * * Return: On success, nothing. On failure a TEST_ASSERT is produced. * * Set value of MSR for VCPU. */ void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, uint64_t msr_value) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); struct { struct kvm_msrs header; struct kvm_msr_entry entry; } buffer = {}; int r; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); memset(&buffer, 0, sizeof(buffer)); buffer.header.nmsrs = 1; buffer.entry.index = msr_index; buffer.entry.data = msr_value; r = ioctl(vcpu->fd, KVM_SET_MSRS, &buffer.header); TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n" " rc: %i errno: %i", r, errno); } /* VM VCPU Args Set * * Input Args: Loading tools/testing/selftests/kvm/platform_info_test.c 0 → 100644 +110 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 /* * Test for x86 KVM_CAP_MSR_PLATFORM_INFO * * Copyright (C) 2018, Google LLC. * * This work is licensed under the terms of the GNU GPL, version 2. * * Verifies expected behavior of controlling guest access to * MSR_PLATFORM_INFO. */ #define _GNU_SOURCE /* for program_invocation_short_name */ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include "test_util.h" #include "kvm_util.h" #include "x86.h" #define VCPU_ID 0 #define MSR_PLATFORM_INFO_MAX_TURBO_RATIO 0xff00 static void guest_code(void) { uint64_t msr_platform_info; for (;;) { msr_platform_info = rdmsr(MSR_PLATFORM_INFO); GUEST_SYNC(msr_platform_info); asm volatile ("inc %r11"); } } static void set_msr_platform_info_enabled(struct kvm_vm *vm, bool enable) { struct kvm_enable_cap cap = {}; cap.cap = KVM_CAP_MSR_PLATFORM_INFO; cap.flags = 0; cap.args[0] = (int)enable; vm_enable_cap(vm, &cap); } static void test_msr_platform_info_enabled(struct kvm_vm *vm) { struct kvm_run *run = vcpu_state(vm, VCPU_ID); struct guest_args args; set_msr_platform_info_enabled(vm, true); vcpu_run(vm, VCPU_ID); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Exit_reason other than KVM_EXIT_IO: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); guest_args_read(vm, VCPU_ID, &args); TEST_ASSERT(args.port == GUEST_PORT_SYNC, "Received IO from port other than PORT_HOST_SYNC: %u\n", run->io.port); TEST_ASSERT((args.arg1 & MSR_PLATFORM_INFO_MAX_TURBO_RATIO) == MSR_PLATFORM_INFO_MAX_TURBO_RATIO, "Expected MSR_PLATFORM_INFO to have max turbo ratio mask: %i.", MSR_PLATFORM_INFO_MAX_TURBO_RATIO); } static void test_msr_platform_info_disabled(struct kvm_vm *vm) { struct kvm_run *run = vcpu_state(vm, VCPU_ID); set_msr_platform_info_enabled(vm, false); vcpu_run(vm, VCPU_ID); TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN, "Exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); } int main(int argc, char *argv[]) { struct kvm_vm *vm; struct kvm_run *state; int rv; uint64_t msr_platform_info; /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); rv = kvm_check_cap(KVM_CAP_MSR_PLATFORM_INFO); if (!rv) { fprintf(stderr, "KVM_CAP_MSR_PLATFORM_INFO not supported, skip test\n"); exit(KSFT_SKIP); } vm = vm_create_default(VCPU_ID, 0, guest_code); msr_platform_info = vcpu_get_msr(vm, VCPU_ID, MSR_PLATFORM_INFO); vcpu_set_msr(vm, VCPU_ID, MSR_PLATFORM_INFO, msr_platform_info | MSR_PLATFORM_INFO_MAX_TURBO_RATIO); test_msr_platform_info_disabled(vm); test_msr_platform_info_enabled(vm); vcpu_set_msr(vm, VCPU_ID, MSR_PLATFORM_INFO, msr_platform_info); kvm_vm_free(vm); return 0; } Loading
tools/testing/selftests/kvm/.gitignore +1 −0 Original line number Diff line number Diff line cr4_cpuid_sync_test platform_info_test set_sregs_test sync_regs_test vmx_tsc_adjust_test Loading
tools/testing/selftests/kvm/Makefile +2 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,8 @@ UNAME_M := $(shell uname -m) LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c LIBKVM_x86_64 = lib/x86.c lib/vmx.c TEST_GEN_PROGS_x86_64 = set_sregs_test TEST_GEN_PROGS_x86_64 = platform_info_test TEST_GEN_PROGS_x86_64 += set_sregs_test TEST_GEN_PROGS_x86_64 += sync_regs_test TEST_GEN_PROGS_x86_64 += vmx_tsc_adjust_test TEST_GEN_PROGS_x86_64 += cr4_cpuid_sync_test Loading
tools/testing/selftests/kvm/include/kvm_util.h +4 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ enum vm_mem_backing_src_type { }; int kvm_check_cap(long cap); int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap); struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); void kvm_vm_free(struct kvm_vm *vmp); Loading Loading @@ -108,6 +109,9 @@ void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_events *events); void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_events *events); uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index); void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, uint64_t msr_value); const char *exit_reason_str(unsigned int exit_reason); Loading
tools/testing/selftests/kvm/lib/kvm_util.c +89 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,29 @@ int kvm_check_cap(long cap) return ret; } /* VM Enable Capability * * Input Args: * vm - Virtual Machine * cap - Capability * * Output Args: None * * Return: On success, 0. On failure a TEST_ASSERT failure is produced. * * Enables a capability (KVM_CAP_*) on the VM. */ int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) { int ret; ret = ioctl(vm->fd, KVM_ENABLE_CAP, cap); TEST_ASSERT(ret == 0, "KVM_ENABLE_CAP IOCTL failed,\n" " rc: %i errno: %i", ret, errno); return ret; } static void vm_open(struct kvm_vm *vm, int perm) { vm->kvm_fd = open(KVM_DEV_PATH, perm); Loading Loading @@ -1220,6 +1243,72 @@ void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, ret, errno); } /* VCPU Get MSR * * Input Args: * vm - Virtual Machine * vcpuid - VCPU ID * msr_index - Index of MSR * * Output Args: None * * Return: On success, value of the MSR. On failure a TEST_ASSERT is produced. * * Get value of MSR for VCPU. */ uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); struct { struct kvm_msrs header; struct kvm_msr_entry entry; } buffer = {}; int r; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); buffer.header.nmsrs = 1; buffer.entry.index = msr_index; r = ioctl(vcpu->fd, KVM_GET_MSRS, &buffer.header); TEST_ASSERT(r == 1, "KVM_GET_MSRS IOCTL failed,\n" " rc: %i errno: %i", r, errno); return buffer.entry.data; } /* VCPU Set MSR * * Input Args: * vm - Virtual Machine * vcpuid - VCPU ID * msr_index - Index of MSR * msr_value - New value of MSR * * Output Args: None * * Return: On success, nothing. On failure a TEST_ASSERT is produced. * * Set value of MSR for VCPU. */ void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, uint64_t msr_value) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); struct { struct kvm_msrs header; struct kvm_msr_entry entry; } buffer = {}; int r; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); memset(&buffer, 0, sizeof(buffer)); buffer.header.nmsrs = 1; buffer.entry.index = msr_index; buffer.entry.data = msr_value; r = ioctl(vcpu->fd, KVM_SET_MSRS, &buffer.header); TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n" " rc: %i errno: %i", r, errno); } /* VM VCPU Args Set * * Input Args: Loading
tools/testing/selftests/kvm/platform_info_test.c 0 → 100644 +110 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 /* * Test for x86 KVM_CAP_MSR_PLATFORM_INFO * * Copyright (C) 2018, Google LLC. * * This work is licensed under the terms of the GNU GPL, version 2. * * Verifies expected behavior of controlling guest access to * MSR_PLATFORM_INFO. */ #define _GNU_SOURCE /* for program_invocation_short_name */ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include "test_util.h" #include "kvm_util.h" #include "x86.h" #define VCPU_ID 0 #define MSR_PLATFORM_INFO_MAX_TURBO_RATIO 0xff00 static void guest_code(void) { uint64_t msr_platform_info; for (;;) { msr_platform_info = rdmsr(MSR_PLATFORM_INFO); GUEST_SYNC(msr_platform_info); asm volatile ("inc %r11"); } } static void set_msr_platform_info_enabled(struct kvm_vm *vm, bool enable) { struct kvm_enable_cap cap = {}; cap.cap = KVM_CAP_MSR_PLATFORM_INFO; cap.flags = 0; cap.args[0] = (int)enable; vm_enable_cap(vm, &cap); } static void test_msr_platform_info_enabled(struct kvm_vm *vm) { struct kvm_run *run = vcpu_state(vm, VCPU_ID); struct guest_args args; set_msr_platform_info_enabled(vm, true); vcpu_run(vm, VCPU_ID); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Exit_reason other than KVM_EXIT_IO: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); guest_args_read(vm, VCPU_ID, &args); TEST_ASSERT(args.port == GUEST_PORT_SYNC, "Received IO from port other than PORT_HOST_SYNC: %u\n", run->io.port); TEST_ASSERT((args.arg1 & MSR_PLATFORM_INFO_MAX_TURBO_RATIO) == MSR_PLATFORM_INFO_MAX_TURBO_RATIO, "Expected MSR_PLATFORM_INFO to have max turbo ratio mask: %i.", MSR_PLATFORM_INFO_MAX_TURBO_RATIO); } static void test_msr_platform_info_disabled(struct kvm_vm *vm) { struct kvm_run *run = vcpu_state(vm, VCPU_ID); set_msr_platform_info_enabled(vm, false); vcpu_run(vm, VCPU_ID); TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN, "Exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); } int main(int argc, char *argv[]) { struct kvm_vm *vm; struct kvm_run *state; int rv; uint64_t msr_platform_info; /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); rv = kvm_check_cap(KVM_CAP_MSR_PLATFORM_INFO); if (!rv) { fprintf(stderr, "KVM_CAP_MSR_PLATFORM_INFO not supported, skip test\n"); exit(KSFT_SKIP); } vm = vm_create_default(VCPU_ID, 0, guest_code); msr_platform_info = vcpu_get_msr(vm, VCPU_ID, MSR_PLATFORM_INFO); vcpu_set_msr(vm, VCPU_ID, MSR_PLATFORM_INFO, msr_platform_info | MSR_PLATFORM_INFO_MAX_TURBO_RATIO); test_msr_platform_info_disabled(vm); test_msr_platform_info_enabled(vm); vcpu_set_msr(vm, VCPU_ID, MSR_PLATFORM_INFO, msr_platform_info); kvm_vm_free(vm); return 0; }