forked from Minki/linux
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: Jim Mattson <jmattson@google.com> Signed-off-by: Aaron Lewis <aaronlewis@google.com> Change-Id: Ia2d644f69e2d6d8c27d7e0a7a45c2bf9c42bf5ff Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
5229743619
commit
c90992bfb0
1
tools/testing/selftests/kvm/.gitignore
vendored
1
tools/testing/selftests/kvm/.gitignore
vendored
@ -13,6 +13,7 @@
|
||||
/x86_64/vmx_dirty_log_test
|
||||
/x86_64/vmx_set_nested_state_test
|
||||
/x86_64/vmx_tsc_adjust_test
|
||||
/x86_64/xss_msr_test
|
||||
/clear_dirty_log_test
|
||||
/dirty_log_test
|
||||
/kvm_create_max_vcpus
|
||||
|
@ -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_set_nested_state_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 += dirty_log_test
|
||||
TEST_GEN_PROGS_x86_64 += kvm_create_max_vcpus
|
||||
|
@ -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,
|
||||
struct kvm_x86_state *state);
|
||||
|
||||
struct kvm_msr_list *kvm_get_msr_index_list(void);
|
||||
|
||||
struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
|
||||
void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid,
|
||||
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);
|
||||
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,
|
||||
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);
|
||||
|
||||
/*
|
||||
|
@ -869,6 +869,39 @@ uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index)
|
||||
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: The result of KVM_SET_MSRS.
|
||||
*
|
||||
* Sets the value of an MSR for the given VCPU.
|
||||
*/
|
||||
int _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);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* VCPU Set MSR
|
||||
*
|
||||
* Input Args:
|
||||
@ -886,19 +919,9 @@ 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)
|
||||
{
|
||||
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);
|
||||
r = _vcpu_set_msr(vm, vcpuid, msr_index, msr_value);
|
||||
TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n"
|
||||
" rc: %i errno: %i", r, errno);
|
||||
}
|
||||
@ -1000,19 +1023,45 @@ struct kvm_x86_state {
|
||||
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;
|
||||
int r;
|
||||
|
||||
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",
|
||||
r);
|
||||
|
||||
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 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]);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -1169,7 +1223,7 @@ void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits)
|
||||
bool pae;
|
||||
|
||||
/* 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);
|
||||
*pa_bits = pae ? 36 : 32;
|
||||
*va_bits = 32;
|
||||
|
76
tools/testing/selftests/kvm/x86_64/xss_msr_test.c
Normal file
76
tools/testing/selftests/kvm/x86_64/xss_msr_test.c
Normal file
@ -0,0 +1,76 @@
|
||||
// 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user