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; }
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; }