Ejemplo n.º 1
0
Archivo: viridian.c Proyecto: djs55/xen
int wrmsr_viridian_regs(uint32_t idx, uint64_t val)
{
    struct vcpu *v = current;
    struct domain *d = v->domain;

    if ( !is_viridian_domain(d) )
        return 0;

    switch ( idx )
    {
    case VIRIDIAN_MSR_GUEST_OS_ID:
        perfc_incr(mshv_wrmsr_osid);
        d->arch.hvm_domain.viridian.guest_os_id.raw = val;
        dump_guest_os_id(d);
        break;

    case VIRIDIAN_MSR_HYPERCALL:
        perfc_incr(mshv_wrmsr_hc_page);
        d->arch.hvm_domain.viridian.hypercall_gpa.raw = val;
        dump_hypercall(d);
        if ( d->arch.hvm_domain.viridian.hypercall_gpa.fields.enabled )
            enable_hypercall_page(d);
        break;

    case VIRIDIAN_MSR_VP_INDEX:
        perfc_incr(mshv_wrmsr_vp_index);
        break;

    case VIRIDIAN_MSR_EOI:
        perfc_incr(mshv_wrmsr_eoi);
        vlapic_EOI_set(vcpu_vlapic(v));
        break;

    case VIRIDIAN_MSR_ICR: {
        u32 eax = (u32)val, edx = (u32)(val >> 32);
        struct vlapic *vlapic = vcpu_vlapic(v);
        perfc_incr(mshv_wrmsr_icr);
        eax &= ~(1 << 12);
        edx &= 0xff000000;
        vlapic_set_reg(vlapic, APIC_ICR2, edx);
        vlapic_ipi(vlapic, eax, edx);
        vlapic_set_reg(vlapic, APIC_ICR, eax);
        break;
    }

    case VIRIDIAN_MSR_TPR:
        perfc_incr(mshv_wrmsr_tpr);
        vlapic_set_reg(vcpu_vlapic(v), APIC_TASKPRI, (uint8_t)val);
        break;

    case VIRIDIAN_MSR_APIC_ASSIST:
        perfc_incr(mshv_wrmsr_apic_msr);
        teardown_apic_assist(v); /* release any previous mapping */
        v->arch.hvm_vcpu.viridian.apic_assist.msr.raw = val;
        dump_apic_assist(v);
        if ( v->arch.hvm_vcpu.viridian.apic_assist.msr.fields.enabled )
            initialize_apic_assist(v);
        break;

    case VIRIDIAN_MSR_REFERENCE_TSC:
        if ( !(viridian_feature_mask(d) & HVMPV_reference_tsc) )
            return 0;

        perfc_incr(mshv_wrmsr_tsc_msr);
        d->arch.hvm_domain.viridian.reference_tsc.raw = val;
        dump_reference_tsc(d);
        if ( d->arch.hvm_domain.viridian.reference_tsc.fields.enabled )
            update_reference_tsc(d, 1);
        break;

    default:
        return 0;
    }

    return 1;
}
Ejemplo n.º 2
0
int wrmsr_viridian_regs(uint32_t idx, uint64_t val)
{
    struct domain *d = current->domain;

    if ( !is_viridian_domain(d) )
        return 0;

    switch ( idx )
    {
    case VIRIDIAN_MSR_GUEST_OS_ID:
        perfc_incr(mshv_wrmsr_osid);
        d->arch.hvm_domain.viridian.guest_os_id.raw = val;
        gdprintk(XENLOG_INFO, "Guest os:\n");
        gdprintk(XENLOG_INFO, "\tvendor: %x\n",
               d->arch.hvm_domain.viridian.guest_os_id.fields.vendor);
        gdprintk(XENLOG_INFO, "\tos: %x\n",
               d->arch.hvm_domain.viridian.guest_os_id.fields.os);
        gdprintk(XENLOG_INFO, "\tmajor: %x\n",
               d->arch.hvm_domain.viridian.guest_os_id.fields.major);
        gdprintk(XENLOG_INFO, "\tminor: %x\n",
               d->arch.hvm_domain.viridian.guest_os_id.fields.minor);
        gdprintk(XENLOG_INFO, "\tsp: %x\n",
               d->arch.hvm_domain.viridian.guest_os_id.fields.service_pack);
        gdprintk(XENLOG_INFO, "\tbuild: %x\n",
               d->arch.hvm_domain.viridian.guest_os_id.fields.build_number);
        break;

    case VIRIDIAN_MSR_HYPERCALL:
        perfc_incr(mshv_wrmsr_hc_page);
        gdprintk(XENLOG_INFO, "Set hypercall page %"PRIx64".\n", val);
        if ( d->arch.hvm_domain.viridian.guest_os_id.raw == 0 )
            break;
        d->arch.hvm_domain.viridian.hypercall_gpa.raw = val;
        if ( d->arch.hvm_domain.viridian.hypercall_gpa.fields.enabled )
            enable_hypercall_page();
        break;

    case VIRIDIAN_MSR_VP_INDEX:
        perfc_incr(mshv_wrmsr_vp_index);
        gdprintk(XENLOG_INFO, "Set VP index %"PRIu64".\n", val);
        break;

    case VIRIDIAN_MSR_EOI:
        perfc_incr(mshv_wrmsr_eoi);
        vlapic_EOI_set(vcpu_vlapic(current));
        break;

    case VIRIDIAN_MSR_ICR: {
        u32 eax = (u32)val, edx = (u32)(val >> 32);
        struct vlapic *vlapic = vcpu_vlapic(current);
        perfc_incr(mshv_wrmsr_icr);
        eax &= ~(1 << 12);
        edx &= 0xff000000;
        vlapic_set_reg(vlapic, APIC_ICR2, edx);
        if ( vlapic_ipi(vlapic, eax, edx) == X86EMUL_OKAY )
            vlapic_set_reg(vlapic, APIC_ICR, eax);
        break;
    }

    case VIRIDIAN_MSR_TPR:
        perfc_incr(mshv_wrmsr_tpr);
        vlapic_set_reg(vcpu_vlapic(current), APIC_TASKPRI, (uint8_t)val);
        break;

    case VIRIDIAN_MSR_APIC_ASSIST:
        /*
         * We don't support the APIC assist page, and that fact is reflected in
         * our CPUID flags. However, Windows 7 build 7000 has a bug which means
         * that it doesn't recognise that, and tries to use the page anyway. We
         * therefore have to fake up just enough to keep win7 happy.
         * Fortunately, that's really easy: just setting the first four bytes
         * in the page to zero effectively disables the page again, so that's
         * what we do. Semantically, the first four bytes are supposed to be a
         * flag saying whether the guest really needs to issue an EOI. Setting
         * that flag to zero means that it must always issue one, which is what
         * we want. Once a page has been repurposed as an APIC assist page the
         * guest isn't allowed to set anything in it, so the flag remains zero
         * and all is fine. The guest is allowed to clear flags in the page,
         * but that doesn't cause us any problems.
         */
        if ( val & 1 ) /* APIC assist page enabled? */
        {
            uint32_t word = 0;
            paddr_t page_start = val & ~1ul;
            (void)hvm_copy_to_guest_phys(page_start, &word, sizeof(word));
        }
        break;

    default:
        return 0;
    }

    return 1;
}