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