linux/tools/testing/selftests/kvm/cr4_cpuid_sync_test.c
Peter Xu aee41be593 kvm: selftest: pass in extra memory when create vm
This information can be used to decide the size of the default memory
slot, which will need to cover the extra pages with page tables.

Signed-off-by: Peter Xu <peterx@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2018-08-22 16:48:38 +02:00

114 lines
2.2 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* CR4 and CPUID sync test
*
* Copyright 2018, Red Hat, Inc. and/or its affiliates.
*
* Author:
* Wei Huang <wei@redhat.com>
*/
#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 X86_FEATURE_XSAVE (1<<26)
#define X86_FEATURE_OSXSAVE (1<<27)
#define VCPU_ID 1
static inline bool cr4_cpuid_is_sync(void)
{
int func, subfunc;
uint32_t eax, ebx, ecx, edx;
uint64_t cr4;
func = 0x1;
subfunc = 0x0;
__asm__ __volatile__("cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(func), "c"(subfunc));
cr4 = get_cr4();
return (!!(ecx & X86_FEATURE_OSXSAVE)) == (!!(cr4 & X86_CR4_OSXSAVE));
}
static void guest_code(void)
{
uint64_t cr4;
/* turn on CR4.OSXSAVE */
cr4 = get_cr4();
cr4 |= X86_CR4_OSXSAVE;
set_cr4(cr4);
/* verify CR4.OSXSAVE == CPUID.OSXSAVE */
GUEST_ASSERT(cr4_cpuid_is_sync());
/* notify hypervisor to change CR4 */
GUEST_SYNC(0);
/* check again */
GUEST_ASSERT(cr4_cpuid_is_sync());
GUEST_DONE();
}
int main(int argc, char *argv[])
{
struct kvm_run *run;
struct kvm_vm *vm;
struct kvm_sregs sregs;
struct kvm_cpuid_entry2 *entry;
int rc;
entry = kvm_get_supported_cpuid_entry(1);
if (!(entry->ecx & X86_FEATURE_XSAVE)) {
printf("XSAVE feature not supported, skipping test\n");
return 0;
}
/* Tell stdout not to buffer its content */
setbuf(stdout, NULL);
/* Create VM */
vm = vm_create_default(VCPU_ID, 0, guest_code);
vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
run = vcpu_state(vm, VCPU_ID);
while (1) {
rc = _vcpu_run(vm, VCPU_ID);
if (run->exit_reason == KVM_EXIT_IO) {
switch (run->io.port) {
case GUEST_PORT_SYNC:
/* emulate hypervisor clearing CR4.OSXSAVE */
vcpu_sregs_get(vm, VCPU_ID, &sregs);
sregs.cr4 &= ~X86_CR4_OSXSAVE;
vcpu_sregs_set(vm, VCPU_ID, &sregs);
break;
case GUEST_PORT_ABORT:
TEST_ASSERT(false, "Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit.");
break;
case GUEST_PORT_DONE:
goto done;
default:
TEST_ASSERT(false, "Unknown port 0x%x.",
run->io.port);
}
}
}
kvm_vm_free(vm);
done:
return 0;
}