Commit c90992bf authored by Aaron Lewis's avatar Aaron Lewis Committed by Paolo Bonzini
Browse files

kvm: tests: Add test to verify MSR_IA32_XSS



Ensure that IA32_XSS appears in KVM_GET_MSR_INDEX_LIST if it can be set
to a non-zero value.

Reviewed-by: default avatarJim Mattson <jmattson@google.com>
Signed-off-by: default avatarAaron Lewis <aaronlewis@google.com>
Change-Id: Ia2d644f69e2d6d8c27d7e0a7a45c2bf9c42bf5ff
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 52297436
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -13,6 +13,7 @@
/x86_64/vmx_dirty_log_test
/x86_64/vmx_dirty_log_test
/x86_64/vmx_set_nested_state_test
/x86_64/vmx_set_nested_state_test
/x86_64/vmx_tsc_adjust_test
/x86_64/vmx_tsc_adjust_test
/x86_64/xss_msr_test
/clear_dirty_log_test
/clear_dirty_log_test
/dirty_log_test
/dirty_log_test
/kvm_create_max_vcpus
/kvm_create_max_vcpus
+1 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test
TEST_GEN_PROGS_x86_64 += x86_64/vmx_dirty_log_test
TEST_GEN_PROGS_x86_64 += x86_64/vmx_dirty_log_test
TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test
TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test
TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
TEST_GEN_PROGS_x86_64 += x86_64/xss_msr_test
TEST_GEN_PROGS_x86_64 += clear_dirty_log_test
TEST_GEN_PROGS_x86_64 += clear_dirty_log_test
TEST_GEN_PROGS_x86_64 += dirty_log_test
TEST_GEN_PROGS_x86_64 += dirty_log_test
TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus
TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus
+6 −1
Original line number Original line Diff line number Diff line
@@ -308,6 +308,8 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid);
void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid,
void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid,
		     struct kvm_x86_state *state);
		     struct kvm_x86_state *state);


struct kvm_msr_list *kvm_get_msr_index_list(void);

struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid,
void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid,
		    struct kvm_cpuid2 *cpuid);
		    struct kvm_cpuid2 *cpuid);
@@ -322,10 +324,13 @@ kvm_get_supported_cpuid_entry(uint32_t function)
}
}


uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index);
uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index);
int _vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index,
		  uint64_t msr_value);
void vcpu_set_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);
	  	  uint64_t msr_value);


uint32_t kvm_get_cpuid_max(void);
uint32_t kvm_get_cpuid_max_basic(void);
uint32_t kvm_get_cpuid_max_extended(void);
void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits);
void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits);


/*
/*
+63 −9
Original line number Original line Diff line number Diff line
@@ -869,7 +869,7 @@ uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index)
	return buffer.entry.data;
	return buffer.entry.data;
}
}


/* VCPU Set MSR
/* _VCPU Set MSR
 *
 *
 * Input Args:
 * Input Args:
 *   vm - Virtual Machine
 *   vm - Virtual Machine
@@ -879,11 +879,11 @@ uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index)
 *
 *
 * Output Args: None
 * Output Args: None
 *
 *
 * Return: On success, nothing. On failure a TEST_ASSERT is produced.
 * Return: The result of KVM_SET_MSRS.
 *
 *
 * Set value of MSR for VCPU.
 * Sets the value of an MSR for the given VCPU.
 */
 */
