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