Ping. Are there any other changes I need to incorporate here? Thanks, Drew On Mon, Aug 20, 2018 at 10:32 AM Drew Schmitt <dasch@xxxxxxxxxx> wrote: > > Test guest access to MSR_PLATFORM_INFO when the capability is enabled > or disabled. > > Signed-off-by: Drew Schmitt <dasch@xxxxxxxxxx> > --- > tools/testing/selftests/kvm/.gitignore | 1 + > tools/testing/selftests/kvm/Makefile | 3 +- > .../testing/selftests/kvm/include/kvm_util.h | 4 + > tools/testing/selftests/kvm/lib/kvm_util.c | 89 +++++++++++++ > .../selftests/kvm/platform_info_test.c | 121 ++++++++++++++++++ > 5 files changed, 217 insertions(+), 1 deletion(-) > create mode 100644 tools/testing/selftests/kvm/platform_info_test.c > > diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore > index 63fc1ab9248fa..8078891ded84a 100644 > --- a/tools/testing/selftests/kvm/.gitignore > +++ b/tools/testing/selftests/kvm/.gitignore > @@ -1,3 +1,4 @@ > +platform_info_test > set_sregs_test > sync_regs_test > vmx_tsc_adjust_test > diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile > index d9d00319b07cd..85e3eb4108c28 100644 > --- a/tools/testing/selftests/kvm/Makefile > +++ b/tools/testing/selftests/kvm/Makefile > @@ -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 > > diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h > index 637b7017b6ee5..a7e34eaccadba 100644 > --- a/tools/testing/selftests/kvm/include/kvm_util.h > +++ b/tools/testing/selftests/kvm/include/kvm_util.h > @@ -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); > @@ -103,6 +104,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); > > diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c > index 37e2a787d2fcc..2d13b26d32215 100644 > --- a/tools/testing/selftests/kvm/lib/kvm_util.c > +++ b/tools/testing/selftests/kvm/lib/kvm_util.c > @@ -62,6 +62,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; > +} > + > /* VM Create > * > * Input Args: > @@ -1124,6 +1147,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: > diff --git a/tools/testing/selftests/kvm/platform_info_test.c b/tools/testing/selftests/kvm/platform_info_test.c > new file mode 100644 > index 0000000000000..3c14959a09210 > --- /dev/null > +++ b/tools/testing/selftests/kvm/platform_info_test.c > @@ -0,0 +1,121 @@ > +// 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 PORT_HOST_SYNC 0x1000 > +#define MSR_PLATFORM_INFO_MAX_TURBO_RATIO 0xff00 > + > +static void __exit_to_l0(uint16_t port, unsigned long arg) > +{ > + __asm__ __volatile__("in %[port], %%al" > + : > + : [port]"d"(port), "D"(arg) > + : "rax"); > +} > + > +#define exit_to_l0(_port, _arg) __exit_to_l0(_port, (unsigned long) (_arg)) > + > +static void guest_code(void) > +{ > + uint64_t msr_platform_info; > + > + for (;;) { > + msr_platform_info = rdmsr(MSR_PLATFORM_INFO); > + exit_to_l0(PORT_HOST_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 kvm_regs regs; > + > + 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)); > + TEST_ASSERT(run->io.port == PORT_HOST_SYNC, > + "Received IO from port other than PORT_HOST_SYNC: %u\n", > + run->io.port); > + vcpu_regs_get(vm, VCPU_ID, ®s); > + TEST_ASSERT((regs.rdi & 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, 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; > +} > -- > 2.18.0.865.gffc8e1a3cd6-goog >