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 12 #define MAX_CPUS 4 13 14 static atomic_t isr_enter_count[MAX_CPUS]; 15 static atomic_t cpus_comp_count; 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 irq_enable(); 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("Hyper-V SynIC test, EOM read %#" PRIx64, false, r); 94 goto ret; 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 ret: 105 atomic_inc(&cpus_comp_count); 106 } 107 108 static void synic_sints_test(int dst_vcpu) 109 { 110 int i; 111 112 atomic_set(&isr_enter_count[dst_vcpu], 0); 113 for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { 114 synic_sint_set(dst_vcpu, i); 115 } 116 117 while (atomic_read(&isr_enter_count[dst_vcpu]) != HV_SYNIC_SINT_COUNT) { 118 pause(); 119 } 120 } 121 122 static void synic_test(void *ctx) 123 { 124 int dst_vcpu = (ulong)ctx; 125 126 irq_enable(); 127 synic_sints_test(dst_vcpu); 128 atomic_inc(&cpus_comp_count); 129 } 130 131 static void synic_test_cleanup(void *ctx) 132 { 133 int i; 134 135 irq_enable(); 136 for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { 137 synic_sint_destroy(i); 138 } 139 140 wrmsr(HV_X64_MSR_SCONTROL, 0); 141 wrmsr(HV_X64_MSR_SIMP, 0); 142 wrmsr(HV_X64_MSR_SIEFP, 0); 143 atomic_inc(&cpus_comp_count); 144 } 145 146 int main(int ac, char **av) 147 { 148 149 if (synic_supported()) { 150 int ncpus, i; 151 bool ok; 152 153 setup_vm(); 154 smp_init(); 155 enable_apic(); 156 157 synic_prepare_sint_vecs(); 158 159 ncpus = cpu_count(); 160 if (ncpus > MAX_CPUS) { 161 ncpus = MAX_CPUS; 162 } 163 printf("ncpus = %d\n", ncpus); 164 165 atomic_set(&cpus_comp_count, 0); 166 for (i = 0; i < ncpus; i++) { 167 on_cpu_async(i, synic_test_prepare, (void *)read_cr3()); 168 } 169 printf("prepare\n"); 170 while (atomic_read(&cpus_comp_count) != ncpus) { 171 pause(); 172 } 173 174 atomic_set(&cpus_comp_count, 0); 175 for (i = 0; i < ncpus; i++) { 176 printf("test %d -> %d\n", i, ncpus - 1 - i); 177 on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i)); 178 } 179 while (atomic_read(&cpus_comp_count) != ncpus) { 180 pause(); 181 } 182 183 atomic_set(&cpus_comp_count, 0); 184 for (i = 0; i < ncpus; i++) { 185 on_cpu_async(i, synic_test_cleanup, NULL); 186 } 187 printf("cleanup\n"); 188 while (atomic_read(&cpus_comp_count) != ncpus) { 189 pause(); 190 } 191 192 ok = true; 193 for (i = 0; i < ncpus; ++i) { 194 printf("isr_enter_count[%d] = %d\n", 195 i, atomic_read(&isr_enter_count[i])); 196 ok &= atomic_read(&isr_enter_count[i]) == 16; 197 } 198 199 report("Hyper-V SynIC test", ok); 200 } else { 201 printf("Hyper-V SynIC is not supported"); 202 } 203 204 return report_summary(); 205 } 206