cr4_cpuid_sync_test.c 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  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. #include <fcntl.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <sys/ioctl.h>
  15. #include "test_util.h"
  16. #include "kvm_util.h"
  17. #include "x86.h"
  18. #define X86_FEATURE_XSAVE (1<<26)
  19. #define X86_FEATURE_OSXSAVE (1<<27)
  20. #define VCPU_ID 1
  21. static inline bool cr4_cpuid_is_sync(void)
  22. {
  23. int func, subfunc;
  24. uint32_t eax, ebx, ecx, edx;
  25. uint64_t cr4;
  26. func = 0x1;
  27. subfunc = 0x0;
  28. __asm__ __volatile__("cpuid"
  29. : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
  30. : "a"(func), "c"(subfunc));
  31. cr4 = get_cr4();
  32. return (!!(ecx & X86_FEATURE_OSXSAVE)) == (!!(cr4 & X86_CR4_OSXSAVE));
  33. }
  34. static void guest_code(void)
  35. {
  36. uint64_t cr4;
  37. /* turn on CR4.OSXSAVE */
  38. cr4 = get_cr4();
  39. cr4 |= X86_CR4_OSXSAVE;
  40. set_cr4(cr4);
  41. /* verify CR4.OSXSAVE == CPUID.OSXSAVE */
  42. GUEST_ASSERT(cr4_cpuid_is_sync());
  43. /* notify hypervisor to change CR4 */
  44. GUEST_SYNC(0);
  45. /* check again */
  46. GUEST_ASSERT(cr4_cpuid_is_sync());
  47. GUEST_DONE();
  48. }
  49. int main(int argc, char *argv[])
  50. {
  51. struct kvm_run *run;
  52. struct kvm_vm *vm;
  53. struct kvm_sregs sregs;
  54. struct kvm_cpuid_entry2 *entry;
  55. int rc;
  56. entry = kvm_get_supported_cpuid_entry(1);
  57. if (!(entry->ecx & X86_FEATURE_XSAVE)) {
  58. printf("XSAVE feature not supported, skipping test\n");
  59. return 0;
  60. }
  61. /* Tell stdout not to buffer its content */
  62. setbuf(stdout, NULL);
  63. /* Create VM */
  64. vm = vm_create_default(VCPU_ID, 0, guest_code);
  65. vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid());
  66. run = vcpu_state(vm, VCPU_ID);
  67. while (1) {
  68. rc = _vcpu_run(vm, VCPU_ID);
  69. if (run->exit_reason == KVM_EXIT_IO) {
  70. switch (run->io.port) {
  71. case GUEST_PORT_SYNC:
  72. /* emulate hypervisor clearing CR4.OSXSAVE */
  73. vcpu_sregs_get(vm, VCPU_ID, &sregs);
  74. sregs.cr4 &= ~X86_CR4_OSXSAVE;
  75. vcpu_sregs_set(vm, VCPU_ID, &sregs);
  76. break;
  77. case GUEST_PORT_ABORT:
  78. TEST_ASSERT(false, "Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit.");
  79. break;
  80. case GUEST_PORT_DONE:
  81. goto done;
  82. default:
  83. TEST_ASSERT(false, "Unknown port 0x%x.",
  84. run->io.port);
  85. }
  86. }
  87. }
  88. kvm_vm_free(vm);
  89. done:
  90. return 0;
  91. }