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" 1117fdf23eSAndrey Smetanin 1217fdf23eSAndrey Smetanin #define MAX_CPUS 4 1317fdf23eSAndrey Smetanin 1417fdf23eSAndrey Smetanin static atomic_t isr_enter_count[MAX_CPUS]; 1517fdf23eSAndrey Smetanin static atomic_t cpus_comp_count; 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; 7298fb3357SAndrey Smetanin synic_sint_create(vcpu, 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) { 93*fd6aada0SRadim Krčmář report("Hyper-V SynIC test, EOM read %#" PRIx64, false, r); 9417fdf23eSAndrey Smetanin goto ret; 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 ret: 10517fdf23eSAndrey Smetanin atomic_inc(&cpus_comp_count); 10617fdf23eSAndrey Smetanin } 10717fdf23eSAndrey Smetanin 10898fb3357SAndrey Smetanin static void synic_sints_test(int dst_vcpu) 10917fdf23eSAndrey Smetanin { 11017fdf23eSAndrey Smetanin int i; 11117fdf23eSAndrey Smetanin 11217fdf23eSAndrey Smetanin atomic_set(&isr_enter_count[dst_vcpu], 0); 11317fdf23eSAndrey Smetanin for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { 11498fb3357SAndrey Smetanin synic_sint_set(dst_vcpu, i); 11517fdf23eSAndrey Smetanin } 11617fdf23eSAndrey Smetanin 11717fdf23eSAndrey Smetanin while (atomic_read(&isr_enter_count[dst_vcpu]) != HV_SYNIC_SINT_COUNT) { 11817fdf23eSAndrey Smetanin pause(); 11917fdf23eSAndrey Smetanin } 12017fdf23eSAndrey Smetanin } 12117fdf23eSAndrey Smetanin 12217fdf23eSAndrey Smetanin static void synic_test(void *ctx) 12317fdf23eSAndrey Smetanin { 12498fb3357SAndrey Smetanin int dst_vcpu = (ulong)ctx; 12517fdf23eSAndrey Smetanin 12617fdf23eSAndrey Smetanin irq_enable(); 12717fdf23eSAndrey Smetanin synic_sints_test(dst_vcpu); 12817fdf23eSAndrey Smetanin atomic_inc(&cpus_comp_count); 12917fdf23eSAndrey Smetanin } 13017fdf23eSAndrey Smetanin 13117fdf23eSAndrey Smetanin static void synic_test_cleanup(void *ctx) 13217fdf23eSAndrey Smetanin { 13398fb3357SAndrey Smetanin int vcpu = smp_id(); 13417fdf23eSAndrey Smetanin int i; 13517fdf23eSAndrey Smetanin 13617fdf23eSAndrey Smetanin irq_enable(); 13717fdf23eSAndrey Smetanin for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) { 13898fb3357SAndrey Smetanin synic_sint_destroy(vcpu, i); 13917fdf23eSAndrey Smetanin wrmsr(HV_X64_MSR_SINT0 + i, 0xFF|HV_SYNIC_SINT_MASKED); 14017fdf23eSAndrey Smetanin } 14117fdf23eSAndrey Smetanin 14217fdf23eSAndrey Smetanin wrmsr(HV_X64_MSR_SCONTROL, 0); 14317fdf23eSAndrey Smetanin wrmsr(HV_X64_MSR_SIMP, 0); 14417fdf23eSAndrey Smetanin wrmsr(HV_X64_MSR_SIEFP, 0); 14517fdf23eSAndrey Smetanin atomic_inc(&cpus_comp_count); 14617fdf23eSAndrey Smetanin } 14717fdf23eSAndrey Smetanin 14817fdf23eSAndrey Smetanin int main(int ac, char **av) 14917fdf23eSAndrey Smetanin { 15017fdf23eSAndrey Smetanin 15117fdf23eSAndrey Smetanin if (synic_supported()) { 15217fdf23eSAndrey Smetanin int ncpus, i; 15317fdf23eSAndrey Smetanin bool ok; 15417fdf23eSAndrey Smetanin 15517fdf23eSAndrey Smetanin setup_vm(); 15617fdf23eSAndrey Smetanin smp_init(); 15717fdf23eSAndrey Smetanin enable_apic(); 15817fdf23eSAndrey Smetanin 15917fdf23eSAndrey Smetanin synic_prepare_sint_vecs(); 16017fdf23eSAndrey Smetanin 16117fdf23eSAndrey Smetanin ncpus = cpu_count(); 16217fdf23eSAndrey Smetanin if (ncpus > MAX_CPUS) { 16317fdf23eSAndrey Smetanin ncpus = MAX_CPUS; 16417fdf23eSAndrey Smetanin } 16517fdf23eSAndrey Smetanin printf("ncpus = %d\n", ncpus); 16617fdf23eSAndrey Smetanin 16717fdf23eSAndrey Smetanin atomic_set(&cpus_comp_count, 0); 16817fdf23eSAndrey Smetanin for (i = 0; i < ncpus; i++) { 16917fdf23eSAndrey Smetanin on_cpu_async(i, synic_test_prepare, (void *)read_cr3()); 17017fdf23eSAndrey Smetanin } 17117fdf23eSAndrey Smetanin printf("prepare\n"); 17217fdf23eSAndrey Smetanin while (atomic_read(&cpus_comp_count) != ncpus) { 17317fdf23eSAndrey Smetanin pause(); 17417fdf23eSAndrey Smetanin } 17517fdf23eSAndrey Smetanin 17617fdf23eSAndrey Smetanin atomic_set(&cpus_comp_count, 0); 17717fdf23eSAndrey Smetanin for (i = 0; i < ncpus; i++) { 17817fdf23eSAndrey Smetanin printf("test %d -> %d\n", i, ncpus - 1 - i); 17917fdf23eSAndrey Smetanin on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i)); 18017fdf23eSAndrey Smetanin } 18117fdf23eSAndrey Smetanin while (atomic_read(&cpus_comp_count) != ncpus) { 18217fdf23eSAndrey Smetanin pause(); 18317fdf23eSAndrey Smetanin } 18417fdf23eSAndrey Smetanin 18517fdf23eSAndrey Smetanin atomic_set(&cpus_comp_count, 0); 18617fdf23eSAndrey Smetanin for (i = 0; i < ncpus; i++) { 18717fdf23eSAndrey Smetanin on_cpu_async(i, synic_test_cleanup, NULL); 18817fdf23eSAndrey Smetanin } 18917fdf23eSAndrey Smetanin printf("cleanup\n"); 19017fdf23eSAndrey Smetanin while (atomic_read(&cpus_comp_count) != ncpus) { 19117fdf23eSAndrey Smetanin pause(); 19217fdf23eSAndrey Smetanin } 19317fdf23eSAndrey Smetanin 19417fdf23eSAndrey Smetanin ok = true; 19517fdf23eSAndrey Smetanin for (i = 0; i < ncpus; ++i) { 19617fdf23eSAndrey Smetanin printf("isr_enter_count[%d] = %d\n", 19717fdf23eSAndrey Smetanin i, atomic_read(&isr_enter_count[i])); 19817fdf23eSAndrey Smetanin ok &= atomic_read(&isr_enter_count[i]) == 16; 19917fdf23eSAndrey Smetanin } 20017fdf23eSAndrey Smetanin 20117fdf23eSAndrey Smetanin report("Hyper-V SynIC test", ok); 20217fdf23eSAndrey Smetanin } else { 20332b9603cSRadim Krčmář printf("Hyper-V SynIC is not supported"); 20417fdf23eSAndrey Smetanin } 20517fdf23eSAndrey Smetanin 20617fdf23eSAndrey Smetanin return report_summary(); 20717fdf23eSAndrey Smetanin } 208