123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- #include "libcflat.h"
- #include "processor.h"
- #include "msr.h"
- #include "isr.h"
- #include "vm.h"
- #include "apic.h"
- #include "desc.h"
- #include "smp.h"
- #include "atomic.h"
- #include "hyperv.h"
- #define MAX_CPUS 4
- static atomic_t isr_enter_count[MAX_CPUS];
- static void synic_sint_auto_eoi_isr(isr_regs_t *regs)
- {
- atomic_inc(&isr_enter_count[smp_id()]);
- }
- static void synic_sint_isr(isr_regs_t *regs)
- {
- atomic_inc(&isr_enter_count[smp_id()]);
- eoi();
- }
- struct sint_vec_entry {
- int vec;
- bool auto_eoi;
- };
- struct sint_vec_entry sint_vecs[HV_SYNIC_SINT_COUNT] = {
- {0xB0, false},
- {0xB1, false},
- {0xB2, false},
- {0xB3, true},
- {0xB4, false},
- {0xB5, false},
- {0xB6, false},
- {0xB7, false},
- {0xB8, true},
- {0xB9, false},
- {0xBA, true},
- {0xBB, false},
- {0xBC, false},
- {0xBD, false},
- {0xBE, true},
- {0xBF, false},
- };
- static void synic_prepare_sint_vecs(void)
- {
- bool auto_eoi;
- int i, vec;
- for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
- vec = sint_vecs[i].vec;
- auto_eoi = sint_vecs[i].auto_eoi;
- handle_irq(vec, (auto_eoi) ? synic_sint_auto_eoi_isr : synic_sint_isr);
- }
- }
- static void synic_sints_prepare(int vcpu)
- {
- bool auto_eoi;
- int i, vec;
- for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
- vec = sint_vecs[i].vec;
- auto_eoi = sint_vecs[i].auto_eoi;
- synic_sint_create(i, vec, auto_eoi);
- }
- }
- static void synic_test_prepare(void *ctx)
- {
- u64 r;
- int i = 0;
- write_cr3((ulong)ctx);
- irq_enable();
- rdmsr(HV_X64_MSR_SVERSION);
- rdmsr(HV_X64_MSR_SIMP);
- rdmsr(HV_X64_MSR_SIEFP);
- rdmsr(HV_X64_MSR_SCONTROL);
- for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
- rdmsr(HV_X64_MSR_SINT0 + i);
- }
- r = rdmsr(HV_X64_MSR_EOM);
- if (r != 0) {
- report("Hyper-V SynIC test, EOM read %#" PRIx64, false, r);
- return;
- }
- wrmsr(HV_X64_MSR_SIMP, (u64)virt_to_phys(alloc_page()) |
- HV_SYNIC_SIMP_ENABLE);
- wrmsr(HV_X64_MSR_SIEFP, (u64)virt_to_phys(alloc_page())|
- HV_SYNIC_SIEFP_ENABLE);
- wrmsr(HV_X64_MSR_SCONTROL, HV_SYNIC_CONTROL_ENABLE);
- synic_sints_prepare(smp_id());
- }
- static void synic_sints_test(int dst_vcpu)
- {
- int i;
- atomic_set(&isr_enter_count[dst_vcpu], 0);
- for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
- synic_sint_set(dst_vcpu, i);
- }
- while (atomic_read(&isr_enter_count[dst_vcpu]) != HV_SYNIC_SINT_COUNT) {
- pause();
- }
- }
- static void synic_test(void *ctx)
- {
- int dst_vcpu = (ulong)ctx;
- irq_enable();
- synic_sints_test(dst_vcpu);
- }
- static void synic_test_cleanup(void *ctx)
- {
- int i;
- irq_enable();
- for (i = 0; i < HV_SYNIC_SINT_COUNT; i++) {
- synic_sint_destroy(i);
- }
- wrmsr(HV_X64_MSR_SCONTROL, 0);
- wrmsr(HV_X64_MSR_SIMP, 0);
- wrmsr(HV_X64_MSR_SIEFP, 0);
- }
- int main(int ac, char **av)
- {
- if (synic_supported()) {
- int ncpus, i;
- bool ok;
- setup_vm();
- smp_init();
- enable_apic();
- ncpus = cpu_count();
- if (ncpus > MAX_CPUS)
- report_abort("number cpus exceeds %d", MAX_CPUS);
- printf("ncpus = %d\n", ncpus);
- synic_prepare_sint_vecs();
- printf("prepare\n");
- on_cpus(synic_test_prepare, (void *)read_cr3());
- for (i = 0; i < ncpus; i++) {
- printf("test %d -> %d\n", i, ncpus - 1 - i);
- on_cpu_async(i, synic_test, (void *)(ulong)(ncpus - 1 - i));
- }
- while (cpus_active() > 1)
- pause();
- printf("cleanup\n");
- on_cpus(synic_test_cleanup, NULL);
- ok = true;
- for (i = 0; i < ncpus; ++i) {
- printf("isr_enter_count[%d] = %d\n",
- i, atomic_read(&isr_enter_count[i]));
- ok &= atomic_read(&isr_enter_count[i]) == 16;
- }
- report("Hyper-V SynIC test", ok);
- } else {
- printf("Hyper-V SynIC is not supported");
- }
- return report_summary();
- }
|