kvm: selftests: Add platform_info_test
authorDrew Schmitt <dasch@google.com>
Mon, 20 Aug 2018 17:32:16 +0000 (10:32 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 19 Sep 2018 22:51:47 +0000 (00:51 +0200)
Test guest access to MSR_PLATFORM_INFO when the capability is enabled
or disabled.

Signed-off-by: Drew Schmitt <dasch@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
tools/testing/selftests/kvm/.gitignore
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/platform_info_test.c [new file with mode: 0644]

index 4202139d81d92c724bcb18df30b41deac28cb935..5c34752e1cff099ff884ffa0a78bb8deaa088dd6 100644 (file)
@@ -1,4 +1,5 @@
 cr4_cpuid_sync_test
+platform_info_test
 set_sregs_test
 sync_regs_test
 vmx_tsc_adjust_test
index 48c970c90353b9dbbfe547c68dc9b2798577d6e3..37e4bd8619a63655e5844678e46eb8bd3e6eebc7 100644 (file)
@@ -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
index bb5a25fb82c60cbe8f7a108c81bc1c78aa2a7a20..3acf9a91704c9b9437cd42c163f6c244cb1c7d08 100644 (file)
@@ -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);
@@ -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);
 
index e9ba389c48dbc95390d965a8ea7d7f03da9ece44..6fd8c089cafcdea41434fadc60512b96d4a90f5d 100644 (file)
@@ -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);
@@ -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:
diff --git a/tools/testing/selftests/kvm/platform_info_test.c b/tools/testing/selftests/kvm/platform_info_test.c
new file mode 100644 (file)
index 0000000..3764e71
--- /dev/null
@@ -0,0 +1,110 @@
+// 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;
+}