1
0

hyperv_synic.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #include "libcflat.h"
  2. #include "processor.h"
  3. #include "msr.h"
  4. #include "isr.h"
  5. #include "vm.h"
  6. #include "apic.h"
  7. #include "desc.h"
  8. #include "smp.h"
  9. #include "atomic.h"
  10. #include "hyperv.h"
  11. #define MAX_CPUS 4
  12. static atomic_t isr_enter_count[MAX_CPUS];
  13. static void synic_sint_auto_eoi_isr(isr_regs_t *regs)
  14. {
  15. atomic_inc(&isr_enter_count[smp_id()]);
  16. }
  17. static void synic_sint_isr(isr_regs_t *regs)
  18. {
  19. atomic_inc(&isr_enter_count[smp_id()]);
  20. eoi();
  21. }
  22. struct sint_vec_entry {
  23. int vec;
  24. bool auto_eoi;
  25. };
  26. struct sint_vec_entry sint_vecs[HV_SYNIC_SINT_COUNT] = {
  27. {0xB0, false},
  28. {0xB1, false},
  29. {0xB2, false},
  30. {0xB3, true},
  31. {0xB4, false},
  32. {0xB5, false},
  33. {0xB6, false},
  34. {0xB7, false},
  35. {0xB8, true},
  36. {0xB9, false},
  37. {0xBA, true},
  38. {0xBB, false},
  39. {0xBC, false},
  40. {0xBD, false},
  41. {0xBE, true},
  42. {0xBF, false},
  43. };
  44. static void synic_prepare_sint_vecs(void)
  45. {
  46. bool auto_eoi;
  47. int i, vec;
  48. for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
  49. vec = sint_vecs[i].vec;
  50. auto_eoi = sint_vecs[i].auto_eoi;
  51. handle_irq(vec, (auto_eoi) ? synic_sint_auto_eoi_isr : synic_sint_isr);
  52. }
  53. }
  54. static void synic_sints_prepare(int vcpu)
  55. {
  56. bool auto_eoi;
  57. int i, vec;
  58. for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
  59. vec = sint_vecs[i].vec;
  60. auto_eoi = sint_vecs[i].auto_eoi;
  61. synic_sint_create(i, vec, auto_eoi);
  62. }
  63. }
  64. static void synic_test_prepare(void *ctx)
  65. {
  66. u64 r;
  67. int i = 0;
  68. write_cr3((ulong)ctx);
  69. irq_enable();
  70. rdmsr(HV_X64_MSR_SVERSION);
  71. rdmsr(HV_X64_MSR_SIMP);
  72. rdmsr(HV_X64_MSR_SIEFP);
  73. rdmsr(HV_X64_MSR_SCONTROL);
  74. for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
  75. rdmsr(HV_X64_MSR_SINT0 + i);
  76. }
  77. r = rdmsr(HV_X64_MSR_EOM);
  78. if (r != 0) {
  79. report("Hyper-V SynIC test, EOM read %#" PRIx64, false, r);
  80. return;
  81. }
  82. wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(alloc_page()) |
  83. HV_SYNIC_SIMP_ENABLE);
  84. wrmsr(HV_X64_MSR_SIEFP, (u64)virt_to_phys(alloc_page())|
  85. HV_SYNIC_SIEFP_ENABLE);
  86. wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE);
  87. synic_sints_prepare(smp_id());
  88. }
  89. static void synic_sints_test(int dst_vcpu)
  90. {
  91. int i;
  92. atomic_set(&isr_enter_count[dst_vcpu], 0);
  93. for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
  94. synic_sint_set(dst_vcpu, i);
  95. }
  96. while (atomic_read(&isr_enter_count[dst_vcpu]) != HV_SYNIC_SINT_COUNT) {
  97. pause();
  98. }
  99. }
  100. static void synic_test(void *ctx)
  101. {
  102. int dst_vcpu = (ulong)ctx;
  103. irq_enable();
  104. synic_sints_test(dst_vcpu);
  105. }
  106. static void synic_test_cleanup(void *ctx)
  107. {
  108. int i;
  109. irq_enable();
  110. for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
  111. synic_sint_destroy(i);
  112. }
  113. wrmsr(HV_X64_MSR_SCONTROL, 0);
  114. wrmsr(HV_X64_MSR_SIMP, 0);
  115. wrmsr(HV_X64_MSR_SIEFP, 0);
  116. }
  117. int main(int ac, char **av)
  118. {
  119. if (synic_supported()) {
  120. int ncpus, i;
  121. bool ok;
  122. setup_vm();
  123. smp_init();
  124. enable_apic();
  125. ncpus = cpu_count();
  126. if (ncpus > MAX_CPUS)
  127. report_abort("number cpus exceeds %d", MAX_CPUS);
  128. printf("ncpus = %d\n", ncpus);
  129. synic_prepare_sint_vecs();
  130. printf("prepare\n");
  131. on_cpus(synic_test_prepare, (void *)read_cr3());
  132. for (i = 0; i < ncpus; i++) {
  133. printf("test %d -> %d\n", i, ncpus - 1 - i);
  134. on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i));
  135. }
  136. while (cpus_active() > 1)
  137. pause();
  138. printf("cleanup\n");
  139. on_cpus(synic_test_cleanup, NULL);
  140. ok = true;
  141. for (i = 0; i < ncpus; ++i) {
  142. printf("isr_enter_count[%d] = %d\n",
  143. i, atomic_read(&isr_enter_count[i]));
  144. ok &= atomic_read(&isr_enter_count[i]) == 16;
  145. }
  146. report("Hyper-V SynIC test", ok);
  147. } else {
  148. printf("Hyper-V SynIC is not supported");
  149. }
  150. return report_summary();
  151. }