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                printf("XSAVE feature not supported, skipping test\n");
  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        vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
  85        run = vcpu_state(vm, VCPU_ID);
  86
  87        while (1) {
  88                rc = _vcpu_run(vm, VCPU_ID);
  89
  90                TEST_ASSERT(rc == 0, "vcpu_run failed: %d\n", rc);
  91                TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
  92                            "Unexpected exit reason: %u (%s),\n",
  93                            run->exit_reason,
  94                            exit_reason_str(run->exit_reason));
  95
  96                switch (get_ucall(vm, VCPU_ID, &uc)) {
  97                case UCALL_SYNC:
  98                        /* emulate hypervisor clearing CR4.OSXSAVE */
  99                        vcpu_sregs_get(vm, VCPU_ID, &sregs);
 100                        sregs.cr4 &= ~X86_CR4_OSXSAVE;
 101                        vcpu_sregs_set(vm, VCPU_ID, &sregs);
 102                        break;
 103                case UCALL_ABORT:
 104                        TEST_ASSERT(false, "Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit.");
 105                        break;
 106                case UCALL_DONE:
 107                        goto done;
 108                default:
 109                        TEST_ASSERT(false, "Unknown ucall 0x%x.", uc.cmd);
 110                }
 111        }
 112
 113        kvm_vm_free(vm);
 114
 115done:
 116        return 0;
 117}
 118