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
synic_sint_auto_eoi_isr(isr_regs_t * regs)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
synic_sint_isr(isr_regs_t * regs)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
synic_prepare_sint_vecs(void)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
synic_sints_prepare(int vcpu)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
synic_test_prepare(void * ctx)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);
82787f0aebSMaxim Levitsky sti();
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) {
93198dfd0eSJanis 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
synic_sints_test(int dst_vcpu)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
synic_test(void * ctx)12017fdf23eSAndrey Smetanin static void synic_test(void *ctx)
12117fdf23eSAndrey Smetanin {
12298fb3357SAndrey Smetanin int dst_vcpu = (ulong)ctx;
12317fdf23eSAndrey Smetanin
124787f0aebSMaxim Levitsky sti();
12517fdf23eSAndrey Smetanin synic_sints_test(dst_vcpu);
12617fdf23eSAndrey Smetanin }
12717fdf23eSAndrey Smetanin
synic_test_cleanup(void * ctx)12817fdf23eSAndrey Smetanin static void synic_test_cleanup(void *ctx)
12917fdf23eSAndrey Smetanin {
13017fdf23eSAndrey Smetanin int i;
13117fdf23eSAndrey Smetanin
132787f0aebSMaxim Levitsky sti();
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
main(int ac,char ** av)14217fdf23eSAndrey Smetanin int main(int ac, char **av)
14317fdf23eSAndrey Smetanin {
14417fdf23eSAndrey Smetanin int ncpus, i;
14517fdf23eSAndrey Smetanin bool ok;
14617fdf23eSAndrey Smetanin
147*65e843e1SVitaly Kuznetsov if (!hv_synic_supported()) {
148*65e843e1SVitaly Kuznetsov report_skip("Hyper-V SynIC is not supported");
149*65e843e1SVitaly Kuznetsov goto done;
150*65e843e1SVitaly Kuznetsov }
151*65e843e1SVitaly Kuznetsov
15217fdf23eSAndrey Smetanin setup_vm();
15317fdf23eSAndrey Smetanin enable_apic();
15417fdf23eSAndrey Smetanin
15517fdf23eSAndrey Smetanin ncpus = cpu_count();
15644e9e319SAndrew Jones if (ncpus > MAX_CPUS)
15744e9e319SAndrew Jones report_abort("number cpus exceeds %d", MAX_CPUS);
15817fdf23eSAndrey Smetanin printf("ncpus = %d\n", ncpus);
15917fdf23eSAndrey Smetanin
16044e9e319SAndrew Jones synic_prepare_sint_vecs();
16117fdf23eSAndrey Smetanin
16244e9e319SAndrew Jones printf("prepare\n");
16344e9e319SAndrew Jones on_cpus(synic_test_prepare, (void *)read_cr3());
16444e9e319SAndrew Jones
16517fdf23eSAndrey Smetanin for (i = 0; i < ncpus; i++) {
16617fdf23eSAndrey Smetanin printf("test %d -> %d\n", i, ncpus - 1 - i);
16717fdf23eSAndrey Smetanin on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i));
16817fdf23eSAndrey Smetanin }
16944e9e319SAndrew Jones while (cpus_active() > 1)
17017fdf23eSAndrey Smetanin pause();
17117fdf23eSAndrey Smetanin
17217fdf23eSAndrey Smetanin printf("cleanup\n");
17344e9e319SAndrew Jones on_cpus(synic_test_cleanup, NULL);
17417fdf23eSAndrey Smetanin
17517fdf23eSAndrey Smetanin ok = true;
17617fdf23eSAndrey Smetanin for (i = 0; i < ncpus; ++i) {
17717fdf23eSAndrey Smetanin printf("isr_enter_count[%d] = %d\n",
17817fdf23eSAndrey Smetanin i, atomic_read(&isr_enter_count[i]));
17917fdf23eSAndrey Smetanin ok &= atomic_read(&isr_enter_count[i]) == 16;
18017fdf23eSAndrey Smetanin }
18117fdf23eSAndrey Smetanin
182a299895bSThomas Huth report(ok, "Hyper-V SynIC test");
18317fdf23eSAndrey Smetanin
184*65e843e1SVitaly Kuznetsov done:
18517fdf23eSAndrey Smetanin return report_summary();
18617fdf23eSAndrey Smetanin }
187