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