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(vcpu, 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 0x%llx", 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 vcpu = smp_id(); 134 int i; 135 136 irq_enable(); 137 for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { 138 synic_sint_destroy(vcpu, i); 139 wrmsr(HV_X64_MSR_SINT0 + i, 0xFF|HV_SYNIC_SINT_MASKED); 140 } 141 142 wrmsr(HV_X64_MSR_SCONTROL, 0); 143 wrmsr(HV_X64_MSR_SIMP, 0); 144 wrmsr(HV_X64_MSR_SIEFP, 0); 145 atomic_inc(&cpus_comp_count); 146 } 147 148 int main(int ac, char **av) 149 { 150 151 if (synic_supported()) { 152 int ncpus, i; 153 bool ok; 154 155 setup_vm(); 156 smp_init(); 157 enable_apic(); 158 159 synic_prepare_sint_vecs(); 160 161 ncpus = cpu_count(); 162 if (ncpus > MAX_CPUS) { 163 ncpus = MAX_CPUS; 164 } 165 printf("ncpus = %d\n", ncpus); 166 167 atomic_set(&cpus_comp_count, 0); 168 for (i = 0; i < ncpus; i++) { 169 on_cpu_async(i, synic_test_prepare, (void *)read_cr3()); 170 } 171 printf("prepare\n"); 172 while (atomic_read(&cpus_comp_count) != ncpus) { 173 pause(); 174 } 175 176 atomic_set(&cpus_comp_count, 0); 177 for (i = 0; i < ncpus; i++) { 178 printf("test %d -> %d\n", i, ncpus - 1 - i); 179 on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i)); 180 } 181 while (atomic_read(&cpus_comp_count) != ncpus) { 182 pause(); 183 } 184 185 atomic_set(&cpus_comp_count, 0); 186 for (i = 0; i < ncpus; i++) { 187 on_cpu_async(i, synic_test_cleanup, NULL); 188 } 189 printf("cleanup\n"); 190 while (atomic_read(&cpus_comp_count) != ncpus) { 191 pause(); 192 } 193 194 ok = true; 195 for (i = 0; i < ncpus; ++i) { 196 printf("isr_enter_count[%d] = %d\n", 197 i, atomic_read(&isr_enter_count[i])); 198 ok &= atomic_read(&isr_enter_count[i]) == 16; 199 } 200 201 report("Hyper-V SynIC test", ok); 202 } else { 203 printf("Hyper-V SynIC is not supported"); 204 } 205 206 return report_summary(); 207 } 208