hyperv.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Hyper-V specific functions.
  4. *
  5. * Copyright (C) 2021, Red Hat Inc.
  6. */
  7. #include <stdint.h>
  8. #include "processor.h"
  9. #include "hyperv.h"
  10. const struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void)
  11. {
  12. static struct kvm_cpuid2 *cpuid;
  13. int kvm_fd;
  14. if (cpuid)
  15. return cpuid;
  16. cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
  17. kvm_fd = open_kvm_dev_path_or_exit();
  18. kvm_ioctl(kvm_fd, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
  19. close(kvm_fd);
  20. return cpuid;
  21. }
  22. void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu)
  23. {
  24. static struct kvm_cpuid2 *cpuid_full;
  25. const struct kvm_cpuid2 *cpuid_sys, *cpuid_hv;
  26. int i, nent = 0;
  27. if (!cpuid_full) {
  28. cpuid_sys = kvm_get_supported_cpuid();
  29. cpuid_hv = kvm_get_supported_hv_cpuid();
  30. cpuid_full = allocate_kvm_cpuid2(cpuid_sys->nent + cpuid_hv->nent);
  31. if (!cpuid_full) {
  32. perror("malloc");
  33. abort();
  34. }
  35. /* Need to skip KVM CPUID leaves 0x400000xx */
  36. for (i = 0; i < cpuid_sys->nent; i++) {
  37. if (cpuid_sys->entries[i].function >= 0x40000000 &&
  38. cpuid_sys->entries[i].function < 0x40000100)
  39. continue;
  40. cpuid_full->entries[nent] = cpuid_sys->entries[i];
  41. nent++;
  42. }
  43. memcpy(&cpuid_full->entries[nent], cpuid_hv->entries,
  44. cpuid_hv->nent * sizeof(struct kvm_cpuid_entry2));
  45. cpuid_full->nent = nent + cpuid_hv->nent;
  46. }
  47. vcpu_init_cpuid(vcpu, cpuid_full);
  48. }
  49. const struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu)
  50. {
  51. struct kvm_cpuid2 *cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES);
  52. vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, cpuid);
  53. return cpuid;
  54. }
  55. bool kvm_hv_cpu_has(struct kvm_x86_cpu_feature feature)
  56. {
  57. if (!kvm_has_cap(KVM_CAP_SYS_HYPERV_CPUID))
  58. return false;
  59. return kvm_cpuid_has(kvm_get_supported_hv_cpuid(), feature);
  60. }
  61. struct hyperv_test_pages *vcpu_alloc_hyperv_test_pages(struct kvm_vm *vm,
  62. vm_vaddr_t *p_hv_pages_gva)
  63. {
  64. vm_vaddr_t hv_pages_gva = vm_vaddr_alloc_page(vm);
  65. struct hyperv_test_pages *hv = addr_gva2hva(vm, hv_pages_gva);
  66. /* Setup of a region of guest memory for the VP Assist page. */
  67. hv->vp_assist = (void *)vm_vaddr_alloc_page(vm);
  68. hv->vp_assist_hva = addr_gva2hva(vm, (uintptr_t)hv->vp_assist);
  69. hv->vp_assist_gpa = addr_gva2gpa(vm, (uintptr_t)hv->vp_assist);
  70. /* Setup of a region of guest memory for the partition assist page. */
  71. hv->partition_assist = (void *)vm_vaddr_alloc_page(vm);
  72. hv->partition_assist_hva = addr_gva2hva(vm, (uintptr_t)hv->partition_assist);
  73. hv->partition_assist_gpa = addr_gva2gpa(vm, (uintptr_t)hv->partition_assist);
  74. /* Setup of a region of guest memory for the enlightened VMCS. */
  75. hv->enlightened_vmcs = (void *)vm_vaddr_alloc_page(vm);
  76. hv->enlightened_vmcs_hva = addr_gva2hva(vm, (uintptr_t)hv->enlightened_vmcs);
  77. hv->enlightened_vmcs_gpa = addr_gva2gpa(vm, (uintptr_t)hv->enlightened_vmcs);
  78. *p_hv_pages_gva = hv_pages_gva;
  79. return hv;
  80. }
  81. int enable_vp_assist(uint64_t vp_assist_pa, void *vp_assist)
  82. {
  83. uint64_t val = (vp_assist_pa & HV_X64_MSR_VP_ASSIST_PAGE_ADDRESS_MASK) |
  84. HV_X64_MSR_VP_ASSIST_PAGE_ENABLE;
  85. wrmsr(HV_X64_MSR_VP_ASSIST_PAGE, val);
  86. current_vp_assist = vp_assist;
  87. return 0;
  88. }