11fc33bb9SClaudio Fontana /* 21fc33bb9SClaudio Fontana * QEMU Windows Hypervisor Platform accelerator (WHPX) 31fc33bb9SClaudio Fontana * 41fc33bb9SClaudio Fontana * Copyright Microsoft Corp. 2017 51fc33bb9SClaudio Fontana * 61fc33bb9SClaudio Fontana * This work is licensed under the terms of the GNU GPL, version 2 or later. 71fc33bb9SClaudio Fontana * See the COPYING file in the top-level directory. 81fc33bb9SClaudio Fontana * 91fc33bb9SClaudio Fontana */ 101fc33bb9SClaudio Fontana 111fc33bb9SClaudio Fontana #include "qemu/osdep.h" 121fc33bb9SClaudio Fontana #include "cpu.h" 131fc33bb9SClaudio Fontana #include "exec/address-spaces.h" 141fc33bb9SClaudio Fontana #include "exec/ioport.h" 151fc33bb9SClaudio Fontana #include "qemu-common.h" 16940e43aaSClaudio Fontana #include "qemu/accel.h" 171fc33bb9SClaudio Fontana #include "sysemu/whpx.h" 181fc33bb9SClaudio Fontana #include "sysemu/cpus.h" 191fc33bb9SClaudio Fontana #include "sysemu/runstate.h" 201fc33bb9SClaudio Fontana #include "qemu/main-loop.h" 211fc33bb9SClaudio Fontana #include "hw/boards.h" 221fc33bb9SClaudio Fontana #include "hw/i386/ioapic.h" 231fc33bb9SClaudio Fontana #include "hw/i386/apic_internal.h" 241fc33bb9SClaudio Fontana #include "qemu/error-report.h" 251fc33bb9SClaudio Fontana #include "qapi/error.h" 261fc33bb9SClaudio Fontana #include "qapi/qapi-types-common.h" 271fc33bb9SClaudio Fontana #include "qapi/qapi-visit-common.h" 281fc33bb9SClaudio Fontana #include "migration/blocker.h" 291fc33bb9SClaudio Fontana #include <winerror.h> 301fc33bb9SClaudio Fontana 319102c968SPaolo Bonzini #include "whpx-internal.h" 32b86f59c7SClaudio Fontana #include "whpx-accel-ops.h" 33b86f59c7SClaudio Fontana 34b86f59c7SClaudio Fontana #include <WinHvPlatform.h> 35b86f59c7SClaudio Fontana #include <WinHvEmulation.h> 361fc33bb9SClaudio Fontana 371fc33bb9SClaudio Fontana #define HYPERV_APIC_BUS_FREQUENCY (200000000ULL) 381fc33bb9SClaudio Fontana 391fc33bb9SClaudio Fontana static const WHV_REGISTER_NAME whpx_register_names[] = { 401fc33bb9SClaudio Fontana 411fc33bb9SClaudio Fontana /* X64 General purpose registers */ 421fc33bb9SClaudio Fontana WHvX64RegisterRax, 431fc33bb9SClaudio Fontana WHvX64RegisterRcx, 441fc33bb9SClaudio Fontana WHvX64RegisterRdx, 451fc33bb9SClaudio Fontana WHvX64RegisterRbx, 461fc33bb9SClaudio Fontana WHvX64RegisterRsp, 471fc33bb9SClaudio Fontana WHvX64RegisterRbp, 481fc33bb9SClaudio Fontana WHvX64RegisterRsi, 491fc33bb9SClaudio Fontana WHvX64RegisterRdi, 501fc33bb9SClaudio Fontana WHvX64RegisterR8, 511fc33bb9SClaudio Fontana WHvX64RegisterR9, 521fc33bb9SClaudio Fontana WHvX64RegisterR10, 531fc33bb9SClaudio Fontana WHvX64RegisterR11, 541fc33bb9SClaudio Fontana WHvX64RegisterR12, 551fc33bb9SClaudio Fontana WHvX64RegisterR13, 561fc33bb9SClaudio Fontana WHvX64RegisterR14, 571fc33bb9SClaudio Fontana WHvX64RegisterR15, 581fc33bb9SClaudio Fontana WHvX64RegisterRip, 591fc33bb9SClaudio Fontana WHvX64RegisterRflags, 601fc33bb9SClaudio Fontana 611fc33bb9SClaudio Fontana /* X64 Segment registers */ 621fc33bb9SClaudio Fontana WHvX64RegisterEs, 631fc33bb9SClaudio Fontana WHvX64RegisterCs, 641fc33bb9SClaudio Fontana WHvX64RegisterSs, 651fc33bb9SClaudio Fontana WHvX64RegisterDs, 661fc33bb9SClaudio Fontana WHvX64RegisterFs, 671fc33bb9SClaudio Fontana WHvX64RegisterGs, 681fc33bb9SClaudio Fontana WHvX64RegisterLdtr, 691fc33bb9SClaudio Fontana WHvX64RegisterTr, 701fc33bb9SClaudio Fontana 711fc33bb9SClaudio Fontana /* X64 Table registers */ 721fc33bb9SClaudio Fontana WHvX64RegisterIdtr, 731fc33bb9SClaudio Fontana WHvX64RegisterGdtr, 741fc33bb9SClaudio Fontana 751fc33bb9SClaudio Fontana /* X64 Control Registers */ 761fc33bb9SClaudio Fontana WHvX64RegisterCr0, 771fc33bb9SClaudio Fontana WHvX64RegisterCr2, 781fc33bb9SClaudio Fontana WHvX64RegisterCr3, 791fc33bb9SClaudio Fontana WHvX64RegisterCr4, 801fc33bb9SClaudio Fontana WHvX64RegisterCr8, 811fc33bb9SClaudio Fontana 821fc33bb9SClaudio Fontana /* X64 Debug Registers */ 831fc33bb9SClaudio Fontana /* 841fc33bb9SClaudio Fontana * WHvX64RegisterDr0, 851fc33bb9SClaudio Fontana * WHvX64RegisterDr1, 861fc33bb9SClaudio Fontana * WHvX64RegisterDr2, 871fc33bb9SClaudio Fontana * WHvX64RegisterDr3, 881fc33bb9SClaudio Fontana * WHvX64RegisterDr6, 891fc33bb9SClaudio Fontana * WHvX64RegisterDr7, 901fc33bb9SClaudio Fontana */ 911fc33bb9SClaudio Fontana 921fc33bb9SClaudio Fontana /* X64 Floating Point and Vector Registers */ 931fc33bb9SClaudio Fontana WHvX64RegisterXmm0, 941fc33bb9SClaudio Fontana WHvX64RegisterXmm1, 951fc33bb9SClaudio Fontana WHvX64RegisterXmm2, 961fc33bb9SClaudio Fontana WHvX64RegisterXmm3, 971fc33bb9SClaudio Fontana WHvX64RegisterXmm4, 981fc33bb9SClaudio Fontana WHvX64RegisterXmm5, 991fc33bb9SClaudio Fontana WHvX64RegisterXmm6, 1001fc33bb9SClaudio Fontana WHvX64RegisterXmm7, 1011fc33bb9SClaudio Fontana WHvX64RegisterXmm8, 1021fc33bb9SClaudio Fontana WHvX64RegisterXmm9, 1031fc33bb9SClaudio Fontana WHvX64RegisterXmm10, 1041fc33bb9SClaudio Fontana WHvX64RegisterXmm11, 1051fc33bb9SClaudio Fontana WHvX64RegisterXmm12, 1061fc33bb9SClaudio Fontana WHvX64RegisterXmm13, 1071fc33bb9SClaudio Fontana WHvX64RegisterXmm14, 1081fc33bb9SClaudio Fontana WHvX64RegisterXmm15, 1091fc33bb9SClaudio Fontana WHvX64RegisterFpMmx0, 1101fc33bb9SClaudio Fontana WHvX64RegisterFpMmx1, 1111fc33bb9SClaudio Fontana WHvX64RegisterFpMmx2, 1121fc33bb9SClaudio Fontana WHvX64RegisterFpMmx3, 1131fc33bb9SClaudio Fontana WHvX64RegisterFpMmx4, 1141fc33bb9SClaudio Fontana WHvX64RegisterFpMmx5, 1151fc33bb9SClaudio Fontana WHvX64RegisterFpMmx6, 1161fc33bb9SClaudio Fontana WHvX64RegisterFpMmx7, 1171fc33bb9SClaudio Fontana WHvX64RegisterFpControlStatus, 1181fc33bb9SClaudio Fontana WHvX64RegisterXmmControlStatus, 1191fc33bb9SClaudio Fontana 1201fc33bb9SClaudio Fontana /* X64 MSRs */ 1211fc33bb9SClaudio Fontana WHvX64RegisterEfer, 1221fc33bb9SClaudio Fontana #ifdef TARGET_X86_64 1231fc33bb9SClaudio Fontana WHvX64RegisterKernelGsBase, 1241fc33bb9SClaudio Fontana #endif 1251fc33bb9SClaudio Fontana WHvX64RegisterApicBase, 1261fc33bb9SClaudio Fontana /* WHvX64RegisterPat, */ 1271fc33bb9SClaudio Fontana WHvX64RegisterSysenterCs, 1281fc33bb9SClaudio Fontana WHvX64RegisterSysenterEip, 1291fc33bb9SClaudio Fontana WHvX64RegisterSysenterEsp, 1301fc33bb9SClaudio Fontana WHvX64RegisterStar, 1311fc33bb9SClaudio Fontana #ifdef TARGET_X86_64 1321fc33bb9SClaudio Fontana WHvX64RegisterLstar, 1331fc33bb9SClaudio Fontana WHvX64RegisterCstar, 1341fc33bb9SClaudio Fontana WHvX64RegisterSfmask, 1351fc33bb9SClaudio Fontana #endif 1361fc33bb9SClaudio Fontana 1371fc33bb9SClaudio Fontana /* Interrupt / Event Registers */ 1381fc33bb9SClaudio Fontana /* 1391fc33bb9SClaudio Fontana * WHvRegisterPendingInterruption, 1401fc33bb9SClaudio Fontana * WHvRegisterInterruptState, 1411fc33bb9SClaudio Fontana * WHvRegisterPendingEvent0, 1421fc33bb9SClaudio Fontana * WHvRegisterPendingEvent1 1431fc33bb9SClaudio Fontana * WHvX64RegisterDeliverabilityNotifications, 1441fc33bb9SClaudio Fontana */ 1451fc33bb9SClaudio Fontana }; 1461fc33bb9SClaudio Fontana 1471fc33bb9SClaudio Fontana struct whpx_register_set { 1481fc33bb9SClaudio Fontana WHV_REGISTER_VALUE values[RTL_NUMBER_OF(whpx_register_names)]; 1491fc33bb9SClaudio Fontana }; 1501fc33bb9SClaudio Fontana 1511fc33bb9SClaudio Fontana struct whpx_vcpu { 1521fc33bb9SClaudio Fontana WHV_EMULATOR_HANDLE emulator; 1531fc33bb9SClaudio Fontana bool window_registered; 1541fc33bb9SClaudio Fontana bool interruptable; 1551fc33bb9SClaudio Fontana bool ready_for_pic_interrupt; 1561fc33bb9SClaudio Fontana uint64_t tpr; 1571fc33bb9SClaudio Fontana uint64_t apic_base; 1581fc33bb9SClaudio Fontana bool interruption_pending; 1591fc33bb9SClaudio Fontana 1601fc33bb9SClaudio Fontana /* Must be the last field as it may have a tail */ 1611fc33bb9SClaudio Fontana WHV_RUN_VP_EXIT_CONTEXT exit_ctx; 1621fc33bb9SClaudio Fontana }; 1631fc33bb9SClaudio Fontana 1641fc33bb9SClaudio Fontana static bool whpx_allowed; 1651fc33bb9SClaudio Fontana static bool whp_dispatch_initialized; 1661fc33bb9SClaudio Fontana static HMODULE hWinHvPlatform, hWinHvEmulation; 1671fc33bb9SClaudio Fontana static uint32_t max_vcpu_index; 1681fc33bb9SClaudio Fontana struct whpx_state whpx_global; 1691fc33bb9SClaudio Fontana struct WHPDispatch whp_dispatch; 1701fc33bb9SClaudio Fontana 1711fc33bb9SClaudio Fontana 1721fc33bb9SClaudio Fontana /* 1731fc33bb9SClaudio Fontana * VP support 1741fc33bb9SClaudio Fontana */ 1751fc33bb9SClaudio Fontana 1761fc33bb9SClaudio Fontana static struct whpx_vcpu *get_whpx_vcpu(CPUState *cpu) 1771fc33bb9SClaudio Fontana { 1781fc33bb9SClaudio Fontana return (struct whpx_vcpu *)cpu->hax_vcpu; 1791fc33bb9SClaudio Fontana } 1801fc33bb9SClaudio Fontana 1811fc33bb9SClaudio Fontana static WHV_X64_SEGMENT_REGISTER whpx_seg_q2h(const SegmentCache *qs, int v86, 1821fc33bb9SClaudio Fontana int r86) 1831fc33bb9SClaudio Fontana { 1841fc33bb9SClaudio Fontana WHV_X64_SEGMENT_REGISTER hs; 1851fc33bb9SClaudio Fontana unsigned flags = qs->flags; 1861fc33bb9SClaudio Fontana 1871fc33bb9SClaudio Fontana hs.Base = qs->base; 1881fc33bb9SClaudio Fontana hs.Limit = qs->limit; 1891fc33bb9SClaudio Fontana hs.Selector = qs->selector; 1901fc33bb9SClaudio Fontana 1911fc33bb9SClaudio Fontana if (v86) { 1921fc33bb9SClaudio Fontana hs.Attributes = 0; 1931fc33bb9SClaudio Fontana hs.SegmentType = 3; 1941fc33bb9SClaudio Fontana hs.Present = 1; 1951fc33bb9SClaudio Fontana hs.DescriptorPrivilegeLevel = 3; 1961fc33bb9SClaudio Fontana hs.NonSystemSegment = 1; 1971fc33bb9SClaudio Fontana 1981fc33bb9SClaudio Fontana } else { 1991fc33bb9SClaudio Fontana hs.Attributes = (flags >> DESC_TYPE_SHIFT); 2001fc33bb9SClaudio Fontana 2011fc33bb9SClaudio Fontana if (r86) { 2021fc33bb9SClaudio Fontana /* hs.Base &= 0xfffff; */ 2031fc33bb9SClaudio Fontana } 2041fc33bb9SClaudio Fontana } 2051fc33bb9SClaudio Fontana 2061fc33bb9SClaudio Fontana return hs; 2071fc33bb9SClaudio Fontana } 2081fc33bb9SClaudio Fontana 2091fc33bb9SClaudio Fontana static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs) 2101fc33bb9SClaudio Fontana { 2111fc33bb9SClaudio Fontana SegmentCache qs; 2121fc33bb9SClaudio Fontana 2131fc33bb9SClaudio Fontana qs.base = hs->Base; 2141fc33bb9SClaudio Fontana qs.limit = hs->Limit; 2151fc33bb9SClaudio Fontana qs.selector = hs->Selector; 2161fc33bb9SClaudio Fontana 2171fc33bb9SClaudio Fontana qs.flags = ((uint32_t)hs->Attributes) << DESC_TYPE_SHIFT; 2181fc33bb9SClaudio Fontana 2191fc33bb9SClaudio Fontana return qs; 2201fc33bb9SClaudio Fontana } 2211fc33bb9SClaudio Fontana 2221fc33bb9SClaudio Fontana static int whpx_set_tsc(CPUState *cpu) 2231fc33bb9SClaudio Fontana { 2241fc33bb9SClaudio Fontana struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); 2251fc33bb9SClaudio Fontana WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc; 2261fc33bb9SClaudio Fontana WHV_REGISTER_VALUE tsc_val; 2271fc33bb9SClaudio Fontana HRESULT hr; 2281fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 2291fc33bb9SClaudio Fontana 2301fc33bb9SClaudio Fontana /* 2311fc33bb9SClaudio Fontana * Suspend the partition prior to setting the TSC to reduce the variance 2321fc33bb9SClaudio Fontana * in TSC across vCPUs. When the first vCPU runs post suspend, the 2331fc33bb9SClaudio Fontana * partition is automatically resumed. 2341fc33bb9SClaudio Fontana */ 2351fc33bb9SClaudio Fontana if (whp_dispatch.WHvSuspendPartitionTime) { 2361fc33bb9SClaudio Fontana 2371fc33bb9SClaudio Fontana /* 2381fc33bb9SClaudio Fontana * Unable to suspend partition while setting TSC is not a fatal 2391fc33bb9SClaudio Fontana * error. It just increases the likelihood of TSC variance between 2401fc33bb9SClaudio Fontana * vCPUs and some guest OS are able to handle that just fine. 2411fc33bb9SClaudio Fontana */ 2421fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSuspendPartitionTime(whpx->partition); 2431fc33bb9SClaudio Fontana if (FAILED(hr)) { 2441fc33bb9SClaudio Fontana warn_report("WHPX: Failed to suspend partition, hr=%08lx", hr); 2451fc33bb9SClaudio Fontana } 2461fc33bb9SClaudio Fontana } 2471fc33bb9SClaudio Fontana 2481fc33bb9SClaudio Fontana tsc_val.Reg64 = env->tsc; 2491fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters( 2501fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val); 2511fc33bb9SClaudio Fontana if (FAILED(hr)) { 2521fc33bb9SClaudio Fontana error_report("WHPX: Failed to set TSC, hr=%08lx", hr); 2531fc33bb9SClaudio Fontana return -1; 2541fc33bb9SClaudio Fontana } 2551fc33bb9SClaudio Fontana 2561fc33bb9SClaudio Fontana return 0; 2571fc33bb9SClaudio Fontana } 2581fc33bb9SClaudio Fontana 2591fc33bb9SClaudio Fontana static void whpx_set_registers(CPUState *cpu, int level) 2601fc33bb9SClaudio Fontana { 2611fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 2621fc33bb9SClaudio Fontana struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); 2631fc33bb9SClaudio Fontana struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); 2641fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu); 2651fc33bb9SClaudio Fontana struct whpx_register_set vcxt; 2661fc33bb9SClaudio Fontana HRESULT hr; 2671fc33bb9SClaudio Fontana int idx; 2681fc33bb9SClaudio Fontana int idx_next; 2691fc33bb9SClaudio Fontana int i; 2701fc33bb9SClaudio Fontana int v86, r86; 2711fc33bb9SClaudio Fontana 2721fc33bb9SClaudio Fontana assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); 2731fc33bb9SClaudio Fontana 2741fc33bb9SClaudio Fontana /* 2751fc33bb9SClaudio Fontana * Following MSRs have side effects on the guest or are too heavy for 2761fc33bb9SClaudio Fontana * runtime. Limit them to full state update. 2771fc33bb9SClaudio Fontana */ 2781fc33bb9SClaudio Fontana if (level >= WHPX_SET_RESET_STATE) { 2791fc33bb9SClaudio Fontana whpx_set_tsc(cpu); 2801fc33bb9SClaudio Fontana } 2811fc33bb9SClaudio Fontana 2821fc33bb9SClaudio Fontana memset(&vcxt, 0, sizeof(struct whpx_register_set)); 2831fc33bb9SClaudio Fontana 2841fc33bb9SClaudio Fontana v86 = (env->eflags & VM_MASK); 2851fc33bb9SClaudio Fontana r86 = !(env->cr[0] & CR0_PE_MASK); 2861fc33bb9SClaudio Fontana 2871fc33bb9SClaudio Fontana vcpu->tpr = cpu_get_apic_tpr(x86_cpu->apic_state); 2881fc33bb9SClaudio Fontana vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state); 2891fc33bb9SClaudio Fontana 2901fc33bb9SClaudio Fontana idx = 0; 2911fc33bb9SClaudio Fontana 2921fc33bb9SClaudio Fontana /* Indexes for first 16 registers match between HV and QEMU definitions */ 2931fc33bb9SClaudio Fontana idx_next = 16; 2941fc33bb9SClaudio Fontana for (idx = 0; idx < CPU_NB_REGS; idx += 1) { 2951fc33bb9SClaudio Fontana vcxt.values[idx].Reg64 = (uint64_t)env->regs[idx]; 2961fc33bb9SClaudio Fontana } 2971fc33bb9SClaudio Fontana idx = idx_next; 2981fc33bb9SClaudio Fontana 2991fc33bb9SClaudio Fontana /* Same goes for RIP and RFLAGS */ 3001fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterRip); 3011fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->eip; 3021fc33bb9SClaudio Fontana 3031fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterRflags); 3041fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->eflags; 3051fc33bb9SClaudio Fontana 3061fc33bb9SClaudio Fontana /* Translate 6+4 segment registers. HV and QEMU order matches */ 3071fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterEs); 3081fc33bb9SClaudio Fontana for (i = 0; i < 6; i += 1, idx += 1) { 3091fc33bb9SClaudio Fontana vcxt.values[idx].Segment = whpx_seg_q2h(&env->segs[i], v86, r86); 3101fc33bb9SClaudio Fontana } 3111fc33bb9SClaudio Fontana 3121fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterLdtr); 3131fc33bb9SClaudio Fontana vcxt.values[idx++].Segment = whpx_seg_q2h(&env->ldt, 0, 0); 3141fc33bb9SClaudio Fontana 3151fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterTr); 3161fc33bb9SClaudio Fontana vcxt.values[idx++].Segment = whpx_seg_q2h(&env->tr, 0, 0); 3171fc33bb9SClaudio Fontana 3181fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterIdtr); 3191fc33bb9SClaudio Fontana vcxt.values[idx].Table.Base = env->idt.base; 3201fc33bb9SClaudio Fontana vcxt.values[idx].Table.Limit = env->idt.limit; 3211fc33bb9SClaudio Fontana idx += 1; 3221fc33bb9SClaudio Fontana 3231fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterGdtr); 3241fc33bb9SClaudio Fontana vcxt.values[idx].Table.Base = env->gdt.base; 3251fc33bb9SClaudio Fontana vcxt.values[idx].Table.Limit = env->gdt.limit; 3261fc33bb9SClaudio Fontana idx += 1; 3271fc33bb9SClaudio Fontana 3281fc33bb9SClaudio Fontana /* CR0, 2, 3, 4, 8 */ 3291fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr0); 3301fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->cr[0]; 3311fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr2); 3321fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->cr[2]; 3331fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr3); 3341fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->cr[3]; 3351fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr4); 3361fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->cr[4]; 3371fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr8); 3381fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = vcpu->tpr; 3391fc33bb9SClaudio Fontana 3401fc33bb9SClaudio Fontana /* 8 Debug Registers - Skipped */ 3411fc33bb9SClaudio Fontana 3421fc33bb9SClaudio Fontana /* 16 XMM registers */ 3431fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterXmm0); 3441fc33bb9SClaudio Fontana idx_next = idx + 16; 3451fc33bb9SClaudio Fontana for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) { 3461fc33bb9SClaudio Fontana vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0); 3471fc33bb9SClaudio Fontana vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1); 3481fc33bb9SClaudio Fontana } 3491fc33bb9SClaudio Fontana idx = idx_next; 3501fc33bb9SClaudio Fontana 3511fc33bb9SClaudio Fontana /* 8 FP registers */ 3521fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0); 3531fc33bb9SClaudio Fontana for (i = 0; i < 8; i += 1, idx += 1) { 3541fc33bb9SClaudio Fontana vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0); 3551fc33bb9SClaudio Fontana /* vcxt.values[idx].Fp.AsUINT128.High64 = 3561fc33bb9SClaudio Fontana env->fpregs[i].mmx.MMX_Q(1); 3571fc33bb9SClaudio Fontana */ 3581fc33bb9SClaudio Fontana } 3591fc33bb9SClaudio Fontana 3601fc33bb9SClaudio Fontana /* FP control status register */ 3611fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus); 3621fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.FpControl = env->fpuc; 3631fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.FpStatus = 3641fc33bb9SClaudio Fontana (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; 3651fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.FpTag = 0; 3661fc33bb9SClaudio Fontana for (i = 0; i < 8; ++i) { 3671fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i; 3681fc33bb9SClaudio Fontana } 3691fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.Reserved = 0; 3701fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop; 3711fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip; 3721fc33bb9SClaudio Fontana idx += 1; 3731fc33bb9SClaudio Fontana 3741fc33bb9SClaudio Fontana /* XMM control status register */ 3751fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus); 3761fc33bb9SClaudio Fontana vcxt.values[idx].XmmControlStatus.LastFpRdp = 0; 3771fc33bb9SClaudio Fontana vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr; 3781fc33bb9SClaudio Fontana vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff; 3791fc33bb9SClaudio Fontana idx += 1; 3801fc33bb9SClaudio Fontana 3811fc33bb9SClaudio Fontana /* MSRs */ 3821fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterEfer); 3831fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->efer; 3841fc33bb9SClaudio Fontana #ifdef TARGET_X86_64 3851fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase); 3861fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->kernelgsbase; 3871fc33bb9SClaudio Fontana #endif 3881fc33bb9SClaudio Fontana 3891fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterApicBase); 3901fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = vcpu->apic_base; 3911fc33bb9SClaudio Fontana 3921fc33bb9SClaudio Fontana /* WHvX64RegisterPat - Skipped */ 3931fc33bb9SClaudio Fontana 3941fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs); 3951fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->sysenter_cs; 3961fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip); 3971fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->sysenter_eip; 3981fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp); 3991fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->sysenter_esp; 4001fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterStar); 4011fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->star; 4021fc33bb9SClaudio Fontana #ifdef TARGET_X86_64 4031fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterLstar); 4041fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->lstar; 4051fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCstar); 4061fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->cstar; 4071fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSfmask); 4081fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->fmask; 4091fc33bb9SClaudio Fontana #endif 4101fc33bb9SClaudio Fontana 4111fc33bb9SClaudio Fontana /* Interrupt / Event Registers - Skipped */ 4121fc33bb9SClaudio Fontana 4131fc33bb9SClaudio Fontana assert(idx == RTL_NUMBER_OF(whpx_register_names)); 4141fc33bb9SClaudio Fontana 4151fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters( 4161fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 4171fc33bb9SClaudio Fontana whpx_register_names, 4181fc33bb9SClaudio Fontana RTL_NUMBER_OF(whpx_register_names), 4191fc33bb9SClaudio Fontana &vcxt.values[0]); 4201fc33bb9SClaudio Fontana 4211fc33bb9SClaudio Fontana if (FAILED(hr)) { 4221fc33bb9SClaudio Fontana error_report("WHPX: Failed to set virtual processor context, hr=%08lx", 4231fc33bb9SClaudio Fontana hr); 4241fc33bb9SClaudio Fontana } 4251fc33bb9SClaudio Fontana 4261fc33bb9SClaudio Fontana return; 4271fc33bb9SClaudio Fontana } 4281fc33bb9SClaudio Fontana 4291fc33bb9SClaudio Fontana static int whpx_get_tsc(CPUState *cpu) 4301fc33bb9SClaudio Fontana { 4311fc33bb9SClaudio Fontana struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); 4321fc33bb9SClaudio Fontana WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc; 4331fc33bb9SClaudio Fontana WHV_REGISTER_VALUE tsc_val; 4341fc33bb9SClaudio Fontana HRESULT hr; 4351fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 4361fc33bb9SClaudio Fontana 4371fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetVirtualProcessorRegisters( 4381fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val); 4391fc33bb9SClaudio Fontana if (FAILED(hr)) { 4401fc33bb9SClaudio Fontana error_report("WHPX: Failed to get TSC, hr=%08lx", hr); 4411fc33bb9SClaudio Fontana return -1; 4421fc33bb9SClaudio Fontana } 4431fc33bb9SClaudio Fontana 4441fc33bb9SClaudio Fontana env->tsc = tsc_val.Reg64; 4451fc33bb9SClaudio Fontana return 0; 4461fc33bb9SClaudio Fontana } 4471fc33bb9SClaudio Fontana 4481fc33bb9SClaudio Fontana static void whpx_get_registers(CPUState *cpu) 4491fc33bb9SClaudio Fontana { 4501fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 4511fc33bb9SClaudio Fontana struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); 4521fc33bb9SClaudio Fontana struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); 4531fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu); 4541fc33bb9SClaudio Fontana struct whpx_register_set vcxt; 4551fc33bb9SClaudio Fontana uint64_t tpr, apic_base; 4561fc33bb9SClaudio Fontana HRESULT hr; 4571fc33bb9SClaudio Fontana int idx; 4581fc33bb9SClaudio Fontana int idx_next; 4591fc33bb9SClaudio Fontana int i; 4601fc33bb9SClaudio Fontana 4611fc33bb9SClaudio Fontana assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu)); 4621fc33bb9SClaudio Fontana 4631fc33bb9SClaudio Fontana if (!env->tsc_valid) { 4641fc33bb9SClaudio Fontana whpx_get_tsc(cpu); 4651fc33bb9SClaudio Fontana env->tsc_valid = !runstate_is_running(); 4661fc33bb9SClaudio Fontana } 4671fc33bb9SClaudio Fontana 4681fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetVirtualProcessorRegisters( 4691fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 4701fc33bb9SClaudio Fontana whpx_register_names, 4711fc33bb9SClaudio Fontana RTL_NUMBER_OF(whpx_register_names), 4721fc33bb9SClaudio Fontana &vcxt.values[0]); 4731fc33bb9SClaudio Fontana if (FAILED(hr)) { 4741fc33bb9SClaudio Fontana error_report("WHPX: Failed to get virtual processor context, hr=%08lx", 4751fc33bb9SClaudio Fontana hr); 4761fc33bb9SClaudio Fontana } 4771fc33bb9SClaudio Fontana 4781fc33bb9SClaudio Fontana idx = 0; 4791fc33bb9SClaudio Fontana 4801fc33bb9SClaudio Fontana /* Indexes for first 16 registers match between HV and QEMU definitions */ 4811fc33bb9SClaudio Fontana idx_next = 16; 4821fc33bb9SClaudio Fontana for (idx = 0; idx < CPU_NB_REGS; idx += 1) { 4831fc33bb9SClaudio Fontana env->regs[idx] = vcxt.values[idx].Reg64; 4841fc33bb9SClaudio Fontana } 4851fc33bb9SClaudio Fontana idx = idx_next; 4861fc33bb9SClaudio Fontana 4871fc33bb9SClaudio Fontana /* Same goes for RIP and RFLAGS */ 4881fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterRip); 4891fc33bb9SClaudio Fontana env->eip = vcxt.values[idx++].Reg64; 4901fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterRflags); 4911fc33bb9SClaudio Fontana env->eflags = vcxt.values[idx++].Reg64; 4921fc33bb9SClaudio Fontana 4931fc33bb9SClaudio Fontana /* Translate 6+4 segment registers. HV and QEMU order matches */ 4941fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterEs); 4951fc33bb9SClaudio Fontana for (i = 0; i < 6; i += 1, idx += 1) { 4961fc33bb9SClaudio Fontana env->segs[i] = whpx_seg_h2q(&vcxt.values[idx].Segment); 4971fc33bb9SClaudio Fontana } 4981fc33bb9SClaudio Fontana 4991fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterLdtr); 5001fc33bb9SClaudio Fontana env->ldt = whpx_seg_h2q(&vcxt.values[idx++].Segment); 5011fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterTr); 5021fc33bb9SClaudio Fontana env->tr = whpx_seg_h2q(&vcxt.values[idx++].Segment); 5031fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterIdtr); 5041fc33bb9SClaudio Fontana env->idt.base = vcxt.values[idx].Table.Base; 5051fc33bb9SClaudio Fontana env->idt.limit = vcxt.values[idx].Table.Limit; 5061fc33bb9SClaudio Fontana idx += 1; 5071fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterGdtr); 5081fc33bb9SClaudio Fontana env->gdt.base = vcxt.values[idx].Table.Base; 5091fc33bb9SClaudio Fontana env->gdt.limit = vcxt.values[idx].Table.Limit; 5101fc33bb9SClaudio Fontana idx += 1; 5111fc33bb9SClaudio Fontana 5121fc33bb9SClaudio Fontana /* CR0, 2, 3, 4, 8 */ 5131fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr0); 5141fc33bb9SClaudio Fontana env->cr[0] = vcxt.values[idx++].Reg64; 5151fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr2); 5161fc33bb9SClaudio Fontana env->cr[2] = vcxt.values[idx++].Reg64; 5171fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr3); 5181fc33bb9SClaudio Fontana env->cr[3] = vcxt.values[idx++].Reg64; 5191fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr4); 5201fc33bb9SClaudio Fontana env->cr[4] = vcxt.values[idx++].Reg64; 5211fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr8); 5221fc33bb9SClaudio Fontana tpr = vcxt.values[idx++].Reg64; 5231fc33bb9SClaudio Fontana if (tpr != vcpu->tpr) { 5241fc33bb9SClaudio Fontana vcpu->tpr = tpr; 5251fc33bb9SClaudio Fontana cpu_set_apic_tpr(x86_cpu->apic_state, tpr); 5261fc33bb9SClaudio Fontana } 5271fc33bb9SClaudio Fontana 5281fc33bb9SClaudio Fontana /* 8 Debug Registers - Skipped */ 5291fc33bb9SClaudio Fontana 5301fc33bb9SClaudio Fontana /* 16 XMM registers */ 5311fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterXmm0); 5321fc33bb9SClaudio Fontana idx_next = idx + 16; 5331fc33bb9SClaudio Fontana for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) { 5341fc33bb9SClaudio Fontana env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64; 5351fc33bb9SClaudio Fontana env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64; 5361fc33bb9SClaudio Fontana } 5371fc33bb9SClaudio Fontana idx = idx_next; 5381fc33bb9SClaudio Fontana 5391fc33bb9SClaudio Fontana /* 8 FP registers */ 5401fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0); 5411fc33bb9SClaudio Fontana for (i = 0; i < 8; i += 1, idx += 1) { 5421fc33bb9SClaudio Fontana env->fpregs[i].mmx.MMX_Q(0) = vcxt.values[idx].Fp.AsUINT128.Low64; 5431fc33bb9SClaudio Fontana /* env->fpregs[i].mmx.MMX_Q(1) = 5441fc33bb9SClaudio Fontana vcxt.values[idx].Fp.AsUINT128.High64; 5451fc33bb9SClaudio Fontana */ 5461fc33bb9SClaudio Fontana } 5471fc33bb9SClaudio Fontana 5481fc33bb9SClaudio Fontana /* FP control status register */ 5491fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus); 5501fc33bb9SClaudio Fontana env->fpuc = vcxt.values[idx].FpControlStatus.FpControl; 5511fc33bb9SClaudio Fontana env->fpstt = (vcxt.values[idx].FpControlStatus.FpStatus >> 11) & 0x7; 5521fc33bb9SClaudio Fontana env->fpus = vcxt.values[idx].FpControlStatus.FpStatus & ~0x3800; 5531fc33bb9SClaudio Fontana for (i = 0; i < 8; ++i) { 5541fc33bb9SClaudio Fontana env->fptags[i] = !((vcxt.values[idx].FpControlStatus.FpTag >> i) & 1); 5551fc33bb9SClaudio Fontana } 5561fc33bb9SClaudio Fontana env->fpop = vcxt.values[idx].FpControlStatus.LastFpOp; 5571fc33bb9SClaudio Fontana env->fpip = vcxt.values[idx].FpControlStatus.LastFpRip; 5581fc33bb9SClaudio Fontana idx += 1; 5591fc33bb9SClaudio Fontana 5601fc33bb9SClaudio Fontana /* XMM control status register */ 5611fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus); 5621fc33bb9SClaudio Fontana env->mxcsr = vcxt.values[idx].XmmControlStatus.XmmStatusControl; 5631fc33bb9SClaudio Fontana idx += 1; 5641fc33bb9SClaudio Fontana 5651fc33bb9SClaudio Fontana /* MSRs */ 5661fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterEfer); 5671fc33bb9SClaudio Fontana env->efer = vcxt.values[idx++].Reg64; 5681fc33bb9SClaudio Fontana #ifdef TARGET_X86_64 5691fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase); 5701fc33bb9SClaudio Fontana env->kernelgsbase = vcxt.values[idx++].Reg64; 5711fc33bb9SClaudio Fontana #endif 5721fc33bb9SClaudio Fontana 5731fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterApicBase); 5741fc33bb9SClaudio Fontana apic_base = vcxt.values[idx++].Reg64; 5751fc33bb9SClaudio Fontana if (apic_base != vcpu->apic_base) { 5761fc33bb9SClaudio Fontana vcpu->apic_base = apic_base; 5771fc33bb9SClaudio Fontana cpu_set_apic_base(x86_cpu->apic_state, vcpu->apic_base); 5781fc33bb9SClaudio Fontana } 5791fc33bb9SClaudio Fontana 5801fc33bb9SClaudio Fontana /* WHvX64RegisterPat - Skipped */ 5811fc33bb9SClaudio Fontana 5821fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs); 5831fc33bb9SClaudio Fontana env->sysenter_cs = vcxt.values[idx++].Reg64; 5841fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip); 5851fc33bb9SClaudio Fontana env->sysenter_eip = vcxt.values[idx++].Reg64; 5861fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp); 5871fc33bb9SClaudio Fontana env->sysenter_esp = vcxt.values[idx++].Reg64; 5881fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterStar); 5891fc33bb9SClaudio Fontana env->star = vcxt.values[idx++].Reg64; 5901fc33bb9SClaudio Fontana #ifdef TARGET_X86_64 5911fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterLstar); 5921fc33bb9SClaudio Fontana env->lstar = vcxt.values[idx++].Reg64; 5931fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCstar); 5941fc33bb9SClaudio Fontana env->cstar = vcxt.values[idx++].Reg64; 5951fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSfmask); 5961fc33bb9SClaudio Fontana env->fmask = vcxt.values[idx++].Reg64; 5971fc33bb9SClaudio Fontana #endif 5981fc33bb9SClaudio Fontana 5991fc33bb9SClaudio Fontana /* Interrupt / Event Registers - Skipped */ 6001fc33bb9SClaudio Fontana 6011fc33bb9SClaudio Fontana assert(idx == RTL_NUMBER_OF(whpx_register_names)); 6021fc33bb9SClaudio Fontana 6031fc33bb9SClaudio Fontana if (whpx_apic_in_platform()) { 6041fc33bb9SClaudio Fontana whpx_apic_get(x86_cpu->apic_state); 6051fc33bb9SClaudio Fontana } 6061fc33bb9SClaudio Fontana 6071fc33bb9SClaudio Fontana return; 6081fc33bb9SClaudio Fontana } 6091fc33bb9SClaudio Fontana 6101fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_ioport_callback( 6111fc33bb9SClaudio Fontana void *ctx, 6121fc33bb9SClaudio Fontana WHV_EMULATOR_IO_ACCESS_INFO *IoAccess) 6131fc33bb9SClaudio Fontana { 6141fc33bb9SClaudio Fontana MemTxAttrs attrs = { 0 }; 6151fc33bb9SClaudio Fontana address_space_rw(&address_space_io, IoAccess->Port, attrs, 6161fc33bb9SClaudio Fontana &IoAccess->Data, IoAccess->AccessSize, 6171fc33bb9SClaudio Fontana IoAccess->Direction); 6181fc33bb9SClaudio Fontana return S_OK; 6191fc33bb9SClaudio Fontana } 6201fc33bb9SClaudio Fontana 6211fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_mmio_callback( 6221fc33bb9SClaudio Fontana void *ctx, 6231fc33bb9SClaudio Fontana WHV_EMULATOR_MEMORY_ACCESS_INFO *ma) 6241fc33bb9SClaudio Fontana { 6251fc33bb9SClaudio Fontana cpu_physical_memory_rw(ma->GpaAddress, ma->Data, ma->AccessSize, 6261fc33bb9SClaudio Fontana ma->Direction); 6271fc33bb9SClaudio Fontana return S_OK; 6281fc33bb9SClaudio Fontana } 6291fc33bb9SClaudio Fontana 6301fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_getreg_callback( 6311fc33bb9SClaudio Fontana void *ctx, 6321fc33bb9SClaudio Fontana const WHV_REGISTER_NAME *RegisterNames, 6331fc33bb9SClaudio Fontana UINT32 RegisterCount, 6341fc33bb9SClaudio Fontana WHV_REGISTER_VALUE *RegisterValues) 6351fc33bb9SClaudio Fontana { 6361fc33bb9SClaudio Fontana HRESULT hr; 6371fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 6381fc33bb9SClaudio Fontana CPUState *cpu = (CPUState *)ctx; 6391fc33bb9SClaudio Fontana 6401fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetVirtualProcessorRegisters( 6411fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 6421fc33bb9SClaudio Fontana RegisterNames, RegisterCount, 6431fc33bb9SClaudio Fontana RegisterValues); 6441fc33bb9SClaudio Fontana if (FAILED(hr)) { 6451fc33bb9SClaudio Fontana error_report("WHPX: Failed to get virtual processor registers," 6461fc33bb9SClaudio Fontana " hr=%08lx", hr); 6471fc33bb9SClaudio Fontana } 6481fc33bb9SClaudio Fontana 6491fc33bb9SClaudio Fontana return hr; 6501fc33bb9SClaudio Fontana } 6511fc33bb9SClaudio Fontana 6521fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_setreg_callback( 6531fc33bb9SClaudio Fontana void *ctx, 6541fc33bb9SClaudio Fontana const WHV_REGISTER_NAME *RegisterNames, 6551fc33bb9SClaudio Fontana UINT32 RegisterCount, 6561fc33bb9SClaudio Fontana const WHV_REGISTER_VALUE *RegisterValues) 6571fc33bb9SClaudio Fontana { 6581fc33bb9SClaudio Fontana HRESULT hr; 6591fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 6601fc33bb9SClaudio Fontana CPUState *cpu = (CPUState *)ctx; 6611fc33bb9SClaudio Fontana 6621fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters( 6631fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 6641fc33bb9SClaudio Fontana RegisterNames, RegisterCount, 6651fc33bb9SClaudio Fontana RegisterValues); 6661fc33bb9SClaudio Fontana if (FAILED(hr)) { 6671fc33bb9SClaudio Fontana error_report("WHPX: Failed to set virtual processor registers," 6681fc33bb9SClaudio Fontana " hr=%08lx", hr); 6691fc33bb9SClaudio Fontana } 6701fc33bb9SClaudio Fontana 6711fc33bb9SClaudio Fontana /* 6721fc33bb9SClaudio Fontana * The emulator just successfully wrote the register state. We clear the 6731fc33bb9SClaudio Fontana * dirty state so we avoid the double write on resume of the VP. 6741fc33bb9SClaudio Fontana */ 6751fc33bb9SClaudio Fontana cpu->vcpu_dirty = false; 6761fc33bb9SClaudio Fontana 6771fc33bb9SClaudio Fontana return hr; 6781fc33bb9SClaudio Fontana } 6791fc33bb9SClaudio Fontana 6801fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_translate_callback( 6811fc33bb9SClaudio Fontana void *ctx, 6821fc33bb9SClaudio Fontana WHV_GUEST_VIRTUAL_ADDRESS Gva, 6831fc33bb9SClaudio Fontana WHV_TRANSLATE_GVA_FLAGS TranslateFlags, 6841fc33bb9SClaudio Fontana WHV_TRANSLATE_GVA_RESULT_CODE *TranslationResult, 6851fc33bb9SClaudio Fontana WHV_GUEST_PHYSICAL_ADDRESS *Gpa) 6861fc33bb9SClaudio Fontana { 6871fc33bb9SClaudio Fontana HRESULT hr; 6881fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 6891fc33bb9SClaudio Fontana CPUState *cpu = (CPUState *)ctx; 6901fc33bb9SClaudio Fontana WHV_TRANSLATE_GVA_RESULT res; 6911fc33bb9SClaudio Fontana 6921fc33bb9SClaudio Fontana hr = whp_dispatch.WHvTranslateGva(whpx->partition, cpu->cpu_index, 6931fc33bb9SClaudio Fontana Gva, TranslateFlags, &res, Gpa); 6941fc33bb9SClaudio Fontana if (FAILED(hr)) { 6951fc33bb9SClaudio Fontana error_report("WHPX: Failed to translate GVA, hr=%08lx", hr); 6961fc33bb9SClaudio Fontana } else { 6971fc33bb9SClaudio Fontana *TranslationResult = res.ResultCode; 6981fc33bb9SClaudio Fontana } 6991fc33bb9SClaudio Fontana 7001fc33bb9SClaudio Fontana return hr; 7011fc33bb9SClaudio Fontana } 7021fc33bb9SClaudio Fontana 7031fc33bb9SClaudio Fontana static const WHV_EMULATOR_CALLBACKS whpx_emu_callbacks = { 7041fc33bb9SClaudio Fontana .Size = sizeof(WHV_EMULATOR_CALLBACKS), 7051fc33bb9SClaudio Fontana .WHvEmulatorIoPortCallback = whpx_emu_ioport_callback, 7061fc33bb9SClaudio Fontana .WHvEmulatorMemoryCallback = whpx_emu_mmio_callback, 7071fc33bb9SClaudio Fontana .WHvEmulatorGetVirtualProcessorRegisters = whpx_emu_getreg_callback, 7081fc33bb9SClaudio Fontana .WHvEmulatorSetVirtualProcessorRegisters = whpx_emu_setreg_callback, 7091fc33bb9SClaudio Fontana .WHvEmulatorTranslateGvaPage = whpx_emu_translate_callback, 7101fc33bb9SClaudio Fontana }; 7111fc33bb9SClaudio Fontana 7121fc33bb9SClaudio Fontana static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx) 7131fc33bb9SClaudio Fontana { 7141fc33bb9SClaudio Fontana HRESULT hr; 7151fc33bb9SClaudio Fontana struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); 7161fc33bb9SClaudio Fontana WHV_EMULATOR_STATUS emu_status; 7171fc33bb9SClaudio Fontana 7181fc33bb9SClaudio Fontana hr = whp_dispatch.WHvEmulatorTryMmioEmulation( 7191fc33bb9SClaudio Fontana vcpu->emulator, cpu, 7201fc33bb9SClaudio Fontana &vcpu->exit_ctx.VpContext, ctx, 7211fc33bb9SClaudio Fontana &emu_status); 7221fc33bb9SClaudio Fontana if (FAILED(hr)) { 7231fc33bb9SClaudio Fontana error_report("WHPX: Failed to parse MMIO access, hr=%08lx", hr); 7241fc33bb9SClaudio Fontana return -1; 7251fc33bb9SClaudio Fontana } 7261fc33bb9SClaudio Fontana 7271fc33bb9SClaudio Fontana if (!emu_status.EmulationSuccessful) { 7281fc33bb9SClaudio Fontana error_report("WHPX: Failed to emulate MMIO access with" 7291fc33bb9SClaudio Fontana " EmulatorReturnStatus: %u", emu_status.AsUINT32); 7301fc33bb9SClaudio Fontana return -1; 7311fc33bb9SClaudio Fontana } 7321fc33bb9SClaudio Fontana 7331fc33bb9SClaudio Fontana return 0; 7341fc33bb9SClaudio Fontana } 7351fc33bb9SClaudio Fontana 7361fc33bb9SClaudio Fontana static int whpx_handle_portio(CPUState *cpu, 7371fc33bb9SClaudio Fontana WHV_X64_IO_PORT_ACCESS_CONTEXT *ctx) 7381fc33bb9SClaudio Fontana { 7391fc33bb9SClaudio Fontana HRESULT hr; 7401fc33bb9SClaudio Fontana struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); 7411fc33bb9SClaudio Fontana WHV_EMULATOR_STATUS emu_status; 7421fc33bb9SClaudio Fontana 7431fc33bb9SClaudio Fontana hr = whp_dispatch.WHvEmulatorTryIoEmulation( 7441fc33bb9SClaudio Fontana vcpu->emulator, cpu, 7451fc33bb9SClaudio Fontana &vcpu->exit_ctx.VpContext, ctx, 7461fc33bb9SClaudio Fontana &emu_status); 7471fc33bb9SClaudio Fontana if (FAILED(hr)) { 7481fc33bb9SClaudio Fontana error_report("WHPX: Failed to parse PortIO access, hr=%08lx", hr); 7491fc33bb9SClaudio Fontana return -1; 7501fc33bb9SClaudio Fontana } 7511fc33bb9SClaudio Fontana 7521fc33bb9SClaudio Fontana if (!emu_status.EmulationSuccessful) { 7531fc33bb9SClaudio Fontana error_report("WHPX: Failed to emulate PortIO access with" 7541fc33bb9SClaudio Fontana " EmulatorReturnStatus: %u", emu_status.AsUINT32); 7551fc33bb9SClaudio Fontana return -1; 7561fc33bb9SClaudio Fontana } 7571fc33bb9SClaudio Fontana 7581fc33bb9SClaudio Fontana return 0; 7591fc33bb9SClaudio Fontana } 7601fc33bb9SClaudio Fontana 7611fc33bb9SClaudio Fontana static int whpx_handle_halt(CPUState *cpu) 7621fc33bb9SClaudio Fontana { 7631fc33bb9SClaudio Fontana struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); 7641fc33bb9SClaudio Fontana int ret = 0; 7651fc33bb9SClaudio Fontana 7661fc33bb9SClaudio Fontana qemu_mutex_lock_iothread(); 7671fc33bb9SClaudio Fontana if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) && 7681fc33bb9SClaudio Fontana (env->eflags & IF_MASK)) && 7691fc33bb9SClaudio Fontana !(cpu->interrupt_request & CPU_INTERRUPT_NMI)) { 7701fc33bb9SClaudio Fontana cpu->exception_index = EXCP_HLT; 7711fc33bb9SClaudio Fontana cpu->halted = true; 7721fc33bb9SClaudio Fontana ret = 1; 7731fc33bb9SClaudio Fontana } 7741fc33bb9SClaudio Fontana qemu_mutex_unlock_iothread(); 7751fc33bb9SClaudio Fontana 7761fc33bb9SClaudio Fontana return ret; 7771fc33bb9SClaudio Fontana } 7781fc33bb9SClaudio Fontana 7791fc33bb9SClaudio Fontana static void whpx_vcpu_pre_run(CPUState *cpu) 7801fc33bb9SClaudio Fontana { 7811fc33bb9SClaudio Fontana HRESULT hr; 7821fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 7831fc33bb9SClaudio Fontana struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); 7841fc33bb9SClaudio Fontana struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); 7851fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu); 7861fc33bb9SClaudio Fontana int irq; 7871fc33bb9SClaudio Fontana uint8_t tpr; 7881fc33bb9SClaudio Fontana WHV_X64_PENDING_INTERRUPTION_REGISTER new_int; 7891fc33bb9SClaudio Fontana UINT32 reg_count = 0; 7901fc33bb9SClaudio Fontana WHV_REGISTER_VALUE reg_values[3]; 7911fc33bb9SClaudio Fontana WHV_REGISTER_NAME reg_names[3]; 7921fc33bb9SClaudio Fontana 7931fc33bb9SClaudio Fontana memset(&new_int, 0, sizeof(new_int)); 7941fc33bb9SClaudio Fontana memset(reg_values, 0, sizeof(reg_values)); 7951fc33bb9SClaudio Fontana 7961fc33bb9SClaudio Fontana qemu_mutex_lock_iothread(); 7971fc33bb9SClaudio Fontana 7981fc33bb9SClaudio Fontana /* Inject NMI */ 7991fc33bb9SClaudio Fontana if (!vcpu->interruption_pending && 8001fc33bb9SClaudio Fontana cpu->interrupt_request & (CPU_INTERRUPT_NMI | CPU_INTERRUPT_SMI)) { 8011fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_NMI) { 8021fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_NMI; 8031fc33bb9SClaudio Fontana vcpu->interruptable = false; 8041fc33bb9SClaudio Fontana new_int.InterruptionType = WHvX64PendingNmi; 8051fc33bb9SClaudio Fontana new_int.InterruptionPending = 1; 8061fc33bb9SClaudio Fontana new_int.InterruptionVector = 2; 8071fc33bb9SClaudio Fontana } 8081fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_SMI) { 8091fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_SMI; 8101fc33bb9SClaudio Fontana } 8111fc33bb9SClaudio Fontana } 8121fc33bb9SClaudio Fontana 8131fc33bb9SClaudio Fontana /* 8141fc33bb9SClaudio Fontana * Force the VCPU out of its inner loop to process any INIT requests or 8151fc33bb9SClaudio Fontana * commit pending TPR access. 8161fc33bb9SClaudio Fontana */ 8171fc33bb9SClaudio Fontana if (cpu->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { 8181fc33bb9SClaudio Fontana if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) && 8191fc33bb9SClaudio Fontana !(env->hflags & HF_SMM_MASK)) { 8201fc33bb9SClaudio Fontana cpu->exit_request = 1; 8211fc33bb9SClaudio Fontana } 8221fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_TPR) { 8231fc33bb9SClaudio Fontana cpu->exit_request = 1; 8241fc33bb9SClaudio Fontana } 8251fc33bb9SClaudio Fontana } 8261fc33bb9SClaudio Fontana 8271fc33bb9SClaudio Fontana /* Get pending hard interruption or replay one that was overwritten */ 8281fc33bb9SClaudio Fontana if (!whpx_apic_in_platform()) { 8291fc33bb9SClaudio Fontana if (!vcpu->interruption_pending && 8301fc33bb9SClaudio Fontana vcpu->interruptable && (env->eflags & IF_MASK)) { 8311fc33bb9SClaudio Fontana assert(!new_int.InterruptionPending); 8321fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_HARD) { 8331fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_HARD; 8341fc33bb9SClaudio Fontana irq = cpu_get_pic_interrupt(env); 8351fc33bb9SClaudio Fontana if (irq >= 0) { 8361fc33bb9SClaudio Fontana new_int.InterruptionType = WHvX64PendingInterrupt; 8371fc33bb9SClaudio Fontana new_int.InterruptionPending = 1; 8381fc33bb9SClaudio Fontana new_int.InterruptionVector = irq; 8391fc33bb9SClaudio Fontana } 8401fc33bb9SClaudio Fontana } 8411fc33bb9SClaudio Fontana } 8421fc33bb9SClaudio Fontana 8431fc33bb9SClaudio Fontana /* Setup interrupt state if new one was prepared */ 8441fc33bb9SClaudio Fontana if (new_int.InterruptionPending) { 8451fc33bb9SClaudio Fontana reg_values[reg_count].PendingInterruption = new_int; 8461fc33bb9SClaudio Fontana reg_names[reg_count] = WHvRegisterPendingInterruption; 8471fc33bb9SClaudio Fontana reg_count += 1; 8481fc33bb9SClaudio Fontana } 8491fc33bb9SClaudio Fontana } else if (vcpu->ready_for_pic_interrupt && 8501fc33bb9SClaudio Fontana (cpu->interrupt_request & CPU_INTERRUPT_HARD)) { 8511fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_HARD; 8521fc33bb9SClaudio Fontana irq = cpu_get_pic_interrupt(env); 8531fc33bb9SClaudio Fontana if (irq >= 0) { 8541fc33bb9SClaudio Fontana reg_names[reg_count] = WHvRegisterPendingEvent; 8551fc33bb9SClaudio Fontana reg_values[reg_count].ExtIntEvent = (WHV_X64_PENDING_EXT_INT_EVENT) 8561fc33bb9SClaudio Fontana { 8571fc33bb9SClaudio Fontana .EventPending = 1, 8581fc33bb9SClaudio Fontana .EventType = WHvX64PendingEventExtInt, 8591fc33bb9SClaudio Fontana .Vector = irq, 8601fc33bb9SClaudio Fontana }; 8611fc33bb9SClaudio Fontana reg_count += 1; 8621fc33bb9SClaudio Fontana } 8631fc33bb9SClaudio Fontana } 8641fc33bb9SClaudio Fontana 8651fc33bb9SClaudio Fontana /* Sync the TPR to the CR8 if was modified during the intercept */ 8661fc33bb9SClaudio Fontana tpr = cpu_get_apic_tpr(x86_cpu->apic_state); 8671fc33bb9SClaudio Fontana if (tpr != vcpu->tpr) { 8681fc33bb9SClaudio Fontana vcpu->tpr = tpr; 8691fc33bb9SClaudio Fontana reg_values[reg_count].Reg64 = tpr; 8701fc33bb9SClaudio Fontana cpu->exit_request = 1; 8711fc33bb9SClaudio Fontana reg_names[reg_count] = WHvX64RegisterCr8; 8721fc33bb9SClaudio Fontana reg_count += 1; 8731fc33bb9SClaudio Fontana } 8741fc33bb9SClaudio Fontana 8751fc33bb9SClaudio Fontana /* Update the state of the interrupt delivery notification */ 8761fc33bb9SClaudio Fontana if (!vcpu->window_registered && 8771fc33bb9SClaudio Fontana cpu->interrupt_request & CPU_INTERRUPT_HARD) { 8781fc33bb9SClaudio Fontana reg_values[reg_count].DeliverabilityNotifications = 8791fc33bb9SClaudio Fontana (WHV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER) { 8801fc33bb9SClaudio Fontana .InterruptNotification = 1 8811fc33bb9SClaudio Fontana }; 8821fc33bb9SClaudio Fontana vcpu->window_registered = 1; 8831fc33bb9SClaudio Fontana reg_names[reg_count] = WHvX64RegisterDeliverabilityNotifications; 8841fc33bb9SClaudio Fontana reg_count += 1; 8851fc33bb9SClaudio Fontana } 8861fc33bb9SClaudio Fontana 8871fc33bb9SClaudio Fontana qemu_mutex_unlock_iothread(); 8881fc33bb9SClaudio Fontana vcpu->ready_for_pic_interrupt = false; 8891fc33bb9SClaudio Fontana 8901fc33bb9SClaudio Fontana if (reg_count) { 8911fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters( 8921fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 8931fc33bb9SClaudio Fontana reg_names, reg_count, reg_values); 8941fc33bb9SClaudio Fontana if (FAILED(hr)) { 8951fc33bb9SClaudio Fontana error_report("WHPX: Failed to set interrupt state registers," 8961fc33bb9SClaudio Fontana " hr=%08lx", hr); 8971fc33bb9SClaudio Fontana } 8981fc33bb9SClaudio Fontana } 8991fc33bb9SClaudio Fontana 9001fc33bb9SClaudio Fontana return; 9011fc33bb9SClaudio Fontana } 9021fc33bb9SClaudio Fontana 9031fc33bb9SClaudio Fontana static void whpx_vcpu_post_run(CPUState *cpu) 9041fc33bb9SClaudio Fontana { 9051fc33bb9SClaudio Fontana struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); 9061fc33bb9SClaudio Fontana struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); 9071fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu); 9081fc33bb9SClaudio Fontana 9091fc33bb9SClaudio Fontana env->eflags = vcpu->exit_ctx.VpContext.Rflags; 9101fc33bb9SClaudio Fontana 9111fc33bb9SClaudio Fontana uint64_t tpr = vcpu->exit_ctx.VpContext.Cr8; 9121fc33bb9SClaudio Fontana if (vcpu->tpr != tpr) { 9131fc33bb9SClaudio Fontana vcpu->tpr = tpr; 9141fc33bb9SClaudio Fontana qemu_mutex_lock_iothread(); 9151fc33bb9SClaudio Fontana cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr); 9161fc33bb9SClaudio Fontana qemu_mutex_unlock_iothread(); 9171fc33bb9SClaudio Fontana } 9181fc33bb9SClaudio Fontana 9191fc33bb9SClaudio Fontana vcpu->interruption_pending = 9201fc33bb9SClaudio Fontana vcpu->exit_ctx.VpContext.ExecutionState.InterruptionPending; 9211fc33bb9SClaudio Fontana 9221fc33bb9SClaudio Fontana vcpu->interruptable = 9231fc33bb9SClaudio Fontana !vcpu->exit_ctx.VpContext.ExecutionState.InterruptShadow; 9241fc33bb9SClaudio Fontana 9251fc33bb9SClaudio Fontana return; 9261fc33bb9SClaudio Fontana } 9271fc33bb9SClaudio Fontana 9281fc33bb9SClaudio Fontana static void whpx_vcpu_process_async_events(CPUState *cpu) 9291fc33bb9SClaudio Fontana { 9301fc33bb9SClaudio Fontana struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); 9311fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu); 9321fc33bb9SClaudio Fontana struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); 9331fc33bb9SClaudio Fontana 9341fc33bb9SClaudio Fontana if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) && 9351fc33bb9SClaudio Fontana !(env->hflags & HF_SMM_MASK)) { 9361fc33bb9SClaudio Fontana whpx_cpu_synchronize_state(cpu); 9371fc33bb9SClaudio Fontana do_cpu_init(x86_cpu); 9381fc33bb9SClaudio Fontana vcpu->interruptable = true; 9391fc33bb9SClaudio Fontana } 9401fc33bb9SClaudio Fontana 9411fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_POLL) { 9421fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_POLL; 9431fc33bb9SClaudio Fontana apic_poll_irq(x86_cpu->apic_state); 9441fc33bb9SClaudio Fontana } 9451fc33bb9SClaudio Fontana 9461fc33bb9SClaudio Fontana if (((cpu->interrupt_request & CPU_INTERRUPT_HARD) && 9471fc33bb9SClaudio Fontana (env->eflags & IF_MASK)) || 9481fc33bb9SClaudio Fontana (cpu->interrupt_request & CPU_INTERRUPT_NMI)) { 9491fc33bb9SClaudio Fontana cpu->halted = false; 9501fc33bb9SClaudio Fontana } 9511fc33bb9SClaudio Fontana 9521fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) { 9531fc33bb9SClaudio Fontana whpx_cpu_synchronize_state(cpu); 9541fc33bb9SClaudio Fontana do_cpu_sipi(x86_cpu); 9551fc33bb9SClaudio Fontana } 9561fc33bb9SClaudio Fontana 9571fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_TPR) { 9581fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_TPR; 9591fc33bb9SClaudio Fontana whpx_cpu_synchronize_state(cpu); 9601fc33bb9SClaudio Fontana apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip, 9611fc33bb9SClaudio Fontana env->tpr_access_type); 9621fc33bb9SClaudio Fontana } 9631fc33bb9SClaudio Fontana 9641fc33bb9SClaudio Fontana return; 9651fc33bb9SClaudio Fontana } 9661fc33bb9SClaudio Fontana 9671fc33bb9SClaudio Fontana static int whpx_vcpu_run(CPUState *cpu) 9681fc33bb9SClaudio Fontana { 9691fc33bb9SClaudio Fontana HRESULT hr; 9701fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 9711fc33bb9SClaudio Fontana struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); 9721fc33bb9SClaudio Fontana int ret; 9731fc33bb9SClaudio Fontana 9741fc33bb9SClaudio Fontana whpx_vcpu_process_async_events(cpu); 9751fc33bb9SClaudio Fontana if (cpu->halted && !whpx_apic_in_platform()) { 9761fc33bb9SClaudio Fontana cpu->exception_index = EXCP_HLT; 9771fc33bb9SClaudio Fontana qatomic_set(&cpu->exit_request, false); 9781fc33bb9SClaudio Fontana return 0; 9791fc33bb9SClaudio Fontana } 9801fc33bb9SClaudio Fontana 9811fc33bb9SClaudio Fontana qemu_mutex_unlock_iothread(); 9821fc33bb9SClaudio Fontana cpu_exec_start(cpu); 9831fc33bb9SClaudio Fontana 9841fc33bb9SClaudio Fontana do { 9851fc33bb9SClaudio Fontana if (cpu->vcpu_dirty) { 9861fc33bb9SClaudio Fontana whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE); 9871fc33bb9SClaudio Fontana cpu->vcpu_dirty = false; 9881fc33bb9SClaudio Fontana } 9891fc33bb9SClaudio Fontana 9901fc33bb9SClaudio Fontana whpx_vcpu_pre_run(cpu); 9911fc33bb9SClaudio Fontana 9921fc33bb9SClaudio Fontana if (qatomic_read(&cpu->exit_request)) { 9931fc33bb9SClaudio Fontana whpx_vcpu_kick(cpu); 9941fc33bb9SClaudio Fontana } 9951fc33bb9SClaudio Fontana 9961fc33bb9SClaudio Fontana hr = whp_dispatch.WHvRunVirtualProcessor( 9971fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 9981fc33bb9SClaudio Fontana &vcpu->exit_ctx, sizeof(vcpu->exit_ctx)); 9991fc33bb9SClaudio Fontana 10001fc33bb9SClaudio Fontana if (FAILED(hr)) { 10011fc33bb9SClaudio Fontana error_report("WHPX: Failed to exec a virtual processor," 10021fc33bb9SClaudio Fontana " hr=%08lx", hr); 10031fc33bb9SClaudio Fontana ret = -1; 10041fc33bb9SClaudio Fontana break; 10051fc33bb9SClaudio Fontana } 10061fc33bb9SClaudio Fontana 10071fc33bb9SClaudio Fontana whpx_vcpu_post_run(cpu); 10081fc33bb9SClaudio Fontana 10091fc33bb9SClaudio Fontana switch (vcpu->exit_ctx.ExitReason) { 10101fc33bb9SClaudio Fontana case WHvRunVpExitReasonMemoryAccess: 10111fc33bb9SClaudio Fontana ret = whpx_handle_mmio(cpu, &vcpu->exit_ctx.MemoryAccess); 10121fc33bb9SClaudio Fontana break; 10131fc33bb9SClaudio Fontana 10141fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64IoPortAccess: 10151fc33bb9SClaudio Fontana ret = whpx_handle_portio(cpu, &vcpu->exit_ctx.IoPortAccess); 10161fc33bb9SClaudio Fontana break; 10171fc33bb9SClaudio Fontana 10181fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64InterruptWindow: 10191fc33bb9SClaudio Fontana vcpu->ready_for_pic_interrupt = 1; 10201fc33bb9SClaudio Fontana vcpu->window_registered = 0; 10211fc33bb9SClaudio Fontana ret = 0; 10221fc33bb9SClaudio Fontana break; 10231fc33bb9SClaudio Fontana 10241fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64ApicEoi: 10251fc33bb9SClaudio Fontana assert(whpx_apic_in_platform()); 10261fc33bb9SClaudio Fontana ioapic_eoi_broadcast(vcpu->exit_ctx.ApicEoi.InterruptVector); 10271fc33bb9SClaudio Fontana break; 10281fc33bb9SClaudio Fontana 10291fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64Halt: 10301fc33bb9SClaudio Fontana ret = whpx_handle_halt(cpu); 10311fc33bb9SClaudio Fontana break; 10321fc33bb9SClaudio Fontana 10331fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64ApicInitSipiTrap: { 10341fc33bb9SClaudio Fontana WHV_INTERRUPT_CONTROL ipi = {0}; 10351fc33bb9SClaudio Fontana uint64_t icr = vcpu->exit_ctx.ApicInitSipi.ApicIcr; 10361fc33bb9SClaudio Fontana uint32_t delivery_mode = 10371fc33bb9SClaudio Fontana (icr & APIC_ICR_DELIV_MOD) >> APIC_ICR_DELIV_MOD_SHIFT; 10381fc33bb9SClaudio Fontana int dest_shorthand = 10391fc33bb9SClaudio Fontana (icr & APIC_ICR_DEST_SHORT) >> APIC_ICR_DEST_SHORT_SHIFT; 10401fc33bb9SClaudio Fontana bool broadcast = false; 10411fc33bb9SClaudio Fontana bool include_self = false; 10421fc33bb9SClaudio Fontana uint32_t i; 10431fc33bb9SClaudio Fontana 10441fc33bb9SClaudio Fontana /* We only registered for INIT and SIPI exits. */ 10451fc33bb9SClaudio Fontana if ((delivery_mode != APIC_DM_INIT) && 10461fc33bb9SClaudio Fontana (delivery_mode != APIC_DM_SIPI)) { 10471fc33bb9SClaudio Fontana error_report( 10481fc33bb9SClaudio Fontana "WHPX: Unexpected APIC exit that is not a INIT or SIPI"); 10491fc33bb9SClaudio Fontana break; 10501fc33bb9SClaudio Fontana } 10511fc33bb9SClaudio Fontana 10521fc33bb9SClaudio Fontana if (delivery_mode == APIC_DM_INIT) { 10531fc33bb9SClaudio Fontana ipi.Type = WHvX64InterruptTypeInit; 10541fc33bb9SClaudio Fontana } else { 10551fc33bb9SClaudio Fontana ipi.Type = WHvX64InterruptTypeSipi; 10561fc33bb9SClaudio Fontana } 10571fc33bb9SClaudio Fontana 10581fc33bb9SClaudio Fontana ipi.DestinationMode = 10591fc33bb9SClaudio Fontana ((icr & APIC_ICR_DEST_MOD) >> APIC_ICR_DEST_MOD_SHIFT) ? 10601fc33bb9SClaudio Fontana WHvX64InterruptDestinationModeLogical : 10611fc33bb9SClaudio Fontana WHvX64InterruptDestinationModePhysical; 10621fc33bb9SClaudio Fontana 10631fc33bb9SClaudio Fontana ipi.TriggerMode = 10641fc33bb9SClaudio Fontana ((icr & APIC_ICR_TRIGGER_MOD) >> APIC_ICR_TRIGGER_MOD_SHIFT) ? 10651fc33bb9SClaudio Fontana WHvX64InterruptTriggerModeLevel : 10661fc33bb9SClaudio Fontana WHvX64InterruptTriggerModeEdge; 10671fc33bb9SClaudio Fontana 10681fc33bb9SClaudio Fontana ipi.Vector = icr & APIC_VECTOR_MASK; 10691fc33bb9SClaudio Fontana switch (dest_shorthand) { 10701fc33bb9SClaudio Fontana /* no shorthand. Bits 56-63 contain the destination. */ 10711fc33bb9SClaudio Fontana case 0: 10721fc33bb9SClaudio Fontana ipi.Destination = (icr >> 56) & APIC_VECTOR_MASK; 10731fc33bb9SClaudio Fontana hr = whp_dispatch.WHvRequestInterrupt(whpx->partition, 10741fc33bb9SClaudio Fontana &ipi, sizeof(ipi)); 10751fc33bb9SClaudio Fontana if (FAILED(hr)) { 10761fc33bb9SClaudio Fontana error_report("WHPX: Failed to request interrupt hr=%08lx", 10771fc33bb9SClaudio Fontana hr); 10781fc33bb9SClaudio Fontana } 10791fc33bb9SClaudio Fontana 10801fc33bb9SClaudio Fontana break; 10811fc33bb9SClaudio Fontana 10821fc33bb9SClaudio Fontana /* self */ 10831fc33bb9SClaudio Fontana case 1: 10841fc33bb9SClaudio Fontana include_self = true; 10851fc33bb9SClaudio Fontana break; 10861fc33bb9SClaudio Fontana 10871fc33bb9SClaudio Fontana /* broadcast, including self */ 10881fc33bb9SClaudio Fontana case 2: 10891fc33bb9SClaudio Fontana broadcast = true; 10901fc33bb9SClaudio Fontana include_self = true; 10911fc33bb9SClaudio Fontana break; 10921fc33bb9SClaudio Fontana 10931fc33bb9SClaudio Fontana /* broadcast, excluding self */ 10941fc33bb9SClaudio Fontana case 3: 10951fc33bb9SClaudio Fontana broadcast = true; 10961fc33bb9SClaudio Fontana break; 10971fc33bb9SClaudio Fontana } 10981fc33bb9SClaudio Fontana 10991fc33bb9SClaudio Fontana if (!broadcast && !include_self) { 11001fc33bb9SClaudio Fontana break; 11011fc33bb9SClaudio Fontana } 11021fc33bb9SClaudio Fontana 11031fc33bb9SClaudio Fontana for (i = 0; i <= max_vcpu_index; i++) { 11041fc33bb9SClaudio Fontana if (i == cpu->cpu_index && !include_self) { 11051fc33bb9SClaudio Fontana continue; 11061fc33bb9SClaudio Fontana } 11071fc33bb9SClaudio Fontana 11081fc33bb9SClaudio Fontana /* 11091fc33bb9SClaudio Fontana * Assuming that APIC Ids are identity mapped since 11101fc33bb9SClaudio Fontana * WHvX64RegisterApicId & WHvX64RegisterInitialApicId registers 11111fc33bb9SClaudio Fontana * are not handled yet and the hypervisor doesn't allow the 11121fc33bb9SClaudio Fontana * guest to modify the APIC ID. 11131fc33bb9SClaudio Fontana */ 11141fc33bb9SClaudio Fontana ipi.Destination = i; 11151fc33bb9SClaudio Fontana hr = whp_dispatch.WHvRequestInterrupt(whpx->partition, 11161fc33bb9SClaudio Fontana &ipi, sizeof(ipi)); 11171fc33bb9SClaudio Fontana if (FAILED(hr)) { 11181fc33bb9SClaudio Fontana error_report( 11191fc33bb9SClaudio Fontana "WHPX: Failed to request SIPI for %d, hr=%08lx", 11201fc33bb9SClaudio Fontana i, hr); 11211fc33bb9SClaudio Fontana } 11221fc33bb9SClaudio Fontana } 11231fc33bb9SClaudio Fontana 11241fc33bb9SClaudio Fontana break; 11251fc33bb9SClaudio Fontana } 11261fc33bb9SClaudio Fontana 11271fc33bb9SClaudio Fontana case WHvRunVpExitReasonCanceled: 11281fc33bb9SClaudio Fontana cpu->exception_index = EXCP_INTERRUPT; 11291fc33bb9SClaudio Fontana ret = 1; 11301fc33bb9SClaudio Fontana break; 11311fc33bb9SClaudio Fontana 11321fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64MsrAccess: { 11331fc33bb9SClaudio Fontana WHV_REGISTER_VALUE reg_values[3] = {0}; 11341fc33bb9SClaudio Fontana WHV_REGISTER_NAME reg_names[3]; 11351fc33bb9SClaudio Fontana UINT32 reg_count; 11361fc33bb9SClaudio Fontana 11371fc33bb9SClaudio Fontana reg_names[0] = WHvX64RegisterRip; 11381fc33bb9SClaudio Fontana reg_names[1] = WHvX64RegisterRax; 11391fc33bb9SClaudio Fontana reg_names[2] = WHvX64RegisterRdx; 11401fc33bb9SClaudio Fontana 11411fc33bb9SClaudio Fontana reg_values[0].Reg64 = 11421fc33bb9SClaudio Fontana vcpu->exit_ctx.VpContext.Rip + 11431fc33bb9SClaudio Fontana vcpu->exit_ctx.VpContext.InstructionLength; 11441fc33bb9SClaudio Fontana 11451fc33bb9SClaudio Fontana /* 11461fc33bb9SClaudio Fontana * For all unsupported MSR access we: 11471fc33bb9SClaudio Fontana * ignore writes 11481fc33bb9SClaudio Fontana * return 0 on read. 11491fc33bb9SClaudio Fontana */ 11501fc33bb9SClaudio Fontana reg_count = vcpu->exit_ctx.MsrAccess.AccessInfo.IsWrite ? 11511fc33bb9SClaudio Fontana 1 : 3; 11521fc33bb9SClaudio Fontana 11531fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters( 11541fc33bb9SClaudio Fontana whpx->partition, 11551fc33bb9SClaudio Fontana cpu->cpu_index, 11561fc33bb9SClaudio Fontana reg_names, reg_count, 11571fc33bb9SClaudio Fontana reg_values); 11581fc33bb9SClaudio Fontana 11591fc33bb9SClaudio Fontana if (FAILED(hr)) { 11601fc33bb9SClaudio Fontana error_report("WHPX: Failed to set MsrAccess state " 11611fc33bb9SClaudio Fontana " registers, hr=%08lx", hr); 11621fc33bb9SClaudio Fontana } 11631fc33bb9SClaudio Fontana ret = 0; 11641fc33bb9SClaudio Fontana break; 11651fc33bb9SClaudio Fontana } 11661fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64Cpuid: { 11671fc33bb9SClaudio Fontana WHV_REGISTER_VALUE reg_values[5]; 11681fc33bb9SClaudio Fontana WHV_REGISTER_NAME reg_names[5]; 11691fc33bb9SClaudio Fontana UINT32 reg_count = 5; 11701fc33bb9SClaudio Fontana UINT64 cpuid_fn, rip = 0, rax = 0, rcx = 0, rdx = 0, rbx = 0; 11711fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu); 11721fc33bb9SClaudio Fontana CPUX86State *env = &x86_cpu->env; 11731fc33bb9SClaudio Fontana 11741fc33bb9SClaudio Fontana memset(reg_values, 0, sizeof(reg_values)); 11751fc33bb9SClaudio Fontana 11761fc33bb9SClaudio Fontana rip = vcpu->exit_ctx.VpContext.Rip + 11771fc33bb9SClaudio Fontana vcpu->exit_ctx.VpContext.InstructionLength; 11781fc33bb9SClaudio Fontana cpuid_fn = vcpu->exit_ctx.CpuidAccess.Rax; 11791fc33bb9SClaudio Fontana 11801fc33bb9SClaudio Fontana /* 11811fc33bb9SClaudio Fontana * Ideally, these should be supplied to the hypervisor during VCPU 11821fc33bb9SClaudio Fontana * initialization and it should be able to satisfy this request. 11831fc33bb9SClaudio Fontana * But, currently, WHPX doesn't support setting CPUID values in the 11841fc33bb9SClaudio Fontana * hypervisor once the partition has been setup, which is too late 11851fc33bb9SClaudio Fontana * since VCPUs are realized later. For now, use the values from 11861fc33bb9SClaudio Fontana * QEMU to satisfy these requests, until WHPX adds support for 11871fc33bb9SClaudio Fontana * being able to set these values in the hypervisor at runtime. 11881fc33bb9SClaudio Fontana */ 11891fc33bb9SClaudio Fontana cpu_x86_cpuid(env, cpuid_fn, 0, (UINT32 *)&rax, (UINT32 *)&rbx, 11901fc33bb9SClaudio Fontana (UINT32 *)&rcx, (UINT32 *)&rdx); 11911fc33bb9SClaudio Fontana switch (cpuid_fn) { 11921fc33bb9SClaudio Fontana case 0x40000000: 11931fc33bb9SClaudio Fontana /* Expose the vmware cpu frequency cpuid leaf */ 11941fc33bb9SClaudio Fontana rax = 0x40000010; 11951fc33bb9SClaudio Fontana rbx = rcx = rdx = 0; 11961fc33bb9SClaudio Fontana break; 11971fc33bb9SClaudio Fontana 11981fc33bb9SClaudio Fontana case 0x40000010: 11991fc33bb9SClaudio Fontana rax = env->tsc_khz; 12001fc33bb9SClaudio Fontana rbx = env->apic_bus_freq / 1000; /* Hz to KHz */ 12011fc33bb9SClaudio Fontana rcx = rdx = 0; 12021fc33bb9SClaudio Fontana break; 12031fc33bb9SClaudio Fontana 12041fc33bb9SClaudio Fontana case 0x80000001: 12051fc33bb9SClaudio Fontana /* Remove any support of OSVW */ 12061fc33bb9SClaudio Fontana rcx &= ~CPUID_EXT3_OSVW; 12071fc33bb9SClaudio Fontana break; 12081fc33bb9SClaudio Fontana } 12091fc33bb9SClaudio Fontana 12101fc33bb9SClaudio Fontana reg_names[0] = WHvX64RegisterRip; 12111fc33bb9SClaudio Fontana reg_names[1] = WHvX64RegisterRax; 12121fc33bb9SClaudio Fontana reg_names[2] = WHvX64RegisterRcx; 12131fc33bb9SClaudio Fontana reg_names[3] = WHvX64RegisterRdx; 12141fc33bb9SClaudio Fontana reg_names[4] = WHvX64RegisterRbx; 12151fc33bb9SClaudio Fontana 12161fc33bb9SClaudio Fontana reg_values[0].Reg64 = rip; 12171fc33bb9SClaudio Fontana reg_values[1].Reg64 = rax; 12181fc33bb9SClaudio Fontana reg_values[2].Reg64 = rcx; 12191fc33bb9SClaudio Fontana reg_values[3].Reg64 = rdx; 12201fc33bb9SClaudio Fontana reg_values[4].Reg64 = rbx; 12211fc33bb9SClaudio Fontana 12221fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters( 12231fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 12241fc33bb9SClaudio Fontana reg_names, 12251fc33bb9SClaudio Fontana reg_count, 12261fc33bb9SClaudio Fontana reg_values); 12271fc33bb9SClaudio Fontana 12281fc33bb9SClaudio Fontana if (FAILED(hr)) { 12291fc33bb9SClaudio Fontana error_report("WHPX: Failed to set CpuidAccess state registers," 12301fc33bb9SClaudio Fontana " hr=%08lx", hr); 12311fc33bb9SClaudio Fontana } 12321fc33bb9SClaudio Fontana ret = 0; 12331fc33bb9SClaudio Fontana break; 12341fc33bb9SClaudio Fontana } 12351fc33bb9SClaudio Fontana case WHvRunVpExitReasonNone: 12361fc33bb9SClaudio Fontana case WHvRunVpExitReasonUnrecoverableException: 12371fc33bb9SClaudio Fontana case WHvRunVpExitReasonInvalidVpRegisterValue: 12381fc33bb9SClaudio Fontana case WHvRunVpExitReasonUnsupportedFeature: 12391fc33bb9SClaudio Fontana case WHvRunVpExitReasonException: 12401fc33bb9SClaudio Fontana default: 12411fc33bb9SClaudio Fontana error_report("WHPX: Unexpected VP exit code %d", 12421fc33bb9SClaudio Fontana vcpu->exit_ctx.ExitReason); 12431fc33bb9SClaudio Fontana whpx_get_registers(cpu); 12441fc33bb9SClaudio Fontana qemu_mutex_lock_iothread(); 12451fc33bb9SClaudio Fontana qemu_system_guest_panicked(cpu_get_crash_info(cpu)); 12461fc33bb9SClaudio Fontana qemu_mutex_unlock_iothread(); 12471fc33bb9SClaudio Fontana break; 12481fc33bb9SClaudio Fontana } 12491fc33bb9SClaudio Fontana 12501fc33bb9SClaudio Fontana } while (!ret); 12511fc33bb9SClaudio Fontana 12521fc33bb9SClaudio Fontana cpu_exec_end(cpu); 12531fc33bb9SClaudio Fontana qemu_mutex_lock_iothread(); 12541fc33bb9SClaudio Fontana current_cpu = cpu; 12551fc33bb9SClaudio Fontana 12561fc33bb9SClaudio Fontana qatomic_set(&cpu->exit_request, false); 12571fc33bb9SClaudio Fontana 12581fc33bb9SClaudio Fontana return ret < 0; 12591fc33bb9SClaudio Fontana } 12601fc33bb9SClaudio Fontana 12611fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) 12621fc33bb9SClaudio Fontana { 12631fc33bb9SClaudio Fontana if (!cpu->vcpu_dirty) { 12641fc33bb9SClaudio Fontana whpx_get_registers(cpu); 12651fc33bb9SClaudio Fontana cpu->vcpu_dirty = true; 12661fc33bb9SClaudio Fontana } 12671fc33bb9SClaudio Fontana } 12681fc33bb9SClaudio Fontana 12691fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu, 12701fc33bb9SClaudio Fontana run_on_cpu_data arg) 12711fc33bb9SClaudio Fontana { 12721fc33bb9SClaudio Fontana whpx_set_registers(cpu, WHPX_SET_RESET_STATE); 12731fc33bb9SClaudio Fontana cpu->vcpu_dirty = false; 12741fc33bb9SClaudio Fontana } 12751fc33bb9SClaudio Fontana 12761fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_post_init(CPUState *cpu, 12771fc33bb9SClaudio Fontana run_on_cpu_data arg) 12781fc33bb9SClaudio Fontana { 12791fc33bb9SClaudio Fontana whpx_set_registers(cpu, WHPX_SET_FULL_STATE); 12801fc33bb9SClaudio Fontana cpu->vcpu_dirty = false; 12811fc33bb9SClaudio Fontana } 12821fc33bb9SClaudio Fontana 12831fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu, 12841fc33bb9SClaudio Fontana run_on_cpu_data arg) 12851fc33bb9SClaudio Fontana { 12861fc33bb9SClaudio Fontana cpu->vcpu_dirty = true; 12871fc33bb9SClaudio Fontana } 12881fc33bb9SClaudio Fontana 12891fc33bb9SClaudio Fontana /* 12901fc33bb9SClaudio Fontana * CPU support. 12911fc33bb9SClaudio Fontana */ 12921fc33bb9SClaudio Fontana 12931fc33bb9SClaudio Fontana void whpx_cpu_synchronize_state(CPUState *cpu) 12941fc33bb9SClaudio Fontana { 12951fc33bb9SClaudio Fontana if (!cpu->vcpu_dirty) { 12961fc33bb9SClaudio Fontana run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL); 12971fc33bb9SClaudio Fontana } 12981fc33bb9SClaudio Fontana } 12991fc33bb9SClaudio Fontana 13001fc33bb9SClaudio Fontana void whpx_cpu_synchronize_post_reset(CPUState *cpu) 13011fc33bb9SClaudio Fontana { 13021fc33bb9SClaudio Fontana run_on_cpu(cpu, do_whpx_cpu_synchronize_post_reset, RUN_ON_CPU_NULL); 13031fc33bb9SClaudio Fontana } 13041fc33bb9SClaudio Fontana 13051fc33bb9SClaudio Fontana void whpx_cpu_synchronize_post_init(CPUState *cpu) 13061fc33bb9SClaudio Fontana { 13071fc33bb9SClaudio Fontana run_on_cpu(cpu, do_whpx_cpu_synchronize_post_init, RUN_ON_CPU_NULL); 13081fc33bb9SClaudio Fontana } 13091fc33bb9SClaudio Fontana 13101fc33bb9SClaudio Fontana void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu) 13111fc33bb9SClaudio Fontana { 13121fc33bb9SClaudio Fontana run_on_cpu(cpu, do_whpx_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL); 13131fc33bb9SClaudio Fontana } 13141fc33bb9SClaudio Fontana 13151fc33bb9SClaudio Fontana /* 13161fc33bb9SClaudio Fontana * Vcpu support. 13171fc33bb9SClaudio Fontana */ 13181fc33bb9SClaudio Fontana 13191fc33bb9SClaudio Fontana static Error *whpx_migration_blocker; 13201fc33bb9SClaudio Fontana 1321538f0497SPhilippe Mathieu-Daudé static void whpx_cpu_update_state(void *opaque, bool running, RunState state) 13221fc33bb9SClaudio Fontana { 13231fc33bb9SClaudio Fontana CPUX86State *env = opaque; 13241fc33bb9SClaudio Fontana 13251fc33bb9SClaudio Fontana if (running) { 13261fc33bb9SClaudio Fontana env->tsc_valid = false; 13271fc33bb9SClaudio Fontana } 13281fc33bb9SClaudio Fontana } 13291fc33bb9SClaudio Fontana 13301fc33bb9SClaudio Fontana int whpx_init_vcpu(CPUState *cpu) 13311fc33bb9SClaudio Fontana { 13321fc33bb9SClaudio Fontana HRESULT hr; 13331fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 13341fc33bb9SClaudio Fontana struct whpx_vcpu *vcpu = NULL; 13351fc33bb9SClaudio Fontana Error *local_error = NULL; 13361fc33bb9SClaudio Fontana struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr); 13371fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu); 13381fc33bb9SClaudio Fontana UINT64 freq = 0; 13391fc33bb9SClaudio Fontana int ret; 13401fc33bb9SClaudio Fontana 13411fc33bb9SClaudio Fontana /* Add migration blockers for all unsupported features of the 13421fc33bb9SClaudio Fontana * Windows Hypervisor Platform 13431fc33bb9SClaudio Fontana */ 13441fc33bb9SClaudio Fontana if (whpx_migration_blocker == NULL) { 13451fc33bb9SClaudio Fontana error_setg(&whpx_migration_blocker, 13461fc33bb9SClaudio Fontana "State blocked due to non-migratable CPUID feature support," 13471fc33bb9SClaudio Fontana "dirty memory tracking support, and XSAVE/XRSTOR support"); 13481fc33bb9SClaudio Fontana 1349436c831aSMarkus Armbruster if (migrate_add_blocker(whpx_migration_blocker, &local_error) < 0) { 13501fc33bb9SClaudio Fontana error_report_err(local_error); 13511fc33bb9SClaudio Fontana error_free(whpx_migration_blocker); 13521fc33bb9SClaudio Fontana ret = -EINVAL; 13531fc33bb9SClaudio Fontana goto error; 13541fc33bb9SClaudio Fontana } 13551fc33bb9SClaudio Fontana } 13561fc33bb9SClaudio Fontana 13571fc33bb9SClaudio Fontana vcpu = g_malloc0(sizeof(struct whpx_vcpu)); 13581fc33bb9SClaudio Fontana 13591fc33bb9SClaudio Fontana if (!vcpu) { 13601fc33bb9SClaudio Fontana error_report("WHPX: Failed to allocte VCPU context."); 13611fc33bb9SClaudio Fontana ret = -ENOMEM; 13621fc33bb9SClaudio Fontana goto error; 13631fc33bb9SClaudio Fontana } 13641fc33bb9SClaudio Fontana 13651fc33bb9SClaudio Fontana hr = whp_dispatch.WHvEmulatorCreateEmulator( 13661fc33bb9SClaudio Fontana &whpx_emu_callbacks, 13671fc33bb9SClaudio Fontana &vcpu->emulator); 13681fc33bb9SClaudio Fontana if (FAILED(hr)) { 13691fc33bb9SClaudio Fontana error_report("WHPX: Failed to setup instruction completion support," 13701fc33bb9SClaudio Fontana " hr=%08lx", hr); 13711fc33bb9SClaudio Fontana ret = -EINVAL; 13721fc33bb9SClaudio Fontana goto error; 13731fc33bb9SClaudio Fontana } 13741fc33bb9SClaudio Fontana 13751fc33bb9SClaudio Fontana hr = whp_dispatch.WHvCreateVirtualProcessor( 13761fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 0); 13771fc33bb9SClaudio Fontana if (FAILED(hr)) { 13781fc33bb9SClaudio Fontana error_report("WHPX: Failed to create a virtual processor," 13791fc33bb9SClaudio Fontana " hr=%08lx", hr); 13801fc33bb9SClaudio Fontana whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator); 13811fc33bb9SClaudio Fontana ret = -EINVAL; 13821fc33bb9SClaudio Fontana goto error; 13831fc33bb9SClaudio Fontana } 13841fc33bb9SClaudio Fontana 13851fc33bb9SClaudio Fontana /* 13861fc33bb9SClaudio Fontana * vcpu's TSC frequency is either specified by user, or use the value 13871fc33bb9SClaudio Fontana * provided by Hyper-V if the former is not present. In the latter case, we 13881fc33bb9SClaudio Fontana * query it from Hyper-V and record in env->tsc_khz, so that vcpu's TSC 13891fc33bb9SClaudio Fontana * frequency can be migrated later via this field. 13901fc33bb9SClaudio Fontana */ 13911fc33bb9SClaudio Fontana if (!env->tsc_khz) { 13921fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetCapability( 13931fc33bb9SClaudio Fontana WHvCapabilityCodeProcessorClockFrequency, &freq, sizeof(freq), 13941fc33bb9SClaudio Fontana NULL); 13951fc33bb9SClaudio Fontana if (hr != WHV_E_UNKNOWN_CAPABILITY) { 13961fc33bb9SClaudio Fontana if (FAILED(hr)) { 13971fc33bb9SClaudio Fontana printf("WHPX: Failed to query tsc frequency, hr=0x%08lx\n", hr); 13981fc33bb9SClaudio Fontana } else { 13991fc33bb9SClaudio Fontana env->tsc_khz = freq / 1000; /* Hz to KHz */ 14001fc33bb9SClaudio Fontana } 14011fc33bb9SClaudio Fontana } 14021fc33bb9SClaudio Fontana } 14031fc33bb9SClaudio Fontana 14041fc33bb9SClaudio Fontana env->apic_bus_freq = HYPERV_APIC_BUS_FREQUENCY; 14051fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetCapability( 14061fc33bb9SClaudio Fontana WHvCapabilityCodeInterruptClockFrequency, &freq, sizeof(freq), NULL); 14071fc33bb9SClaudio Fontana if (hr != WHV_E_UNKNOWN_CAPABILITY) { 14081fc33bb9SClaudio Fontana if (FAILED(hr)) { 14091fc33bb9SClaudio Fontana printf("WHPX: Failed to query apic bus frequency hr=0x%08lx\n", hr); 14101fc33bb9SClaudio Fontana } else { 14111fc33bb9SClaudio Fontana env->apic_bus_freq = freq; 14121fc33bb9SClaudio Fontana } 14131fc33bb9SClaudio Fontana } 14141fc33bb9SClaudio Fontana 14151fc33bb9SClaudio Fontana /* 14161fc33bb9SClaudio Fontana * If the vmware cpuid frequency leaf option is set, and we have a valid 14171fc33bb9SClaudio Fontana * tsc value, trap the corresponding cpuid's. 14181fc33bb9SClaudio Fontana */ 14191fc33bb9SClaudio Fontana if (x86_cpu->vmware_cpuid_freq && env->tsc_khz) { 14201fc33bb9SClaudio Fontana UINT32 cpuidExitList[] = {1, 0x80000001, 0x40000000, 0x40000010}; 14211fc33bb9SClaudio Fontana 14221fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetPartitionProperty( 14231fc33bb9SClaudio Fontana whpx->partition, 14241fc33bb9SClaudio Fontana WHvPartitionPropertyCodeCpuidExitList, 14251fc33bb9SClaudio Fontana cpuidExitList, 14261fc33bb9SClaudio Fontana RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32)); 14271fc33bb9SClaudio Fontana 14281fc33bb9SClaudio Fontana if (FAILED(hr)) { 14291fc33bb9SClaudio Fontana error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx", 14301fc33bb9SClaudio Fontana hr); 14311fc33bb9SClaudio Fontana ret = -EINVAL; 14321fc33bb9SClaudio Fontana goto error; 14331fc33bb9SClaudio Fontana } 14341fc33bb9SClaudio Fontana } 14351fc33bb9SClaudio Fontana 14361fc33bb9SClaudio Fontana vcpu->interruptable = true; 14371fc33bb9SClaudio Fontana cpu->vcpu_dirty = true; 14381fc33bb9SClaudio Fontana cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu; 14391fc33bb9SClaudio Fontana max_vcpu_index = max(max_vcpu_index, cpu->cpu_index); 14401fc33bb9SClaudio Fontana qemu_add_vm_change_state_handler(whpx_cpu_update_state, cpu->env_ptr); 14411fc33bb9SClaudio Fontana 14421fc33bb9SClaudio Fontana return 0; 14431fc33bb9SClaudio Fontana 14441fc33bb9SClaudio Fontana error: 14451fc33bb9SClaudio Fontana g_free(vcpu); 14461fc33bb9SClaudio Fontana 14471fc33bb9SClaudio Fontana return ret; 14481fc33bb9SClaudio Fontana } 14491fc33bb9SClaudio Fontana 14501fc33bb9SClaudio Fontana int whpx_vcpu_exec(CPUState *cpu) 14511fc33bb9SClaudio Fontana { 14521fc33bb9SClaudio Fontana int ret; 14531fc33bb9SClaudio Fontana int fatal; 14541fc33bb9SClaudio Fontana 14551fc33bb9SClaudio Fontana for (;;) { 14561fc33bb9SClaudio Fontana if (cpu->exception_index >= EXCP_INTERRUPT) { 14571fc33bb9SClaudio Fontana ret = cpu->exception_index; 14581fc33bb9SClaudio Fontana cpu->exception_index = -1; 14591fc33bb9SClaudio Fontana break; 14601fc33bb9SClaudio Fontana } 14611fc33bb9SClaudio Fontana 14621fc33bb9SClaudio Fontana fatal = whpx_vcpu_run(cpu); 14631fc33bb9SClaudio Fontana 14641fc33bb9SClaudio Fontana if (fatal) { 14651fc33bb9SClaudio Fontana error_report("WHPX: Failed to exec a virtual processor"); 14661fc33bb9SClaudio Fontana abort(); 14671fc33bb9SClaudio Fontana } 14681fc33bb9SClaudio Fontana } 14691fc33bb9SClaudio Fontana 14701fc33bb9SClaudio Fontana return ret; 14711fc33bb9SClaudio Fontana } 14721fc33bb9SClaudio Fontana 14731fc33bb9SClaudio Fontana void whpx_destroy_vcpu(CPUState *cpu) 14741fc33bb9SClaudio Fontana { 14751fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 14761fc33bb9SClaudio Fontana struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu); 14771fc33bb9SClaudio Fontana 14781fc33bb9SClaudio Fontana whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index); 14791fc33bb9SClaudio Fontana whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator); 14801fc33bb9SClaudio Fontana g_free(cpu->hax_vcpu); 14811fc33bb9SClaudio Fontana return; 14821fc33bb9SClaudio Fontana } 14831fc33bb9SClaudio Fontana 14841fc33bb9SClaudio Fontana void whpx_vcpu_kick(CPUState *cpu) 14851fc33bb9SClaudio Fontana { 14861fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 14871fc33bb9SClaudio Fontana whp_dispatch.WHvCancelRunVirtualProcessor( 14881fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 0); 14891fc33bb9SClaudio Fontana } 14901fc33bb9SClaudio Fontana 14911fc33bb9SClaudio Fontana /* 14921fc33bb9SClaudio Fontana * Memory support. 14931fc33bb9SClaudio Fontana */ 14941fc33bb9SClaudio Fontana 14951fc33bb9SClaudio Fontana static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size, 14961fc33bb9SClaudio Fontana void *host_va, int add, int rom, 14971fc33bb9SClaudio Fontana const char *name) 14981fc33bb9SClaudio Fontana { 14991fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 15001fc33bb9SClaudio Fontana HRESULT hr; 15011fc33bb9SClaudio Fontana 15021fc33bb9SClaudio Fontana /* 15031fc33bb9SClaudio Fontana if (add) { 15041fc33bb9SClaudio Fontana printf("WHPX: ADD PA:%p Size:%p, Host:%p, %s, '%s'\n", 15051fc33bb9SClaudio Fontana (void*)start_pa, (void*)size, host_va, 15061fc33bb9SClaudio Fontana (rom ? "ROM" : "RAM"), name); 15071fc33bb9SClaudio Fontana } else { 15081fc33bb9SClaudio Fontana printf("WHPX: DEL PA:%p Size:%p, Host:%p, '%s'\n", 15091fc33bb9SClaudio Fontana (void*)start_pa, (void*)size, host_va, name); 15101fc33bb9SClaudio Fontana } 15111fc33bb9SClaudio Fontana */ 15121fc33bb9SClaudio Fontana 15131fc33bb9SClaudio Fontana if (add) { 15141fc33bb9SClaudio Fontana hr = whp_dispatch.WHvMapGpaRange(whpx->partition, 15151fc33bb9SClaudio Fontana host_va, 15161fc33bb9SClaudio Fontana start_pa, 15171fc33bb9SClaudio Fontana size, 15181fc33bb9SClaudio Fontana (WHvMapGpaRangeFlagRead | 15191fc33bb9SClaudio Fontana WHvMapGpaRangeFlagExecute | 15201fc33bb9SClaudio Fontana (rom ? 0 : WHvMapGpaRangeFlagWrite))); 15211fc33bb9SClaudio Fontana } else { 15221fc33bb9SClaudio Fontana hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition, 15231fc33bb9SClaudio Fontana start_pa, 15241fc33bb9SClaudio Fontana size); 15251fc33bb9SClaudio Fontana } 15261fc33bb9SClaudio Fontana 15271fc33bb9SClaudio Fontana if (FAILED(hr)) { 15281fc33bb9SClaudio Fontana error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes," 15291fc33bb9SClaudio Fontana " Host:%p, hr=%08lx", 15301fc33bb9SClaudio Fontana (add ? "MAP" : "UNMAP"), name, 15311fc33bb9SClaudio Fontana (void *)(uintptr_t)start_pa, (void *)size, host_va, hr); 15321fc33bb9SClaudio Fontana } 15331fc33bb9SClaudio Fontana } 15341fc33bb9SClaudio Fontana 15351fc33bb9SClaudio Fontana static void whpx_process_section(MemoryRegionSection *section, int add) 15361fc33bb9SClaudio Fontana { 15371fc33bb9SClaudio Fontana MemoryRegion *mr = section->mr; 15381fc33bb9SClaudio Fontana hwaddr start_pa = section->offset_within_address_space; 15391fc33bb9SClaudio Fontana ram_addr_t size = int128_get64(section->size); 15401fc33bb9SClaudio Fontana unsigned int delta; 15411fc33bb9SClaudio Fontana uint64_t host_va; 15421fc33bb9SClaudio Fontana 15431fc33bb9SClaudio Fontana if (!memory_region_is_ram(mr)) { 15441fc33bb9SClaudio Fontana return; 15451fc33bb9SClaudio Fontana } 15461fc33bb9SClaudio Fontana 15471fc33bb9SClaudio Fontana delta = qemu_real_host_page_size - (start_pa & ~qemu_real_host_page_mask); 15481fc33bb9SClaudio Fontana delta &= ~qemu_real_host_page_mask; 15491fc33bb9SClaudio Fontana if (delta > size) { 15501fc33bb9SClaudio Fontana return; 15511fc33bb9SClaudio Fontana } 15521fc33bb9SClaudio Fontana start_pa += delta; 15531fc33bb9SClaudio Fontana size -= delta; 15541fc33bb9SClaudio Fontana size &= qemu_real_host_page_mask; 15551fc33bb9SClaudio Fontana if (!size || (start_pa & ~qemu_real_host_page_mask)) { 15561fc33bb9SClaudio Fontana return; 15571fc33bb9SClaudio Fontana } 15581fc33bb9SClaudio Fontana 15591fc33bb9SClaudio Fontana host_va = (uintptr_t)memory_region_get_ram_ptr(mr) 15601fc33bb9SClaudio Fontana + section->offset_within_region + delta; 15611fc33bb9SClaudio Fontana 15621fc33bb9SClaudio Fontana whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add, 15631fc33bb9SClaudio Fontana memory_region_is_rom(mr), mr->name); 15641fc33bb9SClaudio Fontana } 15651fc33bb9SClaudio Fontana 15661fc33bb9SClaudio Fontana static void whpx_region_add(MemoryListener *listener, 15671fc33bb9SClaudio Fontana MemoryRegionSection *section) 15681fc33bb9SClaudio Fontana { 15691fc33bb9SClaudio Fontana memory_region_ref(section->mr); 15701fc33bb9SClaudio Fontana whpx_process_section(section, 1); 15711fc33bb9SClaudio Fontana } 15721fc33bb9SClaudio Fontana 15731fc33bb9SClaudio Fontana static void whpx_region_del(MemoryListener *listener, 15741fc33bb9SClaudio Fontana MemoryRegionSection *section) 15751fc33bb9SClaudio Fontana { 15761fc33bb9SClaudio Fontana whpx_process_section(section, 0); 15771fc33bb9SClaudio Fontana memory_region_unref(section->mr); 15781fc33bb9SClaudio Fontana } 15791fc33bb9SClaudio Fontana 15801fc33bb9SClaudio Fontana static void whpx_transaction_begin(MemoryListener *listener) 15811fc33bb9SClaudio Fontana { 15821fc33bb9SClaudio Fontana } 15831fc33bb9SClaudio Fontana 15841fc33bb9SClaudio Fontana static void whpx_transaction_commit(MemoryListener *listener) 15851fc33bb9SClaudio Fontana { 15861fc33bb9SClaudio Fontana } 15871fc33bb9SClaudio Fontana 15881fc33bb9SClaudio Fontana static void whpx_log_sync(MemoryListener *listener, 15891fc33bb9SClaudio Fontana MemoryRegionSection *section) 15901fc33bb9SClaudio Fontana { 15911fc33bb9SClaudio Fontana MemoryRegion *mr = section->mr; 15921fc33bb9SClaudio Fontana 15931fc33bb9SClaudio Fontana if (!memory_region_is_ram(mr)) { 15941fc33bb9SClaudio Fontana return; 15951fc33bb9SClaudio Fontana } 15961fc33bb9SClaudio Fontana 15971fc33bb9SClaudio Fontana memory_region_set_dirty(mr, 0, int128_get64(section->size)); 15981fc33bb9SClaudio Fontana } 15991fc33bb9SClaudio Fontana 16001fc33bb9SClaudio Fontana static MemoryListener whpx_memory_listener = { 1601*142518bdSPeter Xu .name = "whpx", 16021fc33bb9SClaudio Fontana .begin = whpx_transaction_begin, 16031fc33bb9SClaudio Fontana .commit = whpx_transaction_commit, 16041fc33bb9SClaudio Fontana .region_add = whpx_region_add, 16051fc33bb9SClaudio Fontana .region_del = whpx_region_del, 16061fc33bb9SClaudio Fontana .log_sync = whpx_log_sync, 16071fc33bb9SClaudio Fontana .priority = 10, 16081fc33bb9SClaudio Fontana }; 16091fc33bb9SClaudio Fontana 16101fc33bb9SClaudio Fontana static void whpx_memory_init(void) 16111fc33bb9SClaudio Fontana { 16121fc33bb9SClaudio Fontana memory_listener_register(&whpx_memory_listener, &address_space_memory); 16131fc33bb9SClaudio Fontana } 16141fc33bb9SClaudio Fontana 16151fc33bb9SClaudio Fontana /* 16161fc33bb9SClaudio Fontana * Load the functions from the given library, using the given handle. If a 16171fc33bb9SClaudio Fontana * handle is provided, it is used, otherwise the library is opened. The 16181fc33bb9SClaudio Fontana * handle will be updated on return with the opened one. 16191fc33bb9SClaudio Fontana */ 16201fc33bb9SClaudio Fontana static bool load_whp_dispatch_fns(HMODULE *handle, 16211fc33bb9SClaudio Fontana WHPFunctionList function_list) 16221fc33bb9SClaudio Fontana { 16231fc33bb9SClaudio Fontana HMODULE hLib = *handle; 16241fc33bb9SClaudio Fontana 16251fc33bb9SClaudio Fontana #define WINHV_PLATFORM_DLL "WinHvPlatform.dll" 16261fc33bb9SClaudio Fontana #define WINHV_EMULATION_DLL "WinHvEmulation.dll" 16271fc33bb9SClaudio Fontana #define WHP_LOAD_FIELD_OPTIONAL(return_type, function_name, signature) \ 16281fc33bb9SClaudio Fontana whp_dispatch.function_name = \ 16291fc33bb9SClaudio Fontana (function_name ## _t)GetProcAddress(hLib, #function_name); \ 16301fc33bb9SClaudio Fontana 16311fc33bb9SClaudio Fontana #define WHP_LOAD_FIELD(return_type, function_name, signature) \ 16321fc33bb9SClaudio Fontana whp_dispatch.function_name = \ 16331fc33bb9SClaudio Fontana (function_name ## _t)GetProcAddress(hLib, #function_name); \ 16341fc33bb9SClaudio Fontana if (!whp_dispatch.function_name) { \ 16351fc33bb9SClaudio Fontana error_report("Could not load function %s", #function_name); \ 16361fc33bb9SClaudio Fontana goto error; \ 16371fc33bb9SClaudio Fontana } \ 16381fc33bb9SClaudio Fontana 16391fc33bb9SClaudio Fontana #define WHP_LOAD_LIB(lib_name, handle_lib) \ 16401fc33bb9SClaudio Fontana if (!handle_lib) { \ 16411fc33bb9SClaudio Fontana handle_lib = LoadLibrary(lib_name); \ 16421fc33bb9SClaudio Fontana if (!handle_lib) { \ 16431fc33bb9SClaudio Fontana error_report("Could not load library %s.", lib_name); \ 16441fc33bb9SClaudio Fontana goto error; \ 16451fc33bb9SClaudio Fontana } \ 16461fc33bb9SClaudio Fontana } \ 16471fc33bb9SClaudio Fontana 16481fc33bb9SClaudio Fontana switch (function_list) { 16491fc33bb9SClaudio Fontana case WINHV_PLATFORM_FNS_DEFAULT: 16501fc33bb9SClaudio Fontana WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib) 16511fc33bb9SClaudio Fontana LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD) 16521fc33bb9SClaudio Fontana break; 16531fc33bb9SClaudio Fontana 16541fc33bb9SClaudio Fontana case WINHV_EMULATION_FNS_DEFAULT: 16551fc33bb9SClaudio Fontana WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib) 16561fc33bb9SClaudio Fontana LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD) 16571fc33bb9SClaudio Fontana break; 16581fc33bb9SClaudio Fontana 16591fc33bb9SClaudio Fontana case WINHV_PLATFORM_FNS_SUPPLEMENTAL: 16601fc33bb9SClaudio Fontana WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib) 16611fc33bb9SClaudio Fontana LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_LOAD_FIELD_OPTIONAL) 16621fc33bb9SClaudio Fontana break; 16631fc33bb9SClaudio Fontana } 16641fc33bb9SClaudio Fontana 16651fc33bb9SClaudio Fontana *handle = hLib; 16661fc33bb9SClaudio Fontana return true; 16671fc33bb9SClaudio Fontana 16681fc33bb9SClaudio Fontana error: 16691fc33bb9SClaudio Fontana if (hLib) { 16701fc33bb9SClaudio Fontana FreeLibrary(hLib); 16711fc33bb9SClaudio Fontana } 16721fc33bb9SClaudio Fontana 16731fc33bb9SClaudio Fontana return false; 16741fc33bb9SClaudio Fontana } 16751fc33bb9SClaudio Fontana 16761fc33bb9SClaudio Fontana static void whpx_set_kernel_irqchip(Object *obj, Visitor *v, 16771fc33bb9SClaudio Fontana const char *name, void *opaque, 16781fc33bb9SClaudio Fontana Error **errp) 16791fc33bb9SClaudio Fontana { 16801fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 16811fc33bb9SClaudio Fontana OnOffSplit mode; 16821fc33bb9SClaudio Fontana 16831fc33bb9SClaudio Fontana if (!visit_type_OnOffSplit(v, name, &mode, errp)) { 16841fc33bb9SClaudio Fontana return; 16851fc33bb9SClaudio Fontana } 16861fc33bb9SClaudio Fontana 16871fc33bb9SClaudio Fontana switch (mode) { 16881fc33bb9SClaudio Fontana case ON_OFF_SPLIT_ON: 16891fc33bb9SClaudio Fontana whpx->kernel_irqchip_allowed = true; 16901fc33bb9SClaudio Fontana whpx->kernel_irqchip_required = true; 16911fc33bb9SClaudio Fontana break; 16921fc33bb9SClaudio Fontana 16931fc33bb9SClaudio Fontana case ON_OFF_SPLIT_OFF: 16941fc33bb9SClaudio Fontana whpx->kernel_irqchip_allowed = false; 16951fc33bb9SClaudio Fontana whpx->kernel_irqchip_required = false; 16961fc33bb9SClaudio Fontana break; 16971fc33bb9SClaudio Fontana 16981fc33bb9SClaudio Fontana case ON_OFF_SPLIT_SPLIT: 16991fc33bb9SClaudio Fontana error_setg(errp, "WHPX: split irqchip currently not supported"); 17001fc33bb9SClaudio Fontana error_append_hint(errp, 17011fc33bb9SClaudio Fontana "Try without kernel-irqchip or with kernel-irqchip=on|off"); 17021fc33bb9SClaudio Fontana break; 17031fc33bb9SClaudio Fontana 17041fc33bb9SClaudio Fontana default: 17051fc33bb9SClaudio Fontana /* 17061fc33bb9SClaudio Fontana * The value was checked in visit_type_OnOffSplit() above. If 17071fc33bb9SClaudio Fontana * we get here, then something is wrong in QEMU. 17081fc33bb9SClaudio Fontana */ 17091fc33bb9SClaudio Fontana abort(); 17101fc33bb9SClaudio Fontana } 17111fc33bb9SClaudio Fontana } 17121fc33bb9SClaudio Fontana 17131fc33bb9SClaudio Fontana /* 17141fc33bb9SClaudio Fontana * Partition support 17151fc33bb9SClaudio Fontana */ 17161fc33bb9SClaudio Fontana 17171fc33bb9SClaudio Fontana static int whpx_accel_init(MachineState *ms) 17181fc33bb9SClaudio Fontana { 17191fc33bb9SClaudio Fontana struct whpx_state *whpx; 17201fc33bb9SClaudio Fontana int ret; 17211fc33bb9SClaudio Fontana HRESULT hr; 17221fc33bb9SClaudio Fontana WHV_CAPABILITY whpx_cap; 17231fc33bb9SClaudio Fontana UINT32 whpx_cap_size; 17241fc33bb9SClaudio Fontana WHV_PARTITION_PROPERTY prop; 17251fc33bb9SClaudio Fontana UINT32 cpuidExitList[] = {1, 0x80000001}; 17261fc33bb9SClaudio Fontana WHV_CAPABILITY_FEATURES features = {0}; 17271fc33bb9SClaudio Fontana 17281fc33bb9SClaudio Fontana whpx = &whpx_global; 17291fc33bb9SClaudio Fontana 17301fc33bb9SClaudio Fontana if (!init_whp_dispatch()) { 17311fc33bb9SClaudio Fontana ret = -ENOSYS; 17321fc33bb9SClaudio Fontana goto error; 17331fc33bb9SClaudio Fontana } 17341fc33bb9SClaudio Fontana 17351fc33bb9SClaudio Fontana whpx->mem_quota = ms->ram_size; 17361fc33bb9SClaudio Fontana 17371fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetCapability( 17381fc33bb9SClaudio Fontana WHvCapabilityCodeHypervisorPresent, &whpx_cap, 17391fc33bb9SClaudio Fontana sizeof(whpx_cap), &whpx_cap_size); 17401fc33bb9SClaudio Fontana if (FAILED(hr) || !whpx_cap.HypervisorPresent) { 17411fc33bb9SClaudio Fontana error_report("WHPX: No accelerator found, hr=%08lx", hr); 17421fc33bb9SClaudio Fontana ret = -ENOSPC; 17431fc33bb9SClaudio Fontana goto error; 17441fc33bb9SClaudio Fontana } 17451fc33bb9SClaudio Fontana 17461fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetCapability( 17471fc33bb9SClaudio Fontana WHvCapabilityCodeFeatures, &features, sizeof(features), NULL); 17481fc33bb9SClaudio Fontana if (FAILED(hr)) { 17491fc33bb9SClaudio Fontana error_report("WHPX: Failed to query capabilities, hr=%08lx", hr); 17501fc33bb9SClaudio Fontana ret = -EINVAL; 17511fc33bb9SClaudio Fontana goto error; 17521fc33bb9SClaudio Fontana } 17531fc33bb9SClaudio Fontana 17541fc33bb9SClaudio Fontana hr = whp_dispatch.WHvCreatePartition(&whpx->partition); 17551fc33bb9SClaudio Fontana if (FAILED(hr)) { 17561fc33bb9SClaudio Fontana error_report("WHPX: Failed to create partition, hr=%08lx", hr); 17571fc33bb9SClaudio Fontana ret = -EINVAL; 17581fc33bb9SClaudio Fontana goto error; 17591fc33bb9SClaudio Fontana } 17601fc33bb9SClaudio Fontana 17611fc33bb9SClaudio Fontana memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY)); 17621fc33bb9SClaudio Fontana prop.ProcessorCount = ms->smp.cpus; 17631fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetPartitionProperty( 17641fc33bb9SClaudio Fontana whpx->partition, 17651fc33bb9SClaudio Fontana WHvPartitionPropertyCodeProcessorCount, 17661fc33bb9SClaudio Fontana &prop, 17671fc33bb9SClaudio Fontana sizeof(WHV_PARTITION_PROPERTY)); 17681fc33bb9SClaudio Fontana 17691fc33bb9SClaudio Fontana if (FAILED(hr)) { 17701fc33bb9SClaudio Fontana error_report("WHPX: Failed to set partition core count to %d," 17711fc33bb9SClaudio Fontana " hr=%08lx", ms->smp.cores, hr); 17721fc33bb9SClaudio Fontana ret = -EINVAL; 17731fc33bb9SClaudio Fontana goto error; 17741fc33bb9SClaudio Fontana } 17751fc33bb9SClaudio Fontana 17761fc33bb9SClaudio Fontana /* 17771fc33bb9SClaudio Fontana * Error out if WHP doesn't support apic emulation and user is requiring 17781fc33bb9SClaudio Fontana * it. 17791fc33bb9SClaudio Fontana */ 17801fc33bb9SClaudio Fontana if (whpx->kernel_irqchip_required && (!features.LocalApicEmulation || 17811fc33bb9SClaudio Fontana !whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2)) { 17821fc33bb9SClaudio Fontana error_report("WHPX: kernel irqchip requested, but unavailable. " 17831fc33bb9SClaudio Fontana "Try without kernel-irqchip or with kernel-irqchip=off"); 17841fc33bb9SClaudio Fontana ret = -EINVAL; 17851fc33bb9SClaudio Fontana goto error; 17861fc33bb9SClaudio Fontana } 17871fc33bb9SClaudio Fontana 17881fc33bb9SClaudio Fontana if (whpx->kernel_irqchip_allowed && features.LocalApicEmulation && 17891fc33bb9SClaudio Fontana whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2) { 17901fc33bb9SClaudio Fontana WHV_X64_LOCAL_APIC_EMULATION_MODE mode = 17911fc33bb9SClaudio Fontana WHvX64LocalApicEmulationModeXApic; 17921fc33bb9SClaudio Fontana printf("WHPX: setting APIC emulation mode in the hypervisor\n"); 17931fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetPartitionProperty( 17941fc33bb9SClaudio Fontana whpx->partition, 17951fc33bb9SClaudio Fontana WHvPartitionPropertyCodeLocalApicEmulationMode, 17961fc33bb9SClaudio Fontana &mode, 17971fc33bb9SClaudio Fontana sizeof(mode)); 17981fc33bb9SClaudio Fontana if (FAILED(hr)) { 17991fc33bb9SClaudio Fontana error_report("WHPX: Failed to enable kernel irqchip hr=%08lx", hr); 18001fc33bb9SClaudio Fontana if (whpx->kernel_irqchip_required) { 18011fc33bb9SClaudio Fontana error_report("WHPX: kernel irqchip requested, but unavailable"); 18021fc33bb9SClaudio Fontana ret = -EINVAL; 18031fc33bb9SClaudio Fontana goto error; 18041fc33bb9SClaudio Fontana } 18051fc33bb9SClaudio Fontana } else { 18061fc33bb9SClaudio Fontana whpx->apic_in_platform = true; 18071fc33bb9SClaudio Fontana } 18081fc33bb9SClaudio Fontana } 18091fc33bb9SClaudio Fontana 18101fc33bb9SClaudio Fontana /* Register for MSR and CPUID exits */ 18111fc33bb9SClaudio Fontana memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY)); 18121fc33bb9SClaudio Fontana prop.ExtendedVmExits.X64MsrExit = 1; 18131fc33bb9SClaudio Fontana prop.ExtendedVmExits.X64CpuidExit = 1; 18141fc33bb9SClaudio Fontana if (whpx_apic_in_platform()) { 18151fc33bb9SClaudio Fontana prop.ExtendedVmExits.X64ApicInitSipiExitTrap = 1; 18161fc33bb9SClaudio Fontana } 18171fc33bb9SClaudio Fontana 18181fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetPartitionProperty( 18191fc33bb9SClaudio Fontana whpx->partition, 18201fc33bb9SClaudio Fontana WHvPartitionPropertyCodeExtendedVmExits, 18211fc33bb9SClaudio Fontana &prop, 18221fc33bb9SClaudio Fontana sizeof(WHV_PARTITION_PROPERTY)); 18231fc33bb9SClaudio Fontana if (FAILED(hr)) { 18241fc33bb9SClaudio Fontana error_report("WHPX: Failed to enable MSR & CPUIDexit, hr=%08lx", hr); 18251fc33bb9SClaudio Fontana ret = -EINVAL; 18261fc33bb9SClaudio Fontana goto error; 18271fc33bb9SClaudio Fontana } 18281fc33bb9SClaudio Fontana 18291fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetPartitionProperty( 18301fc33bb9SClaudio Fontana whpx->partition, 18311fc33bb9SClaudio Fontana WHvPartitionPropertyCodeCpuidExitList, 18321fc33bb9SClaudio Fontana cpuidExitList, 18331fc33bb9SClaudio Fontana RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32)); 18341fc33bb9SClaudio Fontana 18351fc33bb9SClaudio Fontana if (FAILED(hr)) { 18361fc33bb9SClaudio Fontana error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx", 18371fc33bb9SClaudio Fontana hr); 18381fc33bb9SClaudio Fontana ret = -EINVAL; 18391fc33bb9SClaudio Fontana goto error; 18401fc33bb9SClaudio Fontana } 18411fc33bb9SClaudio Fontana 18421fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetupPartition(whpx->partition); 18431fc33bb9SClaudio Fontana if (FAILED(hr)) { 18441fc33bb9SClaudio Fontana error_report("WHPX: Failed to setup partition, hr=%08lx", hr); 18451fc33bb9SClaudio Fontana ret = -EINVAL; 18461fc33bb9SClaudio Fontana goto error; 18471fc33bb9SClaudio Fontana } 18481fc33bb9SClaudio Fontana 18491fc33bb9SClaudio Fontana whpx_memory_init(); 18501fc33bb9SClaudio Fontana 18511fc33bb9SClaudio Fontana printf("Windows Hypervisor Platform accelerator is operational\n"); 18521fc33bb9SClaudio Fontana return 0; 18531fc33bb9SClaudio Fontana 18541fc33bb9SClaudio Fontana error: 18551fc33bb9SClaudio Fontana 18561fc33bb9SClaudio Fontana if (NULL != whpx->partition) { 18571fc33bb9SClaudio Fontana whp_dispatch.WHvDeletePartition(whpx->partition); 18581fc33bb9SClaudio Fontana whpx->partition = NULL; 18591fc33bb9SClaudio Fontana } 18601fc33bb9SClaudio Fontana 18611fc33bb9SClaudio Fontana return ret; 18621fc33bb9SClaudio Fontana } 18631fc33bb9SClaudio Fontana 18641fc33bb9SClaudio Fontana int whpx_enabled(void) 18651fc33bb9SClaudio Fontana { 18661fc33bb9SClaudio Fontana return whpx_allowed; 18671fc33bb9SClaudio Fontana } 18681fc33bb9SClaudio Fontana 186984f4ef17SPaolo Bonzini bool whpx_apic_in_platform(void) { 187084f4ef17SPaolo Bonzini return whpx_global.apic_in_platform; 187184f4ef17SPaolo Bonzini } 187284f4ef17SPaolo Bonzini 18731fc33bb9SClaudio Fontana static void whpx_accel_class_init(ObjectClass *oc, void *data) 18741fc33bb9SClaudio Fontana { 18751fc33bb9SClaudio Fontana AccelClass *ac = ACCEL_CLASS(oc); 18761fc33bb9SClaudio Fontana ac->name = "WHPX"; 18771fc33bb9SClaudio Fontana ac->init_machine = whpx_accel_init; 18781fc33bb9SClaudio Fontana ac->allowed = &whpx_allowed; 18791fc33bb9SClaudio Fontana 18801fc33bb9SClaudio Fontana object_class_property_add(oc, "kernel-irqchip", "on|off|split", 18811fc33bb9SClaudio Fontana NULL, whpx_set_kernel_irqchip, 18821fc33bb9SClaudio Fontana NULL, NULL); 18831fc33bb9SClaudio Fontana object_class_property_set_description(oc, "kernel-irqchip", 18841fc33bb9SClaudio Fontana "Configure WHPX in-kernel irqchip"); 18851fc33bb9SClaudio Fontana } 18861fc33bb9SClaudio Fontana 18871fc33bb9SClaudio Fontana static void whpx_accel_instance_init(Object *obj) 18881fc33bb9SClaudio Fontana { 18891fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global; 18901fc33bb9SClaudio Fontana 18911fc33bb9SClaudio Fontana memset(whpx, 0, sizeof(struct whpx_state)); 18921fc33bb9SClaudio Fontana /* Turn on kernel-irqchip, by default */ 18931fc33bb9SClaudio Fontana whpx->kernel_irqchip_allowed = true; 18941fc33bb9SClaudio Fontana } 18951fc33bb9SClaudio Fontana 18961fc33bb9SClaudio Fontana static const TypeInfo whpx_accel_type = { 18971fc33bb9SClaudio Fontana .name = ACCEL_CLASS_NAME("whpx"), 18981fc33bb9SClaudio Fontana .parent = TYPE_ACCEL, 18991fc33bb9SClaudio Fontana .instance_init = whpx_accel_instance_init, 19001fc33bb9SClaudio Fontana .class_init = whpx_accel_class_init, 19011fc33bb9SClaudio Fontana }; 19021fc33bb9SClaudio Fontana 19031fc33bb9SClaudio Fontana static void whpx_type_init(void) 19041fc33bb9SClaudio Fontana { 19051fc33bb9SClaudio Fontana type_register_static(&whpx_accel_type); 19061fc33bb9SClaudio Fontana } 19071fc33bb9SClaudio Fontana 19081fc33bb9SClaudio Fontana bool init_whp_dispatch(void) 19091fc33bb9SClaudio Fontana { 19101fc33bb9SClaudio Fontana if (whp_dispatch_initialized) { 19111fc33bb9SClaudio Fontana return true; 19121fc33bb9SClaudio Fontana } 19131fc33bb9SClaudio Fontana 19141fc33bb9SClaudio Fontana if (!load_whp_dispatch_fns(&hWinHvPlatform, WINHV_PLATFORM_FNS_DEFAULT)) { 19151fc33bb9SClaudio Fontana goto error; 19161fc33bb9SClaudio Fontana } 19171fc33bb9SClaudio Fontana 19181fc33bb9SClaudio Fontana if (!load_whp_dispatch_fns(&hWinHvEmulation, WINHV_EMULATION_FNS_DEFAULT)) { 19191fc33bb9SClaudio Fontana goto error; 19201fc33bb9SClaudio Fontana } 19211fc33bb9SClaudio Fontana 19221fc33bb9SClaudio Fontana assert(load_whp_dispatch_fns(&hWinHvPlatform, 19231fc33bb9SClaudio Fontana WINHV_PLATFORM_FNS_SUPPLEMENTAL)); 19241fc33bb9SClaudio Fontana whp_dispatch_initialized = true; 19251fc33bb9SClaudio Fontana 19261fc33bb9SClaudio Fontana return true; 19271fc33bb9SClaudio Fontana error: 19281fc33bb9SClaudio Fontana if (hWinHvPlatform) { 19291fc33bb9SClaudio Fontana FreeLibrary(hWinHvPlatform); 19301fc33bb9SClaudio Fontana } 19311fc33bb9SClaudio Fontana 19321fc33bb9SClaudio Fontana if (hWinHvEmulation) { 19331fc33bb9SClaudio Fontana FreeLibrary(hWinHvEmulation); 19341fc33bb9SClaudio Fontana } 19351fc33bb9SClaudio Fontana 19361fc33bb9SClaudio Fontana return false; 19371fc33bb9SClaudio Fontana } 19381fc33bb9SClaudio Fontana 19391fc33bb9SClaudio Fontana type_init(whpx_type_init); 1940