File Index
Files and directories
Sign in
FILE

cr4_cpuid_sync_test.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/kvm/x86/cr4_cpuid_sync_test.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * CR4 and CPUID sync test
  4 *
  5 * Copyright 2018, Red Hat, Inc. and/or its affiliates.
  6 *
  7 * Author:
  8 *   Wei Huang <wei@redhat.com>
  9 */
 10
 11#include <fcntl.h>
 12#include <stdio.h>
 13#include <stdlib.h>
 14#include <string.h>
 15#include <sys/ioctl.h>
 16
 17#include "test_util.h"
 18
 19#include "kvm_util.h"
 20#include "processor.h"
 21
 22#define MAGIC_HYPERCALL_PORT	0x80
 23
 24static void guest_code(void)
 25{
 26	u32 regs[4] = {
 27		[KVM_CPUID_EAX] = X86_FEATURE_OSXSAVE.function,
 28		[KVM_CPUID_ECX] = X86_FEATURE_OSXSAVE.index,
 29	};
 30
 31	/* CR4.OSXSAVE should be enabled by default (for selftests vCPUs). */
 32	GUEST_ASSERT(get_cr4() & X86_CR4_OSXSAVE);
 33
 34	/* verify CR4.OSXSAVE == CPUID.OSXSAVE */
 35	GUEST_ASSERT(this_cpu_has(X86_FEATURE_OSXSAVE));
 36
 37	/*
 38	 * Notify hypervisor to clear CR4.0SXSAVE, do CPUID and save output,
 39	 * and then restore CR4.  Do this all in  assembly to ensure no AVX
 40	 * instructions are executed while OSXSAVE=0.
 41	 */
 42	asm volatile (
 43		"out %%al, $" __stringify(MAGIC_HYPERCALL_PORT) "\n\t"
 44		"cpuid\n\t"
 45		"mov %%rdi, %%cr4\n\t"
 46		: "+a" (regs[KVM_CPUID_EAX]),
 47		  "=b" (regs[KVM_CPUID_EBX]),
 48		  "+c" (regs[KVM_CPUID_ECX]),
 49		  "=d" (regs[KVM_CPUID_EDX])
 50		: "D" (get_cr4())
 51	);
 52
 53	/* Verify KVM cleared OSXSAVE in CPUID when it was cleared in CR4. */
 54	GUEST_ASSERT(!(regs[X86_FEATURE_OSXSAVE.reg] & BIT(X86_FEATURE_OSXSAVE.bit)));
 55
 56	/* Verify restoring CR4 also restored OSXSAVE in CPUID. */
 57	GUEST_ASSERT(this_cpu_has(X86_FEATURE_OSXSAVE));
 58
 59	GUEST_DONE();
 60}
 61
 62int main(int argc, char *argv[])
 63{
 64	struct kvm_vcpu *vcpu;
 65	struct kvm_vm *vm;
 66	struct kvm_sregs sregs;
 67	struct ucall uc;
 68
 69	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XSAVE));
 70
 71	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
 72
 73	while (1) {
 74		vcpu_run(vcpu);
 75		TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
 76
 77		if (vcpu->run->io.port == MAGIC_HYPERCALL_PORT &&
 78		    vcpu->run->io.direction == KVM_EXIT_IO_OUT) {
 79			/* emulate hypervisor clearing CR4.OSXSAVE */
 80			vcpu_sregs_get(vcpu, &sregs);
 81			sregs.cr4 &= ~X86_CR4_OSXSAVE;
 82			vcpu_sregs_set(vcpu, &sregs);
 83			continue;
 84		}
 85
 86		switch (get_ucall(vcpu, &uc)) {
 87		case UCALL_ABORT:
 88			REPORT_GUEST_ASSERT(uc);
 89			break;
 90		case UCALL_DONE:
 91			goto done;
 92		default:
 93			TEST_FAIL("Unknown ucall %lu", uc.cmd);
 94		}
 95	}
 96
 97done:
 98	kvm_vm_free(vm);
 99	return 0;
100}
~/ Read-only file preview.