186 lines
3.9 KiB
C
186 lines
3.9 KiB
C
#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();
|
|
}
|