xref: /kvm-unit-tests/x86/hyperv_synic.c (revision 198dfd0e0aa8a069091f7d44a94f3e0a2a49093c)
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"
115aca024eSPaolo 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) {
93*198dfd0eSJanis Schoetterl-Glausch         report_fail("Hyper-V SynIC test, EOM read %#" PRIx64, 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         enable_apic();
15117fdf23eSAndrey Smetanin 
15217fdf23eSAndrey Smetanin         ncpus = cpu_count();
15344e9e319SAndrew Jones         if (ncpus > MAX_CPUS)
15444e9e319SAndrew Jones             report_abort("number cpus exceeds %d", MAX_CPUS);
15517fdf23eSAndrey Smetanin         printf("ncpus = %d\n", ncpus);
15617fdf23eSAndrey Smetanin 
15744e9e319SAndrew Jones         synic_prepare_sint_vecs();
15817fdf23eSAndrey Smetanin 
15944e9e319SAndrew Jones         printf("prepare\n");
16044e9e319SAndrew Jones         on_cpus(synic_test_prepare, (void *)read_cr3());
16144e9e319SAndrew Jones 
16217fdf23eSAndrey Smetanin         for (i = 0; i < ncpus; i++) {
16317fdf23eSAndrey Smetanin             printf("test %d -> %d\n", i, ncpus - 1 - i);
16417fdf23eSAndrey Smetanin             on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i));
16517fdf23eSAndrey Smetanin         }
16644e9e319SAndrew Jones         while (cpus_active() > 1)
16717fdf23eSAndrey Smetanin             pause();
16817fdf23eSAndrey Smetanin 
16917fdf23eSAndrey Smetanin         printf("cleanup\n");
17044e9e319SAndrew Jones         on_cpus(synic_test_cleanup, NULL);
17117fdf23eSAndrey Smetanin 
17217fdf23eSAndrey Smetanin         ok = true;
17317fdf23eSAndrey Smetanin         for (i = 0; i < ncpus; ++i) {
17417fdf23eSAndrey Smetanin             printf("isr_enter_count[%d] = %d\n",
17517fdf23eSAndrey Smetanin                    i, atomic_read(&isr_enter_count[i]));
17617fdf23eSAndrey Smetanin             ok &= atomic_read(&isr_enter_count[i]) == 16;
17717fdf23eSAndrey Smetanin         }
17817fdf23eSAndrey Smetanin 
179a299895bSThomas Huth         report(ok, "Hyper-V SynIC test");
18017fdf23eSAndrey Smetanin     } else {
18132b9603cSRadim Krčmář         printf("Hyper-V SynIC is not supported");
18217fdf23eSAndrey Smetanin     }
18317fdf23eSAndrey Smetanin 
18417fdf23eSAndrey Smetanin     return report_summary();
18517fdf23eSAndrey Smetanin }
186