cr4_cpuid_sync_test.c (2339B)
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 X86_FEATURE_XSAVE (1<<26) 23#define X86_FEATURE_OSXSAVE (1<<27) 24#define VCPU_ID 1 25 26static inline bool cr4_cpuid_is_sync(void) 27{ 28 int func, subfunc; 29 uint32_t eax, ebx, ecx, edx; 30 uint64_t cr4; 31 32 func = 0x1; 33 subfunc = 0x0; 34 __asm__ __volatile__("cpuid" 35 : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) 36 : "a"(func), "c"(subfunc)); 37 38 cr4 = get_cr4(); 39 40 return (!!(ecx & X86_FEATURE_OSXSAVE)) == (!!(cr4 & X86_CR4_OSXSAVE)); 41} 42 43static void guest_code(void) 44{ 45 uint64_t cr4; 46 47 /* turn on CR4.OSXSAVE */ 48 cr4 = get_cr4(); 49 cr4 |= X86_CR4_OSXSAVE; 50 set_cr4(cr4); 51 52 /* verify CR4.OSXSAVE == CPUID.OSXSAVE */ 53 GUEST_ASSERT(cr4_cpuid_is_sync()); 54 55 /* notify hypervisor to change CR4 */ 56 GUEST_SYNC(0); 57 58 /* check again */ 59 GUEST_ASSERT(cr4_cpuid_is_sync()); 60 61 GUEST_DONE(); 62} 63 64int main(int argc, char *argv[]) 65{ 66 struct kvm_run *run; 67 struct kvm_vm *vm; 68 struct kvm_sregs sregs; 69 struct kvm_cpuid_entry2 *entry; 70 struct ucall uc; 71 int rc; 72 73 entry = kvm_get_supported_cpuid_entry(1); 74 if (!(entry->ecx & X86_FEATURE_XSAVE)) { 75 print_skip("XSAVE feature not supported"); 76 return 0; 77 } 78 79 /* Tell stdout not to buffer its content */ 80 setbuf(stdout, NULL); 81 82 /* Create VM */ 83 vm = vm_create_default(VCPU_ID, 0, guest_code); 84 run = vcpu_state(vm, VCPU_ID); 85 86 while (1) { 87 rc = _vcpu_run(vm, VCPU_ID); 88 89 TEST_ASSERT(rc == 0, "vcpu_run failed: %d\n", rc); 90 TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, 91 "Unexpected exit reason: %u (%s),\n", 92 run->exit_reason, 93 exit_reason_str(run->exit_reason)); 94 95 switch (get_ucall(vm, VCPU_ID, &uc)) { 96 case UCALL_SYNC: 97 /* emulate hypervisor clearing CR4.OSXSAVE */ 98 vcpu_sregs_get(vm, VCPU_ID, &sregs); 99 sregs.cr4 &= ~X86_CR4_OSXSAVE; 100 vcpu_sregs_set(vm, VCPU_ID, &sregs); 101 break; 102 case UCALL_ABORT: 103 TEST_FAIL("Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit."); 104 break; 105 case UCALL_DONE: 106 goto done; 107 default: 108 TEST_FAIL("Unknown ucall %lu", uc.cmd); 109 } 110 } 111 112done: 113 kvm_vm_free(vm); 114 return 0; 115}