void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index,
int _vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index,
		  uint64_t msr_value)
		  uint64_t msr_value)
{
{
	struct vcpu *vcpu = vcpu_find(vm, vcpuid);
	struct vcpu *vcpu = vcpu_find(vm, vcpuid);
@@ -899,6 +899,29 @@ void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index,
	buffer.entry.index = msr_index;
	buffer.entry.index = msr_index;
	buffer.entry.data = msr_value;
	buffer.entry.data = msr_value;
	r = ioctl(vcpu->fd, KVM_SET_MSRS, &buffer.header);
	r = ioctl(vcpu->fd, KVM_SET_MSRS, &buffer.header);
	return r;
}

/* 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)
{
	int r;

	r = _vcpu_set_msr(vm, vcpuid, msr_index, msr_value);
	TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n"
	TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n"
		"  rc: %i errno: %i", r, errno);
		"  rc: %i errno: %i", r, errno);
}
}
@@ -1000,19 +1023,45 @@ struct kvm_x86_state {
	struct kvm_msrs msrs;
	struct kvm_msrs msrs;
};
};


static int kvm_get_num_msrs(struct kvm_vm *vm)
static int kvm_get_num_msrs_fd(int kvm_fd)
{
{
	struct kvm_msr_list nmsrs;
	struct kvm_msr_list nmsrs;
	int r;
	int r;


	nmsrs.nmsrs = 0;
	nmsrs.nmsrs = 0;
	r = ioctl(vm->kvm_fd, KVM_GET_MSR_INDEX_LIST, &nmsrs);
	r = ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, &nmsrs);
	TEST_ASSERT(r == -1 && errno == E2BIG, "Unexpected result from KVM_GET_MSR_INDEX_LIST probe, r: %i",
	TEST_ASSERT(r == -1 && errno == E2BIG, "Unexpected result from KVM_GET_MSR_INDEX_LIST probe, r: %i",
		r);
		r);


	return nmsrs.nmsrs;
	return nmsrs.nmsrs;
}
}


static int kvm_get_num_msrs(struct kvm_vm *vm)
{
	return kvm_get_num_msrs_fd(vm->kvm_fd);
}

struct kvm_msr_list *kvm_get_msr_index_list(void)
{
	struct kvm_msr_list *list;
	int nmsrs, r, kvm_fd;

	kvm_fd = open(KVM_DEV_PATH, O_RDONLY);
	if (kvm_fd < 0)
		exit(KSFT_SKIP);

	nmsrs = kvm_get_num_msrs_fd(kvm_fd);
	list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0]));
	list->nmsrs = nmsrs;
	r = ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list);
	close(kvm_fd);

	TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_MSR_INDEX_LIST, r: %i",
		r);

	return list;
}

struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid)
struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid)
{
{
	struct vcpu *vcpu = vcpu_find(vm, vcpuid);
	struct vcpu *vcpu = vcpu_find(vm, vcpuid);
@@ -1158,7 +1207,12 @@ bool is_intel_cpu(void)
	return (ebx == chunk[0] && edx == chunk[1] && ecx == chunk[2]);
	return (ebx == chunk[0] && edx == chunk[1] && ecx == chunk[2]);
}
}


uint32_t kvm_get_cpuid_max(void)
uint32_t kvm_get_cpuid_max_basic(void)
{
	return kvm_get_supported_cpuid_entry(0)->eax;
}

uint32_t kvm_get_cpuid_max_extended(void)
{
{
	return kvm_get_supported_cpuid_entry(0x80000000)->eax;
	return kvm_get_supported_cpuid_entry(0x80000000)->eax;
}
}
@@ -1169,7 +1223,7 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits)
	bool pae;
	bool pae;


	/* SDM 4.1.4 */
	/* SDM 4.1.4 */
	if (kvm_get_cpuid_max() < 0x80000008) {
	if (kvm_get_cpuid_max_extended() < 0x80000008) {
		pae = kvm_get_supported_cpuid_entry(1)->edx & (1 << 6);
		pae = kvm_get_supported_cpuid_entry(1)->edx & (1 << 6);
		*pa_bits = pae ? 36 : 32;
		*pa_bits = pae ? 36 : 32;
		*va_bits = 32;
		*va_bits = 32;
+76 −0
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2019, Google LLC.
 *
 * Tests for the IA32_XSS MSR.
 */

#define _GNU_SOURCE /* for program_invocation_short_name */
#include <sys/ioctl.h>

#include "test_util.h"
#include "kvm_util.h"
#include "vmx.h"

#define VCPU_ID	      1
#define MSR_BITS      64

#define X86_FEATURE_XSAVES	(1<<3)

bool is_supported_msr(u32 msr_index)
{
	struct kvm_msr_list *list;
	bool found = false;
	int i;

	list = kvm_get_msr_index_list();
	for (i = 0; i < list->nmsrs; ++i) {
		if (list->indices[i] == msr_index) {
			found = true;
			break;
		}
	}

	free(list);
	return found;
}

int main(int argc, char *argv[])
{
	struct kvm_cpuid_entry2 *entry;
	bool xss_supported = false;
	struct kvm_vm *vm;
	uint64_t xss_val;
	int i, r;

	/* Create VM */
	vm = vm_create_default(VCPU_ID, 0, 0);

	if (kvm_get_cpuid_max_basic() >= 0xd) {
		entry = kvm_get_supported_cpuid_index(0xd, 1);
		xss_supported = entry && !!(entry->eax & X86_FEATURE_XSAVES);
	}
	if (!xss_supported) {
		printf("IA32_XSS is not supported by the vCPU.\n");
		exit(KSFT_SKIP);
	}

	xss_val = vcpu_get_msr(vm, VCPU_ID, MSR_IA32_XSS);
	TEST_ASSERT(xss_val == 0,
		    "MSR_IA32_XSS should be initialized to zero\n");

	vcpu_set_msr(vm, VCPU_ID, MSR_IA32_XSS, xss_val);
	/*
	 * At present, KVM only supports a guest IA32_XSS value of 0. Verify
	 * that trying to set the guest IA32_XSS to an unsupported value fails.
	 * Also, in the future when a non-zero value succeeds check that
	 * IA32_XSS is in the KVM_GET_MSR_INDEX_LIST.
	 */
	for (i = 0; i < MSR_BITS; ++i) {
		r = _vcpu_set_msr(vm, VCPU_ID, MSR_IA32_XSS, 1ull << i);
		TEST_ASSERT(r == 0 || is_supported_msr(MSR_IA32_XSS),
			    "IA32_XSS was able to be set, but was not found in KVM_GET_MSR_INDEX_LIST.\n");
	}

	kvm_vm_free(vm);
}