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