117fdf23eSAndrey Smetanin #include "libcflat.h" 217fdf23eSAndrey Smetanin #include "processor.h" 317fdf23eSAndrey Smetanin #include "msr.h" 417fdf23eSAndrey Smetanin #include "isr.h" 517fdf23eSAndrey Smetanin #include "vm.h" 617fdf23eSAndrey Smetanin #include "apic.h" 717fdf23eSAndrey Smetanin #include "desc.h" 817fdf23eSAndrey Smetanin #include "smp.h" 917fdf23eSAndrey Smetanin #include "atomic.h" 1098fb3357SAndrey Smetanin #include "hyperv.h" 11*5aca024eSPaolo Bonzini #include "alloc_page.h" 1217fdf23eSAndrey Smetanin 1317fdf23eSAndrey Smetanin #define MAX_CPUS 4 1417fdf23eSAndrey Smetanin 1517fdf23eSAndrey Smetanin static atomic_t isr_enter_count[MAX_CPUS]; 1617fdf23eSAndrey Smetanin 1717fdf23eSAndrey Smetanin static void synic_sint_auto_eoi_isr(isr_regs_t *regs) 1817fdf23eSAndrey Smetanin { 1917fdf23eSAndrey Smetanin atomic_inc(&isr_enter_count[smp_id()]); 2017fdf23eSAndrey Smetanin } 2117fdf23eSAndrey Smetanin 2217fdf23eSAndrey Smetanin static void synic_sint_isr(isr_regs_t *regs) 2317fdf23eSAndrey Smetanin { 2417fdf23eSAndrey Smetanin atomic_inc(&isr_enter_count[smp_id()]); 2517fdf23eSAndrey Smetanin eoi(); 2617fdf23eSAndrey Smetanin } 2717fdf23eSAndrey Smetanin 2817fdf23eSAndrey Smetanin struct sint_vec_entry { 2917fdf23eSAndrey Smetanin int vec; 3017fdf23eSAndrey Smetanin bool auto_eoi; 3117fdf23eSAndrey Smetanin }; 3217fdf23eSAndrey Smetanin 3317fdf23eSAndrey Smetanin struct sint_vec_entry sint_vecs[HV_SYNIC_SINT_COUNT] = { 3417fdf23eSAndrey Smetanin {0xB0, false}, 3517fdf23eSAndrey Smetanin {0xB1, false}, 3617fdf23eSAndrey Smetanin {0xB2, false}, 3717fdf23eSAndrey Smetanin {0xB3, true}, 3817fdf23eSAndrey Smetanin {0xB4, false}, 3917fdf23eSAndrey Smetanin {0xB5, false}, 4017fdf23eSAndrey Smetanin {0xB6, false}, 4117fdf23eSAndrey Smetanin {0xB7, false}, 4217fdf23eSAndrey Smetanin {0xB8, true}, 4317fdf23eSAndrey Smetanin {0xB9, false}, 4417fdf23eSAndrey Smetanin {0xBA, true}, 4517fdf23eSAndrey Smetanin {0xBB, false}, 4617fdf23eSAndrey Smetanin {0xBC, false}, 4717fdf23eSAndrey Smetanin {0xBD, false}, 4817fdf23eSAndrey Smetanin {0xBE, true}, 4917fdf23eSAndrey Smetanin {0xBF, false}, 5017fdf23eSAndrey Smetanin }; 5117fdf23eSAndrey Smetanin 5217fdf23eSAndrey Smetanin static void synic_prepare_sint_vecs(void) 5317fdf23eSAndrey Smetanin { 5417fdf23eSAndrey Smetanin bool auto_eoi; 5517fdf23eSAndrey Smetanin int i, vec; 5617fdf23eSAndrey Smetanin 5717fdf23eSAndrey Smetanin for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { 5817fdf23eSAndrey Smetanin vec = sint_vecs[i].vec; 5917fdf23eSAndrey Smetanin auto_eoi = sint_vecs[i].auto_eoi; 6017fdf23eSAndrey Smetanin handle_irq(vec, (auto_eoi) ? synic_sint_auto_eoi_isr : synic_sint_isr); 6117fdf23eSAndrey Smetanin } 6217fdf23eSAndrey Smetanin } 6317fdf23eSAndrey Smetanin 6498fb3357SAndrey Smetanin static void synic_sints_prepare(int vcpu) 6517fdf23eSAndrey Smetanin { 6617fdf23eSAndrey Smetanin bool auto_eoi; 6717fdf23eSAndrey Smetanin int i, vec; 6817fdf23eSAndrey Smetanin 6917fdf23eSAndrey Smetanin for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { 7017fdf23eSAndrey Smetanin vec = sint_vecs[i].vec; 7117fdf23eSAndrey Smetanin auto_eoi = sint_vecs[i].auto_eoi; 72d2c248afSRoman Kagan synic_sint_create(i, vec, auto_eoi); 7317fdf23eSAndrey Smetanin } 7417fdf23eSAndrey Smetanin } 7517fdf23eSAndrey Smetanin 7617fdf23eSAndrey Smetanin static void synic_test_prepare(void *ctx) 7717fdf23eSAndrey Smetanin { 7817fdf23eSAndrey Smetanin u64 r; 7917fdf23eSAndrey Smetanin int i = 0; 8017fdf23eSAndrey Smetanin 8117fdf23eSAndrey Smetanin write_cr3((ulong)ctx); 8217fdf23eSAndrey Smetanin irq_enable(); 8317fdf23eSAndrey Smetanin 8417fdf23eSAndrey Smetanin rdmsr(HV_X64_MSR_SVERSION); 8517fdf23eSAndrey Smetanin rdmsr(HV_X64_MSR_SIMP); 8617fdf23eSAndrey Smetanin rdmsr(HV_X64_MSR_SIEFP); 8717fdf23eSAndrey Smetanin rdmsr(HV_X64_MSR_SCONTROL); 8817fdf23eSAndrey Smetanin for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { 8917fdf23eSAndrey Smetanin rdmsr(HV_X64_MSR_SINT0 + i); 9017fdf23eSAndrey Smetanin } 9117fdf23eSAndrey Smetanin r = rdmsr(HV_X64_MSR_EOM); 9217fdf23eSAndrey Smetanin if (r != 0) { 93fd6aada0SRadim Krčmář report("Hyper-V SynIC test, EOM read %#" PRIx64, false, r); 9444e9e319SAndrew Jones return; 9517fdf23eSAndrey Smetanin } 9617fdf23eSAndrey Smetanin 9717fdf23eSAndrey Smetanin wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(alloc_page()) | 9817fdf23eSAndrey Smetanin HV_SYNIC_SIMP_ENABLE); 9917fdf23eSAndrey Smetanin wrmsr(HV_X64_MSR_SIEFP, (u64)virt_to_phys(alloc_page())| 10017fdf23eSAndrey Smetanin HV_SYNIC_SIEFP_ENABLE); 10117fdf23eSAndrey Smetanin wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE); 10217fdf23eSAndrey Smetanin 10317fdf23eSAndrey Smetanin synic_sints_prepare(smp_id()); 10417fdf23eSAndrey Smetanin } 10517fdf23eSAndrey Smetanin 10698fb3357SAndrey Smetanin static void synic_sints_test(int dst_vcpu) 10717fdf23eSAndrey Smetanin { 10817fdf23eSAndrey Smetanin int i; 10917fdf23eSAndrey Smetanin 11017fdf23eSAndrey Smetanin atomic_set(&isr_enter_count[dst_vcpu], 0); 11117fdf23eSAndrey Smetanin for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { 11298fb3357SAndrey Smetanin synic_sint_set(dst_vcpu, i); 11317fdf23eSAndrey Smetanin } 11417fdf23eSAndrey Smetanin 11517fdf23eSAndrey Smetanin while (atomic_read(&isr_enter_count[dst_vcpu]) != HV_SYNIC_SINT_COUNT) { 11617fdf23eSAndrey Smetanin pause(); 11717fdf23eSAndrey Smetanin } 11817fdf23eSAndrey Smetanin } 11917fdf23eSAndrey Smetanin 12017fdf23eSAndrey Smetanin static void synic_test(void *ctx) 12117fdf23eSAndrey Smetanin { 12298fb3357SAndrey Smetanin int dst_vcpu = (ulong)ctx; 12317fdf23eSAndrey Smetanin 12417fdf23eSAndrey Smetanin irq_enable(); 12517fdf23eSAndrey Smetanin synic_sints_test(dst_vcpu); 12617fdf23eSAndrey Smetanin } 12717fdf23eSAndrey Smetanin 12817fdf23eSAndrey Smetanin static void synic_test_cleanup(void *ctx) 12917fdf23eSAndrey Smetanin { 13017fdf23eSAndrey Smetanin int i; 13117fdf23eSAndrey Smetanin 13217fdf23eSAndrey Smetanin irq_enable(); 13317fdf23eSAndrey Smetanin for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { 134d2c248afSRoman Kagan synic_sint_destroy(i); 13517fdf23eSAndrey Smetanin } 13617fdf23eSAndrey Smetanin 13717fdf23eSAndrey Smetanin wrmsr(HV_X64_MSR_SCONTROL, 0); 13817fdf23eSAndrey Smetanin wrmsr(HV_X64_MSR_SIMP, 0); 13917fdf23eSAndrey Smetanin wrmsr(HV_X64_MSR_SIEFP, 0); 14017fdf23eSAndrey Smetanin } 14117fdf23eSAndrey Smetanin 14217fdf23eSAndrey Smetanin int main(int ac, char **av) 14317fdf23eSAndrey Smetanin { 14417fdf23eSAndrey Smetanin 14517fdf23eSAndrey Smetanin if (synic_supported()) { 14617fdf23eSAndrey Smetanin int ncpus, i; 14717fdf23eSAndrey Smetanin bool ok; 14817fdf23eSAndrey Smetanin 14917fdf23eSAndrey Smetanin setup_vm(); 15017fdf23eSAndrey Smetanin smp_init(); 15117fdf23eSAndrey Smetanin enable_apic(); 15217fdf23eSAndrey Smetanin 15317fdf23eSAndrey Smetanin ncpus = cpu_count(); 15444e9e319SAndrew Jones if (ncpus > MAX_CPUS) 15544e9e319SAndrew Jones report_abort("number cpus exceeds %d", MAX_CPUS); 15617fdf23eSAndrey Smetanin printf("ncpus = %d\n", ncpus); 15717fdf23eSAndrey Smetanin 15844e9e319SAndrew Jones synic_prepare_sint_vecs(); 15917fdf23eSAndrey Smetanin 16044e9e319SAndrew Jones printf("prepare\n"); 16144e9e319SAndrew Jones on_cpus(synic_test_prepare, (void *)read_cr3()); 16244e9e319SAndrew Jones 16317fdf23eSAndrey Smetanin for (i = 0; i < ncpus; i++) { 16417fdf23eSAndrey Smetanin printf("test %d -> %d\n", i, ncpus - 1 - i); 16517fdf23eSAndrey Smetanin on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i)); 16617fdf23eSAndrey Smetanin } 16744e9e319SAndrew Jones while (cpus_active() > 1) 16817fdf23eSAndrey Smetanin pause(); 16917fdf23eSAndrey Smetanin 17017fdf23eSAndrey Smetanin printf("cleanup\n"); 17144e9e319SAndrew Jones on_cpus(synic_test_cleanup, NULL); 17217fdf23eSAndrey Smetanin 17317fdf23eSAndrey Smetanin ok = true; 17417fdf23eSAndrey Smetanin for (i = 0; i < ncpus; ++i) { 17517fdf23eSAndrey Smetanin printf("isr_enter_count[%d] = %d\n", 17617fdf23eSAndrey Smetanin i, atomic_read(&isr_enter_count[i])); 17717fdf23eSAndrey Smetanin ok &= atomic_read(&isr_enter_count[i]) == 16; 17817fdf23eSAndrey Smetanin } 17917fdf23eSAndrey Smetanin 18017fdf23eSAndrey Smetanin report("Hyper-V SynIC test", ok); 18117fdf23eSAndrey Smetanin } else { 18232b9603cSRadim Krčmář printf("Hyper-V SynIC is not supported"); 18317fdf23eSAndrey Smetanin } 18417fdf23eSAndrey Smetanin 18517fdf23eSAndrey Smetanin return report_summary(); 18617fdf23eSAndrey Smetanin } 187