linux/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c
<<
>>
Prefs
   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
 112        kvm_vm_free(vm);
 113
 114done:
 115        return 0;
 116}
 117