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