xref: /openbmc/qemu/target/i386/whpx/whpx-all.c (revision d7482ffe9756919531307330fd1c6dbec66e8c32)
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"
15*d7482ffeSIvan Shcherbakov #include "exec/gdbstub.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 
151*d7482ffeSIvan Shcherbakov /*
152*d7482ffeSIvan Shcherbakov  * The current implementation of instruction stepping sets the TF flag
153*d7482ffeSIvan Shcherbakov  * in RFLAGS, causing the CPU to raise an INT1 after each instruction.
154*d7482ffeSIvan Shcherbakov  * This corresponds to the WHvX64ExceptionTypeDebugTrapOrFault exception.
155*d7482ffeSIvan Shcherbakov  *
156*d7482ffeSIvan Shcherbakov  * This approach has a few limitations:
157*d7482ffeSIvan Shcherbakov  *     1. Stepping over a PUSHF/SAHF instruction will save the TF flag
158*d7482ffeSIvan Shcherbakov  *        along with the other flags, possibly restoring it later. It would
159*d7482ffeSIvan Shcherbakov  *        result in another INT1 when the flags are restored, triggering
160*d7482ffeSIvan Shcherbakov  *        a stop in gdb that could be cleared by doing another step.
161*d7482ffeSIvan Shcherbakov  *
162*d7482ffeSIvan Shcherbakov  *        Stepping over a POPF/LAHF instruction will let it overwrite the
163*d7482ffeSIvan Shcherbakov  *        TF flags, ending the stepping mode.
164*d7482ffeSIvan Shcherbakov  *
165*d7482ffeSIvan Shcherbakov  *     2. Stepping over an instruction raising an exception (e.g. INT, DIV,
166*d7482ffeSIvan Shcherbakov  *        or anything that could result in a page fault) will save the flags
167*d7482ffeSIvan Shcherbakov  *        to the stack, clear the TF flag, and let the guest execute the
168*d7482ffeSIvan Shcherbakov  *        handler. Normally, the guest will restore the original flags,
169*d7482ffeSIvan Shcherbakov  *        that will continue single-stepping.
170*d7482ffeSIvan Shcherbakov  *
171*d7482ffeSIvan Shcherbakov  *     3. Debuggers running on the guest may wish to set TF to do instruction
172*d7482ffeSIvan Shcherbakov  *        stepping. INT1 events generated by it would be intercepted by us,
173*d7482ffeSIvan Shcherbakov  *        as long as the gdb is connected to QEMU.
174*d7482ffeSIvan Shcherbakov  *
175*d7482ffeSIvan Shcherbakov  * In practice this means that:
176*d7482ffeSIvan Shcherbakov  *     1. Stepping through flags-modifying instructions may cause gdb to
177*d7482ffeSIvan Shcherbakov  *        continue or stop in unexpected places. This will be fully recoverable
178*d7482ffeSIvan Shcherbakov  *        and will not crash the target.
179*d7482ffeSIvan Shcherbakov  *
180*d7482ffeSIvan Shcherbakov  *     2. Stepping over an instruction that triggers an exception will step
181*d7482ffeSIvan Shcherbakov  *        over the exception handler, not into it.
182*d7482ffeSIvan Shcherbakov  *
183*d7482ffeSIvan Shcherbakov  *     3. Debugging the guest via gdb, while running debugger on the guest
184*d7482ffeSIvan Shcherbakov  *        at the same time may lead to unexpected effects. Removing all
185*d7482ffeSIvan Shcherbakov  *        breakpoints set via QEMU will prevent any further interference
186*d7482ffeSIvan Shcherbakov  *        with the guest-level debuggers.
187*d7482ffeSIvan Shcherbakov  *
188*d7482ffeSIvan Shcherbakov  * The limitations can be addressed as shown below:
189*d7482ffeSIvan Shcherbakov  *     1. PUSHF/SAHF/POPF/LAHF/IRET instructions can be emulated instead of
190*d7482ffeSIvan Shcherbakov  *        stepping through them. The exact semantics of the instructions is
191*d7482ffeSIvan Shcherbakov  *        defined in the "Combined Volume Set of Intel 64 and IA-32
192*d7482ffeSIvan Shcherbakov  *        Architectures Software Developer's Manuals", however it involves a
193*d7482ffeSIvan Shcherbakov  *        fair amount of corner cases due to compatibility with real mode,
194*d7482ffeSIvan Shcherbakov  *        virtual 8086 mode, and differences between 64-bit and 32-bit modes.
195*d7482ffeSIvan Shcherbakov  *
196*d7482ffeSIvan Shcherbakov  *     2. We could step into the guest's exception handlers using the following
197*d7482ffeSIvan Shcherbakov  *        sequence:
198*d7482ffeSIvan Shcherbakov  *          a. Temporarily enable catching of all exception types via
199*d7482ffeSIvan Shcherbakov  *             whpx_set_exception_exit_bitmap().
200*d7482ffeSIvan Shcherbakov  *          b. Once an exception is intercepted, read the IDT/GDT and locate
201*d7482ffeSIvan Shcherbakov  *             the original handler.
202*d7482ffeSIvan Shcherbakov  *          c. Patch the original handler, injecting an INT3 at the beginning.
203*d7482ffeSIvan Shcherbakov  *          d. Update the exception exit bitmap to only catch the
204*d7482ffeSIvan Shcherbakov  *             WHvX64ExceptionTypeBreakpointTrap exception.
205*d7482ffeSIvan Shcherbakov  *          e. Let the affected CPU run in the exclusive mode.
206*d7482ffeSIvan Shcherbakov  *          f. Restore the original handler and the exception exit bitmap.
207*d7482ffeSIvan Shcherbakov  *        Note that handling all corner cases related to IDT/GDT is harder
208*d7482ffeSIvan Shcherbakov  *        than it may seem. See x86_cpu_get_phys_page_attrs_debug() for a
209*d7482ffeSIvan Shcherbakov  *        rough idea.
210*d7482ffeSIvan Shcherbakov  *
211*d7482ffeSIvan Shcherbakov  *     3. In order to properly support guest-level debugging in parallel with
212*d7482ffeSIvan Shcherbakov  *        the QEMU-level debugging, we would need to be able to pass some INT1
213*d7482ffeSIvan Shcherbakov  *        events to the guest. This could be done via the following methods:
214*d7482ffeSIvan Shcherbakov  *          a. Using the WHvRegisterPendingEvent register. As of Windows 21H1,
215*d7482ffeSIvan Shcherbakov  *             it seems to only work for interrupts and not software
216*d7482ffeSIvan Shcherbakov  *             exceptions.
217*d7482ffeSIvan Shcherbakov  *          b. Locating and patching the original handler by parsing IDT/GDT.
218*d7482ffeSIvan Shcherbakov  *             This involves relatively complex logic outlined in the previous
219*d7482ffeSIvan Shcherbakov  *             paragraph.
220*d7482ffeSIvan Shcherbakov  *          c. Emulating the exception invocation (i.e. manually updating RIP,
221*d7482ffeSIvan Shcherbakov  *             RFLAGS, and pushing the old values to stack). This is even more
222*d7482ffeSIvan Shcherbakov  *             complicated than the previous option, since it involves checking
223*d7482ffeSIvan Shcherbakov  *             CPL, gate attributes, and doing various adjustments depending
224*d7482ffeSIvan Shcherbakov  *             on the current CPU mode, whether the CPL is changing, etc.
225*d7482ffeSIvan Shcherbakov  */
226*d7482ffeSIvan Shcherbakov typedef enum WhpxStepMode {
227*d7482ffeSIvan Shcherbakov     WHPX_STEP_NONE = 0,
228*d7482ffeSIvan Shcherbakov     /* Halt other VCPUs */
229*d7482ffeSIvan Shcherbakov     WHPX_STEP_EXCLUSIVE,
230*d7482ffeSIvan Shcherbakov } WhpxStepMode;
231*d7482ffeSIvan Shcherbakov 
2321fc33bb9SClaudio Fontana struct whpx_vcpu {
2331fc33bb9SClaudio Fontana     WHV_EMULATOR_HANDLE emulator;
2341fc33bb9SClaudio Fontana     bool window_registered;
2351fc33bb9SClaudio Fontana     bool interruptable;
2361fc33bb9SClaudio Fontana     bool ready_for_pic_interrupt;
2371fc33bb9SClaudio Fontana     uint64_t tpr;
2381fc33bb9SClaudio Fontana     uint64_t apic_base;
2391fc33bb9SClaudio Fontana     bool interruption_pending;
2401fc33bb9SClaudio Fontana 
2411fc33bb9SClaudio Fontana     /* Must be the last field as it may have a tail */
2421fc33bb9SClaudio Fontana     WHV_RUN_VP_EXIT_CONTEXT exit_ctx;
2431fc33bb9SClaudio Fontana };
2441fc33bb9SClaudio Fontana 
2451fc33bb9SClaudio Fontana static bool whpx_allowed;
2461fc33bb9SClaudio Fontana static bool whp_dispatch_initialized;
2471fc33bb9SClaudio Fontana static HMODULE hWinHvPlatform, hWinHvEmulation;
2481fc33bb9SClaudio Fontana static uint32_t max_vcpu_index;
2491fc33bb9SClaudio Fontana struct whpx_state whpx_global;
2501fc33bb9SClaudio Fontana struct WHPDispatch whp_dispatch;
2511fc33bb9SClaudio Fontana 
2521fc33bb9SClaudio Fontana 
2531fc33bb9SClaudio Fontana /*
2541fc33bb9SClaudio Fontana  * VP support
2551fc33bb9SClaudio Fontana  */
2561fc33bb9SClaudio Fontana 
2571fc33bb9SClaudio Fontana static struct whpx_vcpu *get_whpx_vcpu(CPUState *cpu)
2581fc33bb9SClaudio Fontana {
2591fc33bb9SClaudio Fontana     return (struct whpx_vcpu *)cpu->hax_vcpu;
2601fc33bb9SClaudio Fontana }
2611fc33bb9SClaudio Fontana 
2621fc33bb9SClaudio Fontana static WHV_X64_SEGMENT_REGISTER whpx_seg_q2h(const SegmentCache *qs, int v86,
2631fc33bb9SClaudio Fontana                                              int r86)
2641fc33bb9SClaudio Fontana {
2651fc33bb9SClaudio Fontana     WHV_X64_SEGMENT_REGISTER hs;
2661fc33bb9SClaudio Fontana     unsigned flags = qs->flags;
2671fc33bb9SClaudio Fontana 
2681fc33bb9SClaudio Fontana     hs.Base = qs->base;
2691fc33bb9SClaudio Fontana     hs.Limit = qs->limit;
2701fc33bb9SClaudio Fontana     hs.Selector = qs->selector;
2711fc33bb9SClaudio Fontana 
2721fc33bb9SClaudio Fontana     if (v86) {
2731fc33bb9SClaudio Fontana         hs.Attributes = 0;
2741fc33bb9SClaudio Fontana         hs.SegmentType = 3;
2751fc33bb9SClaudio Fontana         hs.Present = 1;
2761fc33bb9SClaudio Fontana         hs.DescriptorPrivilegeLevel = 3;
2771fc33bb9SClaudio Fontana         hs.NonSystemSegment = 1;
2781fc33bb9SClaudio Fontana 
2791fc33bb9SClaudio Fontana     } else {
2801fc33bb9SClaudio Fontana         hs.Attributes = (flags >> DESC_TYPE_SHIFT);
2811fc33bb9SClaudio Fontana 
2821fc33bb9SClaudio Fontana         if (r86) {
2831fc33bb9SClaudio Fontana             /* hs.Base &= 0xfffff; */
2841fc33bb9SClaudio Fontana         }
2851fc33bb9SClaudio Fontana     }
2861fc33bb9SClaudio Fontana 
2871fc33bb9SClaudio Fontana     return hs;
2881fc33bb9SClaudio Fontana }
2891fc33bb9SClaudio Fontana 
2901fc33bb9SClaudio Fontana static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs)
2911fc33bb9SClaudio Fontana {
2921fc33bb9SClaudio Fontana     SegmentCache qs;
2931fc33bb9SClaudio Fontana 
2941fc33bb9SClaudio Fontana     qs.base = hs->Base;
2951fc33bb9SClaudio Fontana     qs.limit = hs->Limit;
2961fc33bb9SClaudio Fontana     qs.selector = hs->Selector;
2971fc33bb9SClaudio Fontana 
2981fc33bb9SClaudio Fontana     qs.flags = ((uint32_t)hs->Attributes) << DESC_TYPE_SHIFT;
2991fc33bb9SClaudio Fontana 
3001fc33bb9SClaudio Fontana     return qs;
3011fc33bb9SClaudio Fontana }
3021fc33bb9SClaudio Fontana 
3031fc33bb9SClaudio Fontana static int whpx_set_tsc(CPUState *cpu)
3041fc33bb9SClaudio Fontana {
30595e862d7SPhilippe Mathieu-Daudé     CPUX86State *env = cpu->env_ptr;
3061fc33bb9SClaudio Fontana     WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc;
3071fc33bb9SClaudio Fontana     WHV_REGISTER_VALUE tsc_val;
3081fc33bb9SClaudio Fontana     HRESULT hr;
3091fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
3101fc33bb9SClaudio Fontana 
3111fc33bb9SClaudio Fontana     /*
3121fc33bb9SClaudio Fontana      * Suspend the partition prior to setting the TSC to reduce the variance
3131fc33bb9SClaudio Fontana      * in TSC across vCPUs. When the first vCPU runs post suspend, the
3141fc33bb9SClaudio Fontana      * partition is automatically resumed.
3151fc33bb9SClaudio Fontana      */
3161fc33bb9SClaudio Fontana     if (whp_dispatch.WHvSuspendPartitionTime) {
3171fc33bb9SClaudio Fontana 
3181fc33bb9SClaudio Fontana         /*
3191fc33bb9SClaudio Fontana          * Unable to suspend partition while setting TSC is not a fatal
3201fc33bb9SClaudio Fontana          * error. It just increases the likelihood of TSC variance between
3211fc33bb9SClaudio Fontana          * vCPUs and some guest OS are able to handle that just fine.
3221fc33bb9SClaudio Fontana          */
3231fc33bb9SClaudio Fontana         hr = whp_dispatch.WHvSuspendPartitionTime(whpx->partition);
3241fc33bb9SClaudio Fontana         if (FAILED(hr)) {
3251fc33bb9SClaudio Fontana             warn_report("WHPX: Failed to suspend partition, hr=%08lx", hr);
3261fc33bb9SClaudio Fontana         }
3271fc33bb9SClaudio Fontana     }
3281fc33bb9SClaudio Fontana 
3291fc33bb9SClaudio Fontana     tsc_val.Reg64 = env->tsc;
3301fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
3311fc33bb9SClaudio Fontana         whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val);
3321fc33bb9SClaudio Fontana     if (FAILED(hr)) {
3331fc33bb9SClaudio Fontana         error_report("WHPX: Failed to set TSC, hr=%08lx", hr);
3341fc33bb9SClaudio Fontana         return -1;
3351fc33bb9SClaudio Fontana     }
3361fc33bb9SClaudio Fontana 
3371fc33bb9SClaudio Fontana     return 0;
3381fc33bb9SClaudio Fontana }
3391fc33bb9SClaudio Fontana 
3405ad93fd3SIvan Shcherbakov /*
3415ad93fd3SIvan Shcherbakov  * The CR8 register in the CPU is mapped to the TPR register of the APIC,
3425ad93fd3SIvan Shcherbakov  * however, they use a slightly different encoding. Specifically:
3435ad93fd3SIvan Shcherbakov  *
3445ad93fd3SIvan Shcherbakov  *     APIC.TPR[bits 7:4] = CR8[bits 3:0]
3455ad93fd3SIvan Shcherbakov  *
3465ad93fd3SIvan Shcherbakov  * This mechanism is described in section 10.8.6.1 of Volume 3 of Intel 64
3475ad93fd3SIvan Shcherbakov  * and IA-32 Architectures Software Developer's Manual.
3485ad93fd3SIvan Shcherbakov  */
3495ad93fd3SIvan Shcherbakov 
3505ad93fd3SIvan Shcherbakov static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr)
3515ad93fd3SIvan Shcherbakov {
3525ad93fd3SIvan Shcherbakov     return tpr >> 4;
3535ad93fd3SIvan Shcherbakov }
3545ad93fd3SIvan Shcherbakov 
3551fc33bb9SClaudio Fontana static void whpx_set_registers(CPUState *cpu, int level)
3561fc33bb9SClaudio Fontana {
3571fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
3581fc33bb9SClaudio Fontana     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
35995e862d7SPhilippe Mathieu-Daudé     CPUX86State *env = cpu->env_ptr;
3601fc33bb9SClaudio Fontana     X86CPU *x86_cpu = X86_CPU(cpu);
3611fc33bb9SClaudio Fontana     struct whpx_register_set vcxt;
3621fc33bb9SClaudio Fontana     HRESULT hr;
3631fc33bb9SClaudio Fontana     int idx;
3641fc33bb9SClaudio Fontana     int idx_next;
3651fc33bb9SClaudio Fontana     int i;
3661fc33bb9SClaudio Fontana     int v86, r86;
3671fc33bb9SClaudio Fontana 
3681fc33bb9SClaudio Fontana     assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
3691fc33bb9SClaudio Fontana 
3701fc33bb9SClaudio Fontana     /*
3711fc33bb9SClaudio Fontana      * Following MSRs have side effects on the guest or are too heavy for
3721fc33bb9SClaudio Fontana      * runtime. Limit them to full state update.
3731fc33bb9SClaudio Fontana      */
3741fc33bb9SClaudio Fontana     if (level >= WHPX_SET_RESET_STATE) {
3751fc33bb9SClaudio Fontana         whpx_set_tsc(cpu);
3761fc33bb9SClaudio Fontana     }
3771fc33bb9SClaudio Fontana 
3781fc33bb9SClaudio Fontana     memset(&vcxt, 0, sizeof(struct whpx_register_set));
3791fc33bb9SClaudio Fontana 
3801fc33bb9SClaudio Fontana     v86 = (env->eflags & VM_MASK);
3811fc33bb9SClaudio Fontana     r86 = !(env->cr[0] & CR0_PE_MASK);
3821fc33bb9SClaudio Fontana 
3835ad93fd3SIvan Shcherbakov     vcpu->tpr = whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state));
3841fc33bb9SClaudio Fontana     vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state);
3851fc33bb9SClaudio Fontana 
3861fc33bb9SClaudio Fontana     idx = 0;
3871fc33bb9SClaudio Fontana 
3881fc33bb9SClaudio Fontana     /* Indexes for first 16 registers match between HV and QEMU definitions */
3891fc33bb9SClaudio Fontana     idx_next = 16;
3901fc33bb9SClaudio Fontana     for (idx = 0; idx < CPU_NB_REGS; idx += 1) {
3911fc33bb9SClaudio Fontana         vcxt.values[idx].Reg64 = (uint64_t)env->regs[idx];
3921fc33bb9SClaudio Fontana     }
3931fc33bb9SClaudio Fontana     idx = idx_next;
3941fc33bb9SClaudio Fontana 
3951fc33bb9SClaudio Fontana     /* Same goes for RIP and RFLAGS */
3961fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterRip);
3971fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->eip;
3981fc33bb9SClaudio Fontana 
3991fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterRflags);
4001fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->eflags;
4011fc33bb9SClaudio Fontana 
4021fc33bb9SClaudio Fontana     /* Translate 6+4 segment registers. HV and QEMU order matches  */
4031fc33bb9SClaudio Fontana     assert(idx == WHvX64RegisterEs);
4041fc33bb9SClaudio Fontana     for (i = 0; i < 6; i += 1, idx += 1) {
4051fc33bb9SClaudio Fontana         vcxt.values[idx].Segment = whpx_seg_q2h(&env->segs[i], v86, r86);
4061fc33bb9SClaudio Fontana     }
4071fc33bb9SClaudio Fontana 
4081fc33bb9SClaudio Fontana     assert(idx == WHvX64RegisterLdtr);
4091fc33bb9SClaudio Fontana     vcxt.values[idx++].Segment = whpx_seg_q2h(&env->ldt, 0, 0);
4101fc33bb9SClaudio Fontana 
4111fc33bb9SClaudio Fontana     assert(idx == WHvX64RegisterTr);
4121fc33bb9SClaudio Fontana     vcxt.values[idx++].Segment = whpx_seg_q2h(&env->tr, 0, 0);
4131fc33bb9SClaudio Fontana 
4141fc33bb9SClaudio Fontana     assert(idx == WHvX64RegisterIdtr);
4151fc33bb9SClaudio Fontana     vcxt.values[idx].Table.Base = env->idt.base;
4161fc33bb9SClaudio Fontana     vcxt.values[idx].Table.Limit = env->idt.limit;
4171fc33bb9SClaudio Fontana     idx += 1;
4181fc33bb9SClaudio Fontana 
4191fc33bb9SClaudio Fontana     assert(idx == WHvX64RegisterGdtr);
4201fc33bb9SClaudio Fontana     vcxt.values[idx].Table.Base = env->gdt.base;
4211fc33bb9SClaudio Fontana     vcxt.values[idx].Table.Limit = env->gdt.limit;
4221fc33bb9SClaudio Fontana     idx += 1;
4231fc33bb9SClaudio Fontana 
4241fc33bb9SClaudio Fontana     /* CR0, 2, 3, 4, 8 */
4251fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCr0);
4261fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->cr[0];
4271fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCr2);
4281fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->cr[2];
4291fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCr3);
4301fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->cr[3];
4311fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCr4);
4321fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->cr[4];
4331fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCr8);
4341fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = vcpu->tpr;
4351fc33bb9SClaudio Fontana 
4361fc33bb9SClaudio Fontana     /* 8 Debug Registers - Skipped */
4371fc33bb9SClaudio Fontana 
4381fc33bb9SClaudio Fontana     /* 16 XMM registers */
4391fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
4401fc33bb9SClaudio Fontana     idx_next = idx + 16;
4411fc33bb9SClaudio Fontana     for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
4421fc33bb9SClaudio Fontana         vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);
4431fc33bb9SClaudio Fontana         vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);
4441fc33bb9SClaudio Fontana     }
4451fc33bb9SClaudio Fontana     idx = idx_next;
4461fc33bb9SClaudio Fontana 
4471fc33bb9SClaudio Fontana     /* 8 FP registers */
4481fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
4491fc33bb9SClaudio Fontana     for (i = 0; i < 8; i += 1, idx += 1) {
4501fc33bb9SClaudio Fontana         vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0);
4511fc33bb9SClaudio Fontana         /* vcxt.values[idx].Fp.AsUINT128.High64 =
4521fc33bb9SClaudio Fontana                env->fpregs[i].mmx.MMX_Q(1);
4531fc33bb9SClaudio Fontana         */
4541fc33bb9SClaudio Fontana     }
4551fc33bb9SClaudio Fontana 
4561fc33bb9SClaudio Fontana     /* FP control status register */
4571fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);
4581fc33bb9SClaudio Fontana     vcxt.values[idx].FpControlStatus.FpControl = env->fpuc;
4591fc33bb9SClaudio Fontana     vcxt.values[idx].FpControlStatus.FpStatus =
4601fc33bb9SClaudio Fontana         (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4611fc33bb9SClaudio Fontana     vcxt.values[idx].FpControlStatus.FpTag = 0;
4621fc33bb9SClaudio Fontana     for (i = 0; i < 8; ++i) {
4631fc33bb9SClaudio Fontana         vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i;
4641fc33bb9SClaudio Fontana     }
4651fc33bb9SClaudio Fontana     vcxt.values[idx].FpControlStatus.Reserved = 0;
4661fc33bb9SClaudio Fontana     vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop;
4671fc33bb9SClaudio Fontana     vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip;
4681fc33bb9SClaudio Fontana     idx += 1;
4691fc33bb9SClaudio Fontana 
4701fc33bb9SClaudio Fontana     /* XMM control status register */
4711fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);
4721fc33bb9SClaudio Fontana     vcxt.values[idx].XmmControlStatus.LastFpRdp = 0;
4731fc33bb9SClaudio Fontana     vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr;
4741fc33bb9SClaudio Fontana     vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff;
4751fc33bb9SClaudio Fontana     idx += 1;
4761fc33bb9SClaudio Fontana 
4771fc33bb9SClaudio Fontana     /* MSRs */
4781fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterEfer);
4791fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->efer;
4801fc33bb9SClaudio Fontana #ifdef TARGET_X86_64
4811fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase);
4821fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->kernelgsbase;
4831fc33bb9SClaudio Fontana #endif
4841fc33bb9SClaudio Fontana 
4851fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterApicBase);
4861fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = vcpu->apic_base;
4871fc33bb9SClaudio Fontana 
4881fc33bb9SClaudio Fontana     /* WHvX64RegisterPat - Skipped */
4891fc33bb9SClaudio Fontana 
4901fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs);
4911fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->sysenter_cs;
4921fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip);
4931fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->sysenter_eip;
4941fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp);
4951fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->sysenter_esp;
4961fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterStar);
4971fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->star;
4981fc33bb9SClaudio Fontana #ifdef TARGET_X86_64
4991fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterLstar);
5001fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->lstar;
5011fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCstar);
5021fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->cstar;
5031fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterSfmask);
5041fc33bb9SClaudio Fontana     vcxt.values[idx++].Reg64 = env->fmask;
5051fc33bb9SClaudio Fontana #endif
5061fc33bb9SClaudio Fontana 
5071fc33bb9SClaudio Fontana     /* Interrupt / Event Registers - Skipped */
5081fc33bb9SClaudio Fontana 
5091fc33bb9SClaudio Fontana     assert(idx == RTL_NUMBER_OF(whpx_register_names));
5101fc33bb9SClaudio Fontana 
5111fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
5121fc33bb9SClaudio Fontana         whpx->partition, cpu->cpu_index,
5131fc33bb9SClaudio Fontana         whpx_register_names,
5141fc33bb9SClaudio Fontana         RTL_NUMBER_OF(whpx_register_names),
5151fc33bb9SClaudio Fontana         &vcxt.values[0]);
5161fc33bb9SClaudio Fontana 
5171fc33bb9SClaudio Fontana     if (FAILED(hr)) {
5181fc33bb9SClaudio Fontana         error_report("WHPX: Failed to set virtual processor context, hr=%08lx",
5191fc33bb9SClaudio Fontana                      hr);
5201fc33bb9SClaudio Fontana     }
5211fc33bb9SClaudio Fontana 
5221fc33bb9SClaudio Fontana     return;
5231fc33bb9SClaudio Fontana }
5241fc33bb9SClaudio Fontana 
5251fc33bb9SClaudio Fontana static int whpx_get_tsc(CPUState *cpu)
5261fc33bb9SClaudio Fontana {
52795e862d7SPhilippe Mathieu-Daudé     CPUX86State *env = cpu->env_ptr;
5281fc33bb9SClaudio Fontana     WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc;
5291fc33bb9SClaudio Fontana     WHV_REGISTER_VALUE tsc_val;
5301fc33bb9SClaudio Fontana     HRESULT hr;
5311fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
5321fc33bb9SClaudio Fontana 
5331fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
5341fc33bb9SClaudio Fontana         whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val);
5351fc33bb9SClaudio Fontana     if (FAILED(hr)) {
5361fc33bb9SClaudio Fontana         error_report("WHPX: Failed to get TSC, hr=%08lx", hr);
5371fc33bb9SClaudio Fontana         return -1;
5381fc33bb9SClaudio Fontana     }
5391fc33bb9SClaudio Fontana 
5401fc33bb9SClaudio Fontana     env->tsc = tsc_val.Reg64;
5411fc33bb9SClaudio Fontana     return 0;
5421fc33bb9SClaudio Fontana }
5431fc33bb9SClaudio Fontana 
5441fc33bb9SClaudio Fontana static void whpx_get_registers(CPUState *cpu)
5451fc33bb9SClaudio Fontana {
5461fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
5471fc33bb9SClaudio Fontana     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
54895e862d7SPhilippe Mathieu-Daudé     CPUX86State *env = cpu->env_ptr;
5491fc33bb9SClaudio Fontana     X86CPU *x86_cpu = X86_CPU(cpu);
5501fc33bb9SClaudio Fontana     struct whpx_register_set vcxt;
5511fc33bb9SClaudio Fontana     uint64_t tpr, apic_base;
5521fc33bb9SClaudio Fontana     HRESULT hr;
5531fc33bb9SClaudio Fontana     int idx;
5541fc33bb9SClaudio Fontana     int idx_next;
5551fc33bb9SClaudio Fontana     int i;
5561fc33bb9SClaudio Fontana 
5571fc33bb9SClaudio Fontana     assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
5581fc33bb9SClaudio Fontana 
5591fc33bb9SClaudio Fontana     if (!env->tsc_valid) {
5601fc33bb9SClaudio Fontana         whpx_get_tsc(cpu);
5611fc33bb9SClaudio Fontana         env->tsc_valid = !runstate_is_running();
5621fc33bb9SClaudio Fontana     }
5631fc33bb9SClaudio Fontana 
5641fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
5651fc33bb9SClaudio Fontana         whpx->partition, cpu->cpu_index,
5661fc33bb9SClaudio Fontana         whpx_register_names,
5671fc33bb9SClaudio Fontana         RTL_NUMBER_OF(whpx_register_names),
5681fc33bb9SClaudio Fontana         &vcxt.values[0]);
5691fc33bb9SClaudio Fontana     if (FAILED(hr)) {
5701fc33bb9SClaudio Fontana         error_report("WHPX: Failed to get virtual processor context, hr=%08lx",
5711fc33bb9SClaudio Fontana                      hr);
5721fc33bb9SClaudio Fontana     }
5731fc33bb9SClaudio Fontana 
5745ad93fd3SIvan Shcherbakov     if (whpx_apic_in_platform()) {
5755ad93fd3SIvan Shcherbakov         /*
5765ad93fd3SIvan Shcherbakov          * Fetch the TPR value from the emulated APIC. It may get overwritten
5775ad93fd3SIvan Shcherbakov          * below with the value from CR8 returned by
5785ad93fd3SIvan Shcherbakov          * WHvGetVirtualProcessorRegisters().
5795ad93fd3SIvan Shcherbakov          */
5805ad93fd3SIvan Shcherbakov         whpx_apic_get(x86_cpu->apic_state);
5815ad93fd3SIvan Shcherbakov         vcpu->tpr = whpx_apic_tpr_to_cr8(
5825ad93fd3SIvan Shcherbakov             cpu_get_apic_tpr(x86_cpu->apic_state));
5835ad93fd3SIvan Shcherbakov     }
5845ad93fd3SIvan Shcherbakov 
5851fc33bb9SClaudio Fontana     idx = 0;
5861fc33bb9SClaudio Fontana 
5871fc33bb9SClaudio Fontana     /* Indexes for first 16 registers match between HV and QEMU definitions */
5881fc33bb9SClaudio Fontana     idx_next = 16;
5891fc33bb9SClaudio Fontana     for (idx = 0; idx < CPU_NB_REGS; idx += 1) {
5901fc33bb9SClaudio Fontana         env->regs[idx] = vcxt.values[idx].Reg64;
5911fc33bb9SClaudio Fontana     }
5921fc33bb9SClaudio Fontana     idx = idx_next;
5931fc33bb9SClaudio Fontana 
5941fc33bb9SClaudio Fontana     /* Same goes for RIP and RFLAGS */
5951fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterRip);
5961fc33bb9SClaudio Fontana     env->eip = vcxt.values[idx++].Reg64;
5971fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterRflags);
5981fc33bb9SClaudio Fontana     env->eflags = vcxt.values[idx++].Reg64;
5991fc33bb9SClaudio Fontana 
6001fc33bb9SClaudio Fontana     /* Translate 6+4 segment registers. HV and QEMU order matches  */
6011fc33bb9SClaudio Fontana     assert(idx == WHvX64RegisterEs);
6021fc33bb9SClaudio Fontana     for (i = 0; i < 6; i += 1, idx += 1) {
6031fc33bb9SClaudio Fontana         env->segs[i] = whpx_seg_h2q(&vcxt.values[idx].Segment);
6041fc33bb9SClaudio Fontana     }
6051fc33bb9SClaudio Fontana 
6061fc33bb9SClaudio Fontana     assert(idx == WHvX64RegisterLdtr);
6071fc33bb9SClaudio Fontana     env->ldt = whpx_seg_h2q(&vcxt.values[idx++].Segment);
6081fc33bb9SClaudio Fontana     assert(idx == WHvX64RegisterTr);
6091fc33bb9SClaudio Fontana     env->tr = whpx_seg_h2q(&vcxt.values[idx++].Segment);
6101fc33bb9SClaudio Fontana     assert(idx == WHvX64RegisterIdtr);
6111fc33bb9SClaudio Fontana     env->idt.base = vcxt.values[idx].Table.Base;
6121fc33bb9SClaudio Fontana     env->idt.limit = vcxt.values[idx].Table.Limit;
6131fc33bb9SClaudio Fontana     idx += 1;
6141fc33bb9SClaudio Fontana     assert(idx == WHvX64RegisterGdtr);
6151fc33bb9SClaudio Fontana     env->gdt.base = vcxt.values[idx].Table.Base;
6161fc33bb9SClaudio Fontana     env->gdt.limit = vcxt.values[idx].Table.Limit;
6171fc33bb9SClaudio Fontana     idx += 1;
6181fc33bb9SClaudio Fontana 
6191fc33bb9SClaudio Fontana     /* CR0, 2, 3, 4, 8 */
6201fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCr0);
6211fc33bb9SClaudio Fontana     env->cr[0] = vcxt.values[idx++].Reg64;
6221fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCr2);
6231fc33bb9SClaudio Fontana     env->cr[2] = vcxt.values[idx++].Reg64;
6241fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCr3);
6251fc33bb9SClaudio Fontana     env->cr[3] = vcxt.values[idx++].Reg64;
6261fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCr4);
6271fc33bb9SClaudio Fontana     env->cr[4] = vcxt.values[idx++].Reg64;
6281fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCr8);
6291fc33bb9SClaudio Fontana     tpr = vcxt.values[idx++].Reg64;
6301fc33bb9SClaudio Fontana     if (tpr != vcpu->tpr) {
6311fc33bb9SClaudio Fontana         vcpu->tpr = tpr;
6321fc33bb9SClaudio Fontana         cpu_set_apic_tpr(x86_cpu->apic_state, tpr);
6331fc33bb9SClaudio Fontana     }
6341fc33bb9SClaudio Fontana 
6351fc33bb9SClaudio Fontana     /* 8 Debug Registers - Skipped */
6361fc33bb9SClaudio Fontana 
6371fc33bb9SClaudio Fontana     /* 16 XMM registers */
6381fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
6391fc33bb9SClaudio Fontana     idx_next = idx + 16;
6401fc33bb9SClaudio Fontana     for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
6411fc33bb9SClaudio Fontana         env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64;
6421fc33bb9SClaudio Fontana         env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64;
6431fc33bb9SClaudio Fontana     }
6441fc33bb9SClaudio Fontana     idx = idx_next;
6451fc33bb9SClaudio Fontana 
6461fc33bb9SClaudio Fontana     /* 8 FP registers */
6471fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
6481fc33bb9SClaudio Fontana     for (i = 0; i < 8; i += 1, idx += 1) {
6491fc33bb9SClaudio Fontana         env->fpregs[i].mmx.MMX_Q(0) = vcxt.values[idx].Fp.AsUINT128.Low64;
6501fc33bb9SClaudio Fontana         /* env->fpregs[i].mmx.MMX_Q(1) =
6511fc33bb9SClaudio Fontana                vcxt.values[idx].Fp.AsUINT128.High64;
6521fc33bb9SClaudio Fontana         */
6531fc33bb9SClaudio Fontana     }
6541fc33bb9SClaudio Fontana 
6551fc33bb9SClaudio Fontana     /* FP control status register */
6561fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);
6571fc33bb9SClaudio Fontana     env->fpuc = vcxt.values[idx].FpControlStatus.FpControl;
6581fc33bb9SClaudio Fontana     env->fpstt = (vcxt.values[idx].FpControlStatus.FpStatus >> 11) & 0x7;
6591fc33bb9SClaudio Fontana     env->fpus = vcxt.values[idx].FpControlStatus.FpStatus & ~0x3800;
6601fc33bb9SClaudio Fontana     for (i = 0; i < 8; ++i) {
6611fc33bb9SClaudio Fontana         env->fptags[i] = !((vcxt.values[idx].FpControlStatus.FpTag >> i) & 1);
6621fc33bb9SClaudio Fontana     }
6631fc33bb9SClaudio Fontana     env->fpop = vcxt.values[idx].FpControlStatus.LastFpOp;
6641fc33bb9SClaudio Fontana     env->fpip = vcxt.values[idx].FpControlStatus.LastFpRip;
6651fc33bb9SClaudio Fontana     idx += 1;
6661fc33bb9SClaudio Fontana 
6671fc33bb9SClaudio Fontana     /* XMM control status register */
6681fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);
6691fc33bb9SClaudio Fontana     env->mxcsr = vcxt.values[idx].XmmControlStatus.XmmStatusControl;
6701fc33bb9SClaudio Fontana     idx += 1;
6711fc33bb9SClaudio Fontana 
6721fc33bb9SClaudio Fontana     /* MSRs */
6731fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterEfer);
6741fc33bb9SClaudio Fontana     env->efer = vcxt.values[idx++].Reg64;
6751fc33bb9SClaudio Fontana #ifdef TARGET_X86_64
6761fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase);
6771fc33bb9SClaudio Fontana     env->kernelgsbase = vcxt.values[idx++].Reg64;
6781fc33bb9SClaudio Fontana #endif
6791fc33bb9SClaudio Fontana 
6801fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterApicBase);
6811fc33bb9SClaudio Fontana     apic_base = vcxt.values[idx++].Reg64;
6821fc33bb9SClaudio Fontana     if (apic_base != vcpu->apic_base) {
6831fc33bb9SClaudio Fontana         vcpu->apic_base = apic_base;
6841fc33bb9SClaudio Fontana         cpu_set_apic_base(x86_cpu->apic_state, vcpu->apic_base);
6851fc33bb9SClaudio Fontana     }
6861fc33bb9SClaudio Fontana 
6871fc33bb9SClaudio Fontana     /* WHvX64RegisterPat - Skipped */
6881fc33bb9SClaudio Fontana 
6891fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs);
6901fc33bb9SClaudio Fontana     env->sysenter_cs = vcxt.values[idx++].Reg64;
6911fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip);
6921fc33bb9SClaudio Fontana     env->sysenter_eip = vcxt.values[idx++].Reg64;
6931fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp);
6941fc33bb9SClaudio Fontana     env->sysenter_esp = vcxt.values[idx++].Reg64;
6951fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterStar);
6961fc33bb9SClaudio Fontana     env->star = vcxt.values[idx++].Reg64;
6971fc33bb9SClaudio Fontana #ifdef TARGET_X86_64
6981fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterLstar);
6991fc33bb9SClaudio Fontana     env->lstar = vcxt.values[idx++].Reg64;
7001fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterCstar);
7011fc33bb9SClaudio Fontana     env->cstar = vcxt.values[idx++].Reg64;
7021fc33bb9SClaudio Fontana     assert(whpx_register_names[idx] == WHvX64RegisterSfmask);
7031fc33bb9SClaudio Fontana     env->fmask = vcxt.values[idx++].Reg64;
7041fc33bb9SClaudio Fontana #endif
7051fc33bb9SClaudio Fontana 
7061fc33bb9SClaudio Fontana     /* Interrupt / Event Registers - Skipped */
7071fc33bb9SClaudio Fontana 
7081fc33bb9SClaudio Fontana     assert(idx == RTL_NUMBER_OF(whpx_register_names));
7091fc33bb9SClaudio Fontana 
7101fc33bb9SClaudio Fontana     if (whpx_apic_in_platform()) {
7111fc33bb9SClaudio Fontana         whpx_apic_get(x86_cpu->apic_state);
7121fc33bb9SClaudio Fontana     }
7131fc33bb9SClaudio Fontana 
714e5618908SIvan Shcherbakov     x86_update_hflags(env);
715e5618908SIvan Shcherbakov 
7161fc33bb9SClaudio Fontana     return;
7171fc33bb9SClaudio Fontana }
7181fc33bb9SClaudio Fontana 
7191fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_ioport_callback(
7201fc33bb9SClaudio Fontana     void *ctx,
7211fc33bb9SClaudio Fontana     WHV_EMULATOR_IO_ACCESS_INFO *IoAccess)
7221fc33bb9SClaudio Fontana {
7231fc33bb9SClaudio Fontana     MemTxAttrs attrs = { 0 };
7241fc33bb9SClaudio Fontana     address_space_rw(&address_space_io, IoAccess->Port, attrs,
7251fc33bb9SClaudio Fontana                      &IoAccess->Data, IoAccess->AccessSize,
7261fc33bb9SClaudio Fontana                      IoAccess->Direction);
7271fc33bb9SClaudio Fontana     return S_OK;
7281fc33bb9SClaudio Fontana }
7291fc33bb9SClaudio Fontana 
7301fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_mmio_callback(
7311fc33bb9SClaudio Fontana     void *ctx,
7321fc33bb9SClaudio Fontana     WHV_EMULATOR_MEMORY_ACCESS_INFO *ma)
7331fc33bb9SClaudio Fontana {
7341fc33bb9SClaudio Fontana     cpu_physical_memory_rw(ma->GpaAddress, ma->Data, ma->AccessSize,
7351fc33bb9SClaudio Fontana                            ma->Direction);
7361fc33bb9SClaudio Fontana     return S_OK;
7371fc33bb9SClaudio Fontana }
7381fc33bb9SClaudio Fontana 
7391fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_getreg_callback(
7401fc33bb9SClaudio Fontana     void *ctx,
7411fc33bb9SClaudio Fontana     const WHV_REGISTER_NAME *RegisterNames,
7421fc33bb9SClaudio Fontana     UINT32 RegisterCount,
7431fc33bb9SClaudio Fontana     WHV_REGISTER_VALUE *RegisterValues)
7441fc33bb9SClaudio Fontana {
7451fc33bb9SClaudio Fontana     HRESULT hr;
7461fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
7471fc33bb9SClaudio Fontana     CPUState *cpu = (CPUState *)ctx;
7481fc33bb9SClaudio Fontana 
7491fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
7501fc33bb9SClaudio Fontana         whpx->partition, cpu->cpu_index,
7511fc33bb9SClaudio Fontana         RegisterNames, RegisterCount,
7521fc33bb9SClaudio Fontana         RegisterValues);
7531fc33bb9SClaudio Fontana     if (FAILED(hr)) {
7541fc33bb9SClaudio Fontana         error_report("WHPX: Failed to get virtual processor registers,"
7551fc33bb9SClaudio Fontana                      " hr=%08lx", hr);
7561fc33bb9SClaudio Fontana     }
7571fc33bb9SClaudio Fontana 
7581fc33bb9SClaudio Fontana     return hr;
7591fc33bb9SClaudio Fontana }
7601fc33bb9SClaudio Fontana 
7611fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_setreg_callback(
7621fc33bb9SClaudio Fontana     void *ctx,
7631fc33bb9SClaudio Fontana     const WHV_REGISTER_NAME *RegisterNames,
7641fc33bb9SClaudio Fontana     UINT32 RegisterCount,
7651fc33bb9SClaudio Fontana     const WHV_REGISTER_VALUE *RegisterValues)
7661fc33bb9SClaudio Fontana {
7671fc33bb9SClaudio Fontana     HRESULT hr;
7681fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
7691fc33bb9SClaudio Fontana     CPUState *cpu = (CPUState *)ctx;
7701fc33bb9SClaudio Fontana 
7711fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
7721fc33bb9SClaudio Fontana         whpx->partition, cpu->cpu_index,
7731fc33bb9SClaudio Fontana         RegisterNames, RegisterCount,
7741fc33bb9SClaudio Fontana         RegisterValues);
7751fc33bb9SClaudio Fontana     if (FAILED(hr)) {
7761fc33bb9SClaudio Fontana         error_report("WHPX: Failed to set virtual processor registers,"
7771fc33bb9SClaudio Fontana                      " hr=%08lx", hr);
7781fc33bb9SClaudio Fontana     }
7791fc33bb9SClaudio Fontana 
7801fc33bb9SClaudio Fontana     /*
7811fc33bb9SClaudio Fontana      * The emulator just successfully wrote the register state. We clear the
7821fc33bb9SClaudio Fontana      * dirty state so we avoid the double write on resume of the VP.
7831fc33bb9SClaudio Fontana      */
7841fc33bb9SClaudio Fontana     cpu->vcpu_dirty = false;
7851fc33bb9SClaudio Fontana 
7861fc33bb9SClaudio Fontana     return hr;
7871fc33bb9SClaudio Fontana }
7881fc33bb9SClaudio Fontana 
7891fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_translate_callback(
7901fc33bb9SClaudio Fontana     void *ctx,
7911fc33bb9SClaudio Fontana     WHV_GUEST_VIRTUAL_ADDRESS Gva,
7921fc33bb9SClaudio Fontana     WHV_TRANSLATE_GVA_FLAGS TranslateFlags,
7931fc33bb9SClaudio Fontana     WHV_TRANSLATE_GVA_RESULT_CODE *TranslationResult,
7941fc33bb9SClaudio Fontana     WHV_GUEST_PHYSICAL_ADDRESS *Gpa)
7951fc33bb9SClaudio Fontana {
7961fc33bb9SClaudio Fontana     HRESULT hr;
7971fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
7981fc33bb9SClaudio Fontana     CPUState *cpu = (CPUState *)ctx;
7991fc33bb9SClaudio Fontana     WHV_TRANSLATE_GVA_RESULT res;
8001fc33bb9SClaudio Fontana 
8011fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvTranslateGva(whpx->partition, cpu->cpu_index,
8021fc33bb9SClaudio Fontana                                       Gva, TranslateFlags, &res, Gpa);
8031fc33bb9SClaudio Fontana     if (FAILED(hr)) {
8041fc33bb9SClaudio Fontana         error_report("WHPX: Failed to translate GVA, hr=%08lx", hr);
8051fc33bb9SClaudio Fontana     } else {
8061fc33bb9SClaudio Fontana         *TranslationResult = res.ResultCode;
8071fc33bb9SClaudio Fontana     }
8081fc33bb9SClaudio Fontana 
8091fc33bb9SClaudio Fontana     return hr;
8101fc33bb9SClaudio Fontana }
8111fc33bb9SClaudio Fontana 
8121fc33bb9SClaudio Fontana static const WHV_EMULATOR_CALLBACKS whpx_emu_callbacks = {
8131fc33bb9SClaudio Fontana     .Size = sizeof(WHV_EMULATOR_CALLBACKS),
8141fc33bb9SClaudio Fontana     .WHvEmulatorIoPortCallback = whpx_emu_ioport_callback,
8151fc33bb9SClaudio Fontana     .WHvEmulatorMemoryCallback = whpx_emu_mmio_callback,
8161fc33bb9SClaudio Fontana     .WHvEmulatorGetVirtualProcessorRegisters = whpx_emu_getreg_callback,
8171fc33bb9SClaudio Fontana     .WHvEmulatorSetVirtualProcessorRegisters = whpx_emu_setreg_callback,
8181fc33bb9SClaudio Fontana     .WHvEmulatorTranslateGvaPage = whpx_emu_translate_callback,
8191fc33bb9SClaudio Fontana };
8201fc33bb9SClaudio Fontana 
8211fc33bb9SClaudio Fontana static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx)
8221fc33bb9SClaudio Fontana {
8231fc33bb9SClaudio Fontana     HRESULT hr;
8241fc33bb9SClaudio Fontana     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
8251fc33bb9SClaudio Fontana     WHV_EMULATOR_STATUS emu_status;
8261fc33bb9SClaudio Fontana 
8271fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvEmulatorTryMmioEmulation(
8281fc33bb9SClaudio Fontana         vcpu->emulator, cpu,
8291fc33bb9SClaudio Fontana         &vcpu->exit_ctx.VpContext, ctx,
8301fc33bb9SClaudio Fontana         &emu_status);
8311fc33bb9SClaudio Fontana     if (FAILED(hr)) {
8321fc33bb9SClaudio Fontana         error_report("WHPX: Failed to parse MMIO access, hr=%08lx", hr);
8331fc33bb9SClaudio Fontana         return -1;
8341fc33bb9SClaudio Fontana     }
8351fc33bb9SClaudio Fontana 
8361fc33bb9SClaudio Fontana     if (!emu_status.EmulationSuccessful) {
8371fc33bb9SClaudio Fontana         error_report("WHPX: Failed to emulate MMIO access with"
8381fc33bb9SClaudio Fontana                      " EmulatorReturnStatus: %u", emu_status.AsUINT32);
8391fc33bb9SClaudio Fontana         return -1;
8401fc33bb9SClaudio Fontana     }
8411fc33bb9SClaudio Fontana 
8421fc33bb9SClaudio Fontana     return 0;
8431fc33bb9SClaudio Fontana }
8441fc33bb9SClaudio Fontana 
8451fc33bb9SClaudio Fontana static int whpx_handle_portio(CPUState *cpu,
8461fc33bb9SClaudio Fontana                               WHV_X64_IO_PORT_ACCESS_CONTEXT *ctx)
8471fc33bb9SClaudio Fontana {
8481fc33bb9SClaudio Fontana     HRESULT hr;
8491fc33bb9SClaudio Fontana     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
8501fc33bb9SClaudio Fontana     WHV_EMULATOR_STATUS emu_status;
8511fc33bb9SClaudio Fontana 
8521fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvEmulatorTryIoEmulation(
8531fc33bb9SClaudio Fontana         vcpu->emulator, cpu,
8541fc33bb9SClaudio Fontana         &vcpu->exit_ctx.VpContext, ctx,
8551fc33bb9SClaudio Fontana         &emu_status);
8561fc33bb9SClaudio Fontana     if (FAILED(hr)) {
8571fc33bb9SClaudio Fontana         error_report("WHPX: Failed to parse PortIO access, hr=%08lx", hr);
8581fc33bb9SClaudio Fontana         return -1;
8591fc33bb9SClaudio Fontana     }
8601fc33bb9SClaudio Fontana 
8611fc33bb9SClaudio Fontana     if (!emu_status.EmulationSuccessful) {
8621fc33bb9SClaudio Fontana         error_report("WHPX: Failed to emulate PortIO access with"
8631fc33bb9SClaudio Fontana                      " EmulatorReturnStatus: %u", emu_status.AsUINT32);
8641fc33bb9SClaudio Fontana         return -1;
8651fc33bb9SClaudio Fontana     }
8661fc33bb9SClaudio Fontana 
8671fc33bb9SClaudio Fontana     return 0;
8681fc33bb9SClaudio Fontana }
8691fc33bb9SClaudio Fontana 
870*d7482ffeSIvan Shcherbakov /*
871*d7482ffeSIvan Shcherbakov  * Controls whether we should intercept various exceptions on the guest,
872*d7482ffeSIvan Shcherbakov  * namely breakpoint/single-step events.
873*d7482ffeSIvan Shcherbakov  *
874*d7482ffeSIvan Shcherbakov  * The 'exceptions' argument accepts a bitmask, e.g:
875*d7482ffeSIvan Shcherbakov  * (1 << WHvX64ExceptionTypeDebugTrapOrFault) | (...)
876*d7482ffeSIvan Shcherbakov  */
877*d7482ffeSIvan Shcherbakov static HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions)
878*d7482ffeSIvan Shcherbakov {
879*d7482ffeSIvan Shcherbakov     struct whpx_state *whpx = &whpx_global;
880*d7482ffeSIvan Shcherbakov     WHV_PARTITION_PROPERTY prop = { 0, };
881*d7482ffeSIvan Shcherbakov     HRESULT hr;
882*d7482ffeSIvan Shcherbakov 
883*d7482ffeSIvan Shcherbakov     if (exceptions == whpx->exception_exit_bitmap) {
884*d7482ffeSIvan Shcherbakov         return S_OK;
885*d7482ffeSIvan Shcherbakov     }
886*d7482ffeSIvan Shcherbakov 
887*d7482ffeSIvan Shcherbakov     prop.ExceptionExitBitmap = exceptions;
888*d7482ffeSIvan Shcherbakov 
889*d7482ffeSIvan Shcherbakov     hr = whp_dispatch.WHvSetPartitionProperty(
890*d7482ffeSIvan Shcherbakov         whpx->partition,
891*d7482ffeSIvan Shcherbakov         WHvPartitionPropertyCodeExceptionExitBitmap,
892*d7482ffeSIvan Shcherbakov         &prop,
893*d7482ffeSIvan Shcherbakov         sizeof(WHV_PARTITION_PROPERTY));
894*d7482ffeSIvan Shcherbakov 
895*d7482ffeSIvan Shcherbakov     if (SUCCEEDED(hr)) {
896*d7482ffeSIvan Shcherbakov         whpx->exception_exit_bitmap = exceptions;
897*d7482ffeSIvan Shcherbakov     }
898*d7482ffeSIvan Shcherbakov 
899*d7482ffeSIvan Shcherbakov     return hr;
900*d7482ffeSIvan Shcherbakov }
901*d7482ffeSIvan Shcherbakov 
902*d7482ffeSIvan Shcherbakov 
903*d7482ffeSIvan Shcherbakov /*
904*d7482ffeSIvan Shcherbakov  * This function is called before/after stepping over a single instruction.
905*d7482ffeSIvan Shcherbakov  * It will update the CPU registers to arm/disarm the instruction stepping
906*d7482ffeSIvan Shcherbakov  * accordingly.
907*d7482ffeSIvan Shcherbakov  */
908*d7482ffeSIvan Shcherbakov static HRESULT whpx_vcpu_configure_single_stepping(CPUState *cpu,
909*d7482ffeSIvan Shcherbakov     bool set,
910*d7482ffeSIvan Shcherbakov     uint64_t *exit_context_rflags)
911*d7482ffeSIvan Shcherbakov {
912*d7482ffeSIvan Shcherbakov     WHV_REGISTER_NAME reg_name;
913*d7482ffeSIvan Shcherbakov     WHV_REGISTER_VALUE reg_value;
914*d7482ffeSIvan Shcherbakov     HRESULT hr;
915*d7482ffeSIvan Shcherbakov     struct whpx_state *whpx = &whpx_global;
916*d7482ffeSIvan Shcherbakov 
917*d7482ffeSIvan Shcherbakov     /*
918*d7482ffeSIvan Shcherbakov      * If we are trying to step over a single instruction, we need to set the
919*d7482ffeSIvan Shcherbakov      * TF bit in rflags. Otherwise, clear it.
920*d7482ffeSIvan Shcherbakov      */
921*d7482ffeSIvan Shcherbakov     reg_name = WHvX64RegisterRflags;
922*d7482ffeSIvan Shcherbakov     hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
923*d7482ffeSIvan Shcherbakov         whpx->partition,
924*d7482ffeSIvan Shcherbakov         cpu->cpu_index,
925*d7482ffeSIvan Shcherbakov         &reg_name,
926*d7482ffeSIvan Shcherbakov         1,
927*d7482ffeSIvan Shcherbakov         &reg_value);
928*d7482ffeSIvan Shcherbakov 
929*d7482ffeSIvan Shcherbakov     if (FAILED(hr)) {
930*d7482ffeSIvan Shcherbakov         error_report("WHPX: Failed to get rflags, hr=%08lx", hr);
931*d7482ffeSIvan Shcherbakov         return hr;
932*d7482ffeSIvan Shcherbakov     }
933*d7482ffeSIvan Shcherbakov 
934*d7482ffeSIvan Shcherbakov     if (exit_context_rflags) {
935*d7482ffeSIvan Shcherbakov         assert(*exit_context_rflags == reg_value.Reg64);
936*d7482ffeSIvan Shcherbakov     }
937*d7482ffeSIvan Shcherbakov 
938*d7482ffeSIvan Shcherbakov     if (set) {
939*d7482ffeSIvan Shcherbakov         /* Raise WHvX64ExceptionTypeDebugTrapOrFault after each instruction */
940*d7482ffeSIvan Shcherbakov         reg_value.Reg64 |= TF_MASK;
941*d7482ffeSIvan Shcherbakov     } else {
942*d7482ffeSIvan Shcherbakov         reg_value.Reg64 &= ~TF_MASK;
943*d7482ffeSIvan Shcherbakov     }
944*d7482ffeSIvan Shcherbakov 
945*d7482ffeSIvan Shcherbakov     if (exit_context_rflags) {
946*d7482ffeSIvan Shcherbakov         *exit_context_rflags = reg_value.Reg64;
947*d7482ffeSIvan Shcherbakov     }
948*d7482ffeSIvan Shcherbakov 
949*d7482ffeSIvan Shcherbakov     hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
950*d7482ffeSIvan Shcherbakov         whpx->partition,
951*d7482ffeSIvan Shcherbakov         cpu->cpu_index,
952*d7482ffeSIvan Shcherbakov         &reg_name,
953*d7482ffeSIvan Shcherbakov         1,
954*d7482ffeSIvan Shcherbakov         &reg_value);
955*d7482ffeSIvan Shcherbakov 
956*d7482ffeSIvan Shcherbakov     if (FAILED(hr)) {
957*d7482ffeSIvan Shcherbakov         error_report("WHPX: Failed to set rflags,"
958*d7482ffeSIvan Shcherbakov             " hr=%08lx",
959*d7482ffeSIvan Shcherbakov             hr);
960*d7482ffeSIvan Shcherbakov         return hr;
961*d7482ffeSIvan Shcherbakov     }
962*d7482ffeSIvan Shcherbakov 
963*d7482ffeSIvan Shcherbakov     reg_name = WHvRegisterInterruptState;
964*d7482ffeSIvan Shcherbakov     reg_value.Reg64 = 0;
965*d7482ffeSIvan Shcherbakov 
966*d7482ffeSIvan Shcherbakov     /* Suspend delivery of hardware interrupts during single-stepping. */
967*d7482ffeSIvan Shcherbakov     reg_value.InterruptState.InterruptShadow = set != 0;
968*d7482ffeSIvan Shcherbakov 
969*d7482ffeSIvan Shcherbakov     hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
970*d7482ffeSIvan Shcherbakov     whpx->partition,
971*d7482ffeSIvan Shcherbakov         cpu->cpu_index,
972*d7482ffeSIvan Shcherbakov         &reg_name,
973*d7482ffeSIvan Shcherbakov         1,
974*d7482ffeSIvan Shcherbakov         &reg_value);
975*d7482ffeSIvan Shcherbakov 
976*d7482ffeSIvan Shcherbakov     if (FAILED(hr)) {
977*d7482ffeSIvan Shcherbakov         error_report("WHPX: Failed to set InterruptState,"
978*d7482ffeSIvan Shcherbakov             " hr=%08lx",
979*d7482ffeSIvan Shcherbakov             hr);
980*d7482ffeSIvan Shcherbakov         return hr;
981*d7482ffeSIvan Shcherbakov     }
982*d7482ffeSIvan Shcherbakov 
983*d7482ffeSIvan Shcherbakov     if (!set) {
984*d7482ffeSIvan Shcherbakov         /*
985*d7482ffeSIvan Shcherbakov          * We have just finished stepping over a single instruction,
986*d7482ffeSIvan Shcherbakov          * and intercepted the INT1 generated by it.
987*d7482ffeSIvan Shcherbakov          * We need to now hide the INT1 from the guest,
988*d7482ffeSIvan Shcherbakov          * as it would not be expecting it.
989*d7482ffeSIvan Shcherbakov          */
990*d7482ffeSIvan Shcherbakov 
991*d7482ffeSIvan Shcherbakov         reg_name = WHvX64RegisterPendingDebugException;
992*d7482ffeSIvan Shcherbakov         hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
993*d7482ffeSIvan Shcherbakov         whpx->partition,
994*d7482ffeSIvan Shcherbakov             cpu->cpu_index,
995*d7482ffeSIvan Shcherbakov             &reg_name,
996*d7482ffeSIvan Shcherbakov             1,
997*d7482ffeSIvan Shcherbakov             &reg_value);
998*d7482ffeSIvan Shcherbakov 
999*d7482ffeSIvan Shcherbakov         if (FAILED(hr)) {
1000*d7482ffeSIvan Shcherbakov             error_report("WHPX: Failed to get pending debug exceptions,"
1001*d7482ffeSIvan Shcherbakov                          "hr=%08lx", hr);
1002*d7482ffeSIvan Shcherbakov             return hr;
1003*d7482ffeSIvan Shcherbakov         }
1004*d7482ffeSIvan Shcherbakov 
1005*d7482ffeSIvan Shcherbakov         if (reg_value.PendingDebugException.SingleStep) {
1006*d7482ffeSIvan Shcherbakov             reg_value.PendingDebugException.SingleStep = 0;
1007*d7482ffeSIvan Shcherbakov 
1008*d7482ffeSIvan Shcherbakov             hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
1009*d7482ffeSIvan Shcherbakov                 whpx->partition,
1010*d7482ffeSIvan Shcherbakov                 cpu->cpu_index,
1011*d7482ffeSIvan Shcherbakov                 &reg_name,
1012*d7482ffeSIvan Shcherbakov                 1,
1013*d7482ffeSIvan Shcherbakov                 &reg_value);
1014*d7482ffeSIvan Shcherbakov 
1015*d7482ffeSIvan Shcherbakov             if (FAILED(hr)) {
1016*d7482ffeSIvan Shcherbakov                 error_report("WHPX: Failed to clear pending debug exceptions,"
1017*d7482ffeSIvan Shcherbakov                              "hr=%08lx", hr);
1018*d7482ffeSIvan Shcherbakov              return hr;
1019*d7482ffeSIvan Shcherbakov             }
1020*d7482ffeSIvan Shcherbakov         }
1021*d7482ffeSIvan Shcherbakov 
1022*d7482ffeSIvan Shcherbakov     }
1023*d7482ffeSIvan Shcherbakov 
1024*d7482ffeSIvan Shcherbakov     return S_OK;
1025*d7482ffeSIvan Shcherbakov }
1026*d7482ffeSIvan Shcherbakov 
1027*d7482ffeSIvan Shcherbakov /* Tries to find a breakpoint at the specified address. */
1028*d7482ffeSIvan Shcherbakov static struct whpx_breakpoint *whpx_lookup_breakpoint_by_addr(uint64_t address)
1029*d7482ffeSIvan Shcherbakov {
1030*d7482ffeSIvan Shcherbakov     struct whpx_state *whpx = &whpx_global;
1031*d7482ffeSIvan Shcherbakov     int i;
1032*d7482ffeSIvan Shcherbakov 
1033*d7482ffeSIvan Shcherbakov     if (whpx->breakpoints.breakpoints) {
1034*d7482ffeSIvan Shcherbakov         for (i = 0; i < whpx->breakpoints.breakpoints->used; i++) {
1035*d7482ffeSIvan Shcherbakov             if (address == whpx->breakpoints.breakpoints->data[i].address) {
1036*d7482ffeSIvan Shcherbakov                 return &whpx->breakpoints.breakpoints->data[i];
1037*d7482ffeSIvan Shcherbakov             }
1038*d7482ffeSIvan Shcherbakov         }
1039*d7482ffeSIvan Shcherbakov     }
1040*d7482ffeSIvan Shcherbakov 
1041*d7482ffeSIvan Shcherbakov     return NULL;
1042*d7482ffeSIvan Shcherbakov }
1043*d7482ffeSIvan Shcherbakov 
1044*d7482ffeSIvan Shcherbakov /*
1045*d7482ffeSIvan Shcherbakov  * Linux uses int3 (0xCC) during startup (see int3_selftest()) and for
1046*d7482ffeSIvan Shcherbakov  * debugging user-mode applications. Since the WHPX API does not offer
1047*d7482ffeSIvan Shcherbakov  * an easy way to pass the intercepted exception back to the guest, we
1048*d7482ffeSIvan Shcherbakov  * resort to using INT1 instead, and let the guest always handle INT3.
1049*d7482ffeSIvan Shcherbakov  */
1050*d7482ffeSIvan Shcherbakov static const uint8_t whpx_breakpoint_instruction = 0xF1;
1051*d7482ffeSIvan Shcherbakov 
1052*d7482ffeSIvan Shcherbakov /*
1053*d7482ffeSIvan Shcherbakov  * The WHPX QEMU backend implements breakpoints by writing the INT1
1054*d7482ffeSIvan Shcherbakov  * instruction into memory (ignoring the DRx registers). This raises a few
1055*d7482ffeSIvan Shcherbakov  * issues that need to be carefully handled:
1056*d7482ffeSIvan Shcherbakov  *
1057*d7482ffeSIvan Shcherbakov  * 1. Although unlikely, other parts of QEMU may set multiple breakpoints
1058*d7482ffeSIvan Shcherbakov  *    at the same location, and later remove them in arbitrary order.
1059*d7482ffeSIvan Shcherbakov  *    This should not cause memory corruption, and should only remove the
1060*d7482ffeSIvan Shcherbakov  *    physical breakpoint instruction when the last QEMU breakpoint is gone.
1061*d7482ffeSIvan Shcherbakov  *
1062*d7482ffeSIvan Shcherbakov  * 2. Writing arbitrary virtual memory may fail if it's not mapped to a valid
1063*d7482ffeSIvan Shcherbakov  *    physical location. Hence, physically adding/removing a breakpoint can
1064*d7482ffeSIvan Shcherbakov  *    theoretically fail at any time. We need to keep track of it.
1065*d7482ffeSIvan Shcherbakov  *
1066*d7482ffeSIvan Shcherbakov  * The function below rebuilds a list of low-level breakpoints (one per
1067*d7482ffeSIvan Shcherbakov  * address, tracking the original instruction and any errors) from the list of
1068*d7482ffeSIvan Shcherbakov  * high-level breakpoints (set via cpu_breakpoint_insert()).
1069*d7482ffeSIvan Shcherbakov  *
1070*d7482ffeSIvan Shcherbakov  * In order to optimize performance, this function stores the list of
1071*d7482ffeSIvan Shcherbakov  * high-level breakpoints (a.k.a. CPU breakpoints) used to compute the
1072*d7482ffeSIvan Shcherbakov  * low-level ones, so that it won't be re-invoked until these breakpoints
1073*d7482ffeSIvan Shcherbakov  * change.
1074*d7482ffeSIvan Shcherbakov  *
1075*d7482ffeSIvan Shcherbakov  * Note that this function decides which breakpoints should be inserted into,
1076*d7482ffeSIvan Shcherbakov  * memory, but doesn't actually do it. The memory accessing is done in
1077*d7482ffeSIvan Shcherbakov  * whpx_apply_breakpoints().
1078*d7482ffeSIvan Shcherbakov  */
1079*d7482ffeSIvan Shcherbakov static void whpx_translate_cpu_breakpoints(
1080*d7482ffeSIvan Shcherbakov     struct whpx_breakpoints *breakpoints,
1081*d7482ffeSIvan Shcherbakov     CPUState *cpu,
1082*d7482ffeSIvan Shcherbakov     int cpu_breakpoint_count)
1083*d7482ffeSIvan Shcherbakov {
1084*d7482ffeSIvan Shcherbakov     CPUBreakpoint *bp;
1085*d7482ffeSIvan Shcherbakov     int cpu_bp_index = 0;
1086*d7482ffeSIvan Shcherbakov 
1087*d7482ffeSIvan Shcherbakov     breakpoints->original_addresses =
1088*d7482ffeSIvan Shcherbakov         g_renew(vaddr, breakpoints->original_addresses, cpu_breakpoint_count);
1089*d7482ffeSIvan Shcherbakov 
1090*d7482ffeSIvan Shcherbakov     breakpoints->original_address_count = cpu_breakpoint_count;
1091*d7482ffeSIvan Shcherbakov 
1092*d7482ffeSIvan Shcherbakov     int max_breakpoints = cpu_breakpoint_count +
1093*d7482ffeSIvan Shcherbakov         (breakpoints->breakpoints ? breakpoints->breakpoints->used : 0);
1094*d7482ffeSIvan Shcherbakov 
1095*d7482ffeSIvan Shcherbakov     struct whpx_breakpoint_collection *new_breakpoints =
1096*d7482ffeSIvan Shcherbakov         (struct whpx_breakpoint_collection *)g_malloc0(
1097*d7482ffeSIvan Shcherbakov         sizeof(struct whpx_breakpoint_collection) +
1098*d7482ffeSIvan Shcherbakov             max_breakpoints * sizeof(struct whpx_breakpoint));
1099*d7482ffeSIvan Shcherbakov 
1100*d7482ffeSIvan Shcherbakov     new_breakpoints->allocated = max_breakpoints;
1101*d7482ffeSIvan Shcherbakov     new_breakpoints->used = 0;
1102*d7482ffeSIvan Shcherbakov 
1103*d7482ffeSIvan Shcherbakov     /*
1104*d7482ffeSIvan Shcherbakov      * 1. Preserve all old breakpoints that could not be automatically
1105*d7482ffeSIvan Shcherbakov      * cleared when the CPU got stopped.
1106*d7482ffeSIvan Shcherbakov      */
1107*d7482ffeSIvan Shcherbakov     if (breakpoints->breakpoints) {
1108*d7482ffeSIvan Shcherbakov         int i;
1109*d7482ffeSIvan Shcherbakov         for (i = 0; i < breakpoints->breakpoints->used; i++) {
1110*d7482ffeSIvan Shcherbakov             if (breakpoints->breakpoints->data[i].state != WHPX_BP_CLEARED) {
1111*d7482ffeSIvan Shcherbakov                 new_breakpoints->data[new_breakpoints->used++] =
1112*d7482ffeSIvan Shcherbakov                     breakpoints->breakpoints->data[i];
1113*d7482ffeSIvan Shcherbakov             }
1114*d7482ffeSIvan Shcherbakov         }
1115*d7482ffeSIvan Shcherbakov     }
1116*d7482ffeSIvan Shcherbakov 
1117*d7482ffeSIvan Shcherbakov     /* 2. Map all CPU breakpoints to WHPX breakpoints */
1118*d7482ffeSIvan Shcherbakov     QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
1119*d7482ffeSIvan Shcherbakov         int i;
1120*d7482ffeSIvan Shcherbakov         bool found = false;
1121*d7482ffeSIvan Shcherbakov 
1122*d7482ffeSIvan Shcherbakov         /* This will be used to detect changed CPU breakpoints later. */
1123*d7482ffeSIvan Shcherbakov         breakpoints->original_addresses[cpu_bp_index++] = bp->pc;
1124*d7482ffeSIvan Shcherbakov 
1125*d7482ffeSIvan Shcherbakov         for (i = 0; i < new_breakpoints->used; i++) {
1126*d7482ffeSIvan Shcherbakov             /*
1127*d7482ffeSIvan Shcherbakov              * WARNING: This loop has O(N^2) complexity, where N is the
1128*d7482ffeSIvan Shcherbakov              * number of breakpoints. It should not be a bottleneck in
1129*d7482ffeSIvan Shcherbakov              * real-world scenarios, since it only needs to run once after
1130*d7482ffeSIvan Shcherbakov              * the breakpoints have been modified.
1131*d7482ffeSIvan Shcherbakov              * If this ever becomes a concern, it can be optimized by storing
1132*d7482ffeSIvan Shcherbakov              * high-level breakpoint objects in a tree or hash map.
1133*d7482ffeSIvan Shcherbakov              */
1134*d7482ffeSIvan Shcherbakov 
1135*d7482ffeSIvan Shcherbakov             if (new_breakpoints->data[i].address == bp->pc) {
1136*d7482ffeSIvan Shcherbakov                 /* There was already a breakpoint at this address. */
1137*d7482ffeSIvan Shcherbakov                 if (new_breakpoints->data[i].state == WHPX_BP_CLEAR_PENDING) {
1138*d7482ffeSIvan Shcherbakov                     new_breakpoints->data[i].state = WHPX_BP_SET;
1139*d7482ffeSIvan Shcherbakov                 } else if (new_breakpoints->data[i].state == WHPX_BP_SET) {
1140*d7482ffeSIvan Shcherbakov                     new_breakpoints->data[i].state = WHPX_BP_SET_PENDING;
1141*d7482ffeSIvan Shcherbakov                 }
1142*d7482ffeSIvan Shcherbakov 
1143*d7482ffeSIvan Shcherbakov                 found = true;
1144*d7482ffeSIvan Shcherbakov                 break;
1145*d7482ffeSIvan Shcherbakov             }
1146*d7482ffeSIvan Shcherbakov         }
1147*d7482ffeSIvan Shcherbakov 
1148*d7482ffeSIvan Shcherbakov         if (!found && new_breakpoints->used < new_breakpoints->allocated) {
1149*d7482ffeSIvan Shcherbakov             /* No WHPX breakpoint at this address. Create one. */
1150*d7482ffeSIvan Shcherbakov             new_breakpoints->data[new_breakpoints->used].address = bp->pc;
1151*d7482ffeSIvan Shcherbakov             new_breakpoints->data[new_breakpoints->used].state =
1152*d7482ffeSIvan Shcherbakov                 WHPX_BP_SET_PENDING;
1153*d7482ffeSIvan Shcherbakov             new_breakpoints->used++;
1154*d7482ffeSIvan Shcherbakov         }
1155*d7482ffeSIvan Shcherbakov     }
1156*d7482ffeSIvan Shcherbakov 
1157*d7482ffeSIvan Shcherbakov     if (breakpoints->breakpoints) {
1158*d7482ffeSIvan Shcherbakov         /*
1159*d7482ffeSIvan Shcherbakov          * Free the previous breakpoint list. This can be optimized by keeping
1160*d7482ffeSIvan Shcherbakov          * it as shadow buffer for the next computation instead of freeing
1161*d7482ffeSIvan Shcherbakov          * it immediately.
1162*d7482ffeSIvan Shcherbakov          */
1163*d7482ffeSIvan Shcherbakov         g_free(breakpoints->breakpoints);
1164*d7482ffeSIvan Shcherbakov     }
1165*d7482ffeSIvan Shcherbakov 
1166*d7482ffeSIvan Shcherbakov     breakpoints->breakpoints = new_breakpoints;
1167*d7482ffeSIvan Shcherbakov }
1168*d7482ffeSIvan Shcherbakov 
1169*d7482ffeSIvan Shcherbakov /*
1170*d7482ffeSIvan Shcherbakov  * Physically inserts/removes the breakpoints by reading and writing the
1171*d7482ffeSIvan Shcherbakov  * physical memory, keeping a track of the failed attempts.
1172*d7482ffeSIvan Shcherbakov  *
1173*d7482ffeSIvan Shcherbakov  * Passing resuming=true  will try to set all previously unset breakpoints.
1174*d7482ffeSIvan Shcherbakov  * Passing resuming=false will remove all inserted ones.
1175*d7482ffeSIvan Shcherbakov  */
1176*d7482ffeSIvan Shcherbakov static void whpx_apply_breakpoints(
1177*d7482ffeSIvan Shcherbakov     struct whpx_breakpoint_collection *breakpoints,
1178*d7482ffeSIvan Shcherbakov     CPUState *cpu,
1179*d7482ffeSIvan Shcherbakov     bool resuming)
1180*d7482ffeSIvan Shcherbakov {
1181*d7482ffeSIvan Shcherbakov     int i, rc;
1182*d7482ffeSIvan Shcherbakov     if (!breakpoints) {
1183*d7482ffeSIvan Shcherbakov         return;
1184*d7482ffeSIvan Shcherbakov     }
1185*d7482ffeSIvan Shcherbakov 
1186*d7482ffeSIvan Shcherbakov     for (i = 0; i < breakpoints->used; i++) {
1187*d7482ffeSIvan Shcherbakov         /* Decide what to do right now based on the last known state. */
1188*d7482ffeSIvan Shcherbakov         WhpxBreakpointState state = breakpoints->data[i].state;
1189*d7482ffeSIvan Shcherbakov         switch (state) {
1190*d7482ffeSIvan Shcherbakov         case WHPX_BP_CLEARED:
1191*d7482ffeSIvan Shcherbakov             if (resuming) {
1192*d7482ffeSIvan Shcherbakov                 state = WHPX_BP_SET_PENDING;
1193*d7482ffeSIvan Shcherbakov             }
1194*d7482ffeSIvan Shcherbakov             break;
1195*d7482ffeSIvan Shcherbakov         case WHPX_BP_SET_PENDING:
1196*d7482ffeSIvan Shcherbakov             if (!resuming) {
1197*d7482ffeSIvan Shcherbakov                 state = WHPX_BP_CLEARED;
1198*d7482ffeSIvan Shcherbakov             }
1199*d7482ffeSIvan Shcherbakov             break;
1200*d7482ffeSIvan Shcherbakov         case WHPX_BP_SET:
1201*d7482ffeSIvan Shcherbakov             if (!resuming) {
1202*d7482ffeSIvan Shcherbakov                 state = WHPX_BP_CLEAR_PENDING;
1203*d7482ffeSIvan Shcherbakov             }
1204*d7482ffeSIvan Shcherbakov             break;
1205*d7482ffeSIvan Shcherbakov         case WHPX_BP_CLEAR_PENDING:
1206*d7482ffeSIvan Shcherbakov             if (resuming) {
1207*d7482ffeSIvan Shcherbakov                 state = WHPX_BP_SET;
1208*d7482ffeSIvan Shcherbakov             }
1209*d7482ffeSIvan Shcherbakov             break;
1210*d7482ffeSIvan Shcherbakov         }
1211*d7482ffeSIvan Shcherbakov 
1212*d7482ffeSIvan Shcherbakov         if (state == WHPX_BP_SET_PENDING) {
1213*d7482ffeSIvan Shcherbakov             /* Remember the original instruction. */
1214*d7482ffeSIvan Shcherbakov             rc = cpu_memory_rw_debug(cpu,
1215*d7482ffeSIvan Shcherbakov                 breakpoints->data[i].address,
1216*d7482ffeSIvan Shcherbakov                 &breakpoints->data[i].original_instruction,
1217*d7482ffeSIvan Shcherbakov                 1,
1218*d7482ffeSIvan Shcherbakov                 false);
1219*d7482ffeSIvan Shcherbakov 
1220*d7482ffeSIvan Shcherbakov             if (!rc) {
1221*d7482ffeSIvan Shcherbakov                 /* Write the breakpoint instruction. */
1222*d7482ffeSIvan Shcherbakov                 rc = cpu_memory_rw_debug(cpu,
1223*d7482ffeSIvan Shcherbakov                     breakpoints->data[i].address,
1224*d7482ffeSIvan Shcherbakov                     (void *)&whpx_breakpoint_instruction,
1225*d7482ffeSIvan Shcherbakov                     1,
1226*d7482ffeSIvan Shcherbakov                     true);
1227*d7482ffeSIvan Shcherbakov             }
1228*d7482ffeSIvan Shcherbakov 
1229*d7482ffeSIvan Shcherbakov             if (!rc) {
1230*d7482ffeSIvan Shcherbakov                 state = WHPX_BP_SET;
1231*d7482ffeSIvan Shcherbakov             }
1232*d7482ffeSIvan Shcherbakov 
1233*d7482ffeSIvan Shcherbakov         }
1234*d7482ffeSIvan Shcherbakov 
1235*d7482ffeSIvan Shcherbakov         if (state == WHPX_BP_CLEAR_PENDING) {
1236*d7482ffeSIvan Shcherbakov             /* Restore the original instruction. */
1237*d7482ffeSIvan Shcherbakov             rc = cpu_memory_rw_debug(cpu,
1238*d7482ffeSIvan Shcherbakov                 breakpoints->data[i].address,
1239*d7482ffeSIvan Shcherbakov                 &breakpoints->data[i].original_instruction,
1240*d7482ffeSIvan Shcherbakov                 1,
1241*d7482ffeSIvan Shcherbakov                 true);
1242*d7482ffeSIvan Shcherbakov 
1243*d7482ffeSIvan Shcherbakov             if (!rc) {
1244*d7482ffeSIvan Shcherbakov                 state = WHPX_BP_CLEARED;
1245*d7482ffeSIvan Shcherbakov             }
1246*d7482ffeSIvan Shcherbakov         }
1247*d7482ffeSIvan Shcherbakov 
1248*d7482ffeSIvan Shcherbakov         breakpoints->data[i].state = state;
1249*d7482ffeSIvan Shcherbakov     }
1250*d7482ffeSIvan Shcherbakov }
1251*d7482ffeSIvan Shcherbakov 
1252*d7482ffeSIvan Shcherbakov /*
1253*d7482ffeSIvan Shcherbakov  * This function is called when the a VCPU is about to start and no other
1254*d7482ffeSIvan Shcherbakov  * VCPUs have been started so far. Since the VCPU start order could be
1255*d7482ffeSIvan Shcherbakov  * arbitrary, it doesn't have to be VCPU#0.
1256*d7482ffeSIvan Shcherbakov  *
1257*d7482ffeSIvan Shcherbakov  * It is used to commit the breakpoints into memory, and configure WHPX
1258*d7482ffeSIvan Shcherbakov  * to intercept debug exceptions.
1259*d7482ffeSIvan Shcherbakov  *
1260*d7482ffeSIvan Shcherbakov  * Note that whpx_set_exception_exit_bitmap() cannot be called if one or
1261*d7482ffeSIvan Shcherbakov  * more VCPUs are already running, so this is the best place to do it.
1262*d7482ffeSIvan Shcherbakov  */
1263*d7482ffeSIvan Shcherbakov static int whpx_first_vcpu_starting(CPUState *cpu)
1264*d7482ffeSIvan Shcherbakov {
1265*d7482ffeSIvan Shcherbakov     struct whpx_state *whpx = &whpx_global;
1266*d7482ffeSIvan Shcherbakov     HRESULT hr;
1267*d7482ffeSIvan Shcherbakov 
1268*d7482ffeSIvan Shcherbakov     g_assert(qemu_mutex_iothread_locked());
1269*d7482ffeSIvan Shcherbakov 
1270*d7482ffeSIvan Shcherbakov     if (!QTAILQ_EMPTY(&cpu->breakpoints) ||
1271*d7482ffeSIvan Shcherbakov             (whpx->breakpoints.breakpoints &&
1272*d7482ffeSIvan Shcherbakov              whpx->breakpoints.breakpoints->used)) {
1273*d7482ffeSIvan Shcherbakov         CPUBreakpoint *bp;
1274*d7482ffeSIvan Shcherbakov         int i = 0;
1275*d7482ffeSIvan Shcherbakov         bool update_pending = false;
1276*d7482ffeSIvan Shcherbakov 
1277*d7482ffeSIvan Shcherbakov         QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
1278*d7482ffeSIvan Shcherbakov             if (i >= whpx->breakpoints.original_address_count ||
1279*d7482ffeSIvan Shcherbakov                 bp->pc != whpx->breakpoints.original_addresses[i]) {
1280*d7482ffeSIvan Shcherbakov                 update_pending = true;
1281*d7482ffeSIvan Shcherbakov             }
1282*d7482ffeSIvan Shcherbakov 
1283*d7482ffeSIvan Shcherbakov             i++;
1284*d7482ffeSIvan Shcherbakov         }
1285*d7482ffeSIvan Shcherbakov 
1286*d7482ffeSIvan Shcherbakov         if (i != whpx->breakpoints.original_address_count) {
1287*d7482ffeSIvan Shcherbakov             update_pending = true;
1288*d7482ffeSIvan Shcherbakov         }
1289*d7482ffeSIvan Shcherbakov 
1290*d7482ffeSIvan Shcherbakov         if (update_pending) {
1291*d7482ffeSIvan Shcherbakov             /*
1292*d7482ffeSIvan Shcherbakov              * The CPU breakpoints have changed since the last call to
1293*d7482ffeSIvan Shcherbakov              * whpx_translate_cpu_breakpoints(). WHPX breakpoints must
1294*d7482ffeSIvan Shcherbakov              * now be recomputed.
1295*d7482ffeSIvan Shcherbakov              */
1296*d7482ffeSIvan Shcherbakov             whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i);
1297*d7482ffeSIvan Shcherbakov         }
1298*d7482ffeSIvan Shcherbakov 
1299*d7482ffeSIvan Shcherbakov         /* Actually insert the breakpoints into the memory. */
1300*d7482ffeSIvan Shcherbakov         whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true);
1301*d7482ffeSIvan Shcherbakov     }
1302*d7482ffeSIvan Shcherbakov 
1303*d7482ffeSIvan Shcherbakov     uint64_t exception_mask;
1304*d7482ffeSIvan Shcherbakov     if (whpx->step_pending ||
1305*d7482ffeSIvan Shcherbakov         (whpx->breakpoints.breakpoints &&
1306*d7482ffeSIvan Shcherbakov          whpx->breakpoints.breakpoints->used)) {
1307*d7482ffeSIvan Shcherbakov         /*
1308*d7482ffeSIvan Shcherbakov          * We are either attempting to single-step one or more CPUs, or
1309*d7482ffeSIvan Shcherbakov          * have one or more breakpoints enabled. Both require intercepting
1310*d7482ffeSIvan Shcherbakov          * the WHvX64ExceptionTypeBreakpointTrap exception.
1311*d7482ffeSIvan Shcherbakov          */
1312*d7482ffeSIvan Shcherbakov 
1313*d7482ffeSIvan Shcherbakov         exception_mask = 1UL << WHvX64ExceptionTypeDebugTrapOrFault;
1314*d7482ffeSIvan Shcherbakov     } else {
1315*d7482ffeSIvan Shcherbakov         /* Let the guest handle all exceptions. */
1316*d7482ffeSIvan Shcherbakov         exception_mask = 0;
1317*d7482ffeSIvan Shcherbakov     }
1318*d7482ffeSIvan Shcherbakov 
1319*d7482ffeSIvan Shcherbakov     hr = whpx_set_exception_exit_bitmap(exception_mask);
1320*d7482ffeSIvan Shcherbakov     if (!SUCCEEDED(hr)) {
1321*d7482ffeSIvan Shcherbakov         error_report("WHPX: Failed to update exception exit mask,"
1322*d7482ffeSIvan Shcherbakov                      "hr=%08lx.", hr);
1323*d7482ffeSIvan Shcherbakov         return 1;
1324*d7482ffeSIvan Shcherbakov     }
1325*d7482ffeSIvan Shcherbakov 
1326*d7482ffeSIvan Shcherbakov     return 0;
1327*d7482ffeSIvan Shcherbakov }
1328*d7482ffeSIvan Shcherbakov 
1329*d7482ffeSIvan Shcherbakov /*
1330*d7482ffeSIvan Shcherbakov  * This function is called when the last VCPU has finished running.
1331*d7482ffeSIvan Shcherbakov  * It is used to remove any previously set breakpoints from memory.
1332*d7482ffeSIvan Shcherbakov  */
1333*d7482ffeSIvan Shcherbakov static int whpx_last_vcpu_stopping(CPUState *cpu)
1334*d7482ffeSIvan Shcherbakov {
1335*d7482ffeSIvan Shcherbakov     whpx_apply_breakpoints(whpx_global.breakpoints.breakpoints, cpu, false);
1336*d7482ffeSIvan Shcherbakov     return 0;
1337*d7482ffeSIvan Shcherbakov }
1338*d7482ffeSIvan Shcherbakov 
1339*d7482ffeSIvan Shcherbakov /* Returns the address of the next instruction that is about to be executed. */
1340*d7482ffeSIvan Shcherbakov static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid)
1341*d7482ffeSIvan Shcherbakov {
1342*d7482ffeSIvan Shcherbakov     if (cpu->vcpu_dirty) {
1343*d7482ffeSIvan Shcherbakov         /* The CPU registers have been modified by other parts of QEMU. */
1344*d7482ffeSIvan Shcherbakov         CPUArchState *env = (CPUArchState *)(cpu->env_ptr);
1345*d7482ffeSIvan Shcherbakov         return env->eip;
1346*d7482ffeSIvan Shcherbakov     } else if (exit_context_valid) {
1347*d7482ffeSIvan Shcherbakov         /*
1348*d7482ffeSIvan Shcherbakov          * The CPU registers have not been modified by neither other parts
1349*d7482ffeSIvan Shcherbakov          * of QEMU, nor this port by calling WHvSetVirtualProcessorRegisters().
1350*d7482ffeSIvan Shcherbakov          * This is the most common case.
1351*d7482ffeSIvan Shcherbakov          */
1352*d7482ffeSIvan Shcherbakov         struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
1353*d7482ffeSIvan Shcherbakov         return vcpu->exit_ctx.VpContext.Rip;
1354*d7482ffeSIvan Shcherbakov     } else {
1355*d7482ffeSIvan Shcherbakov         /*
1356*d7482ffeSIvan Shcherbakov          * The CPU registers have been modified by a call to
1357*d7482ffeSIvan Shcherbakov          * WHvSetVirtualProcessorRegisters() and must be re-queried from
1358*d7482ffeSIvan Shcherbakov          * the target.
1359*d7482ffeSIvan Shcherbakov          */
1360*d7482ffeSIvan Shcherbakov         WHV_REGISTER_VALUE reg_value;
1361*d7482ffeSIvan Shcherbakov         WHV_REGISTER_NAME reg_name = WHvX64RegisterRip;
1362*d7482ffeSIvan Shcherbakov         HRESULT hr;
1363*d7482ffeSIvan Shcherbakov         struct whpx_state *whpx = &whpx_global;
1364*d7482ffeSIvan Shcherbakov 
1365*d7482ffeSIvan Shcherbakov         hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
1366*d7482ffeSIvan Shcherbakov             whpx->partition,
1367*d7482ffeSIvan Shcherbakov             cpu->cpu_index,
1368*d7482ffeSIvan Shcherbakov             &reg_name,
1369*d7482ffeSIvan Shcherbakov             1,
1370*d7482ffeSIvan Shcherbakov             &reg_value);
1371*d7482ffeSIvan Shcherbakov 
1372*d7482ffeSIvan Shcherbakov         if (FAILED(hr)) {
1373*d7482ffeSIvan Shcherbakov             error_report("WHPX: Failed to get PC, hr=%08lx", hr);
1374*d7482ffeSIvan Shcherbakov             return 0;
1375*d7482ffeSIvan Shcherbakov         }
1376*d7482ffeSIvan Shcherbakov 
1377*d7482ffeSIvan Shcherbakov         return reg_value.Reg64;
1378*d7482ffeSIvan Shcherbakov     }
1379*d7482ffeSIvan Shcherbakov }
1380*d7482ffeSIvan Shcherbakov 
13811fc33bb9SClaudio Fontana static int whpx_handle_halt(CPUState *cpu)
13821fc33bb9SClaudio Fontana {
138395e862d7SPhilippe Mathieu-Daudé     CPUX86State *env = cpu->env_ptr;
13841fc33bb9SClaudio Fontana     int ret = 0;
13851fc33bb9SClaudio Fontana 
13861fc33bb9SClaudio Fontana     qemu_mutex_lock_iothread();
13871fc33bb9SClaudio Fontana     if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
13881fc33bb9SClaudio Fontana           (env->eflags & IF_MASK)) &&
13891fc33bb9SClaudio Fontana         !(cpu->interrupt_request & CPU_INTERRUPT_NMI)) {
13901fc33bb9SClaudio Fontana         cpu->exception_index = EXCP_HLT;
13911fc33bb9SClaudio Fontana         cpu->halted = true;
13921fc33bb9SClaudio Fontana         ret = 1;
13931fc33bb9SClaudio Fontana     }
13941fc33bb9SClaudio Fontana     qemu_mutex_unlock_iothread();
13951fc33bb9SClaudio Fontana 
13961fc33bb9SClaudio Fontana     return ret;
13971fc33bb9SClaudio Fontana }
13981fc33bb9SClaudio Fontana 
13991fc33bb9SClaudio Fontana static void whpx_vcpu_pre_run(CPUState *cpu)
14001fc33bb9SClaudio Fontana {
14011fc33bb9SClaudio Fontana     HRESULT hr;
14021fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
14031fc33bb9SClaudio Fontana     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
140495e862d7SPhilippe Mathieu-Daudé     CPUX86State *env = cpu->env_ptr;
14051fc33bb9SClaudio Fontana     X86CPU *x86_cpu = X86_CPU(cpu);
14061fc33bb9SClaudio Fontana     int irq;
14071fc33bb9SClaudio Fontana     uint8_t tpr;
14081fc33bb9SClaudio Fontana     WHV_X64_PENDING_INTERRUPTION_REGISTER new_int;
14091fc33bb9SClaudio Fontana     UINT32 reg_count = 0;
14101fc33bb9SClaudio Fontana     WHV_REGISTER_VALUE reg_values[3];
14111fc33bb9SClaudio Fontana     WHV_REGISTER_NAME reg_names[3];
14121fc33bb9SClaudio Fontana 
14131fc33bb9SClaudio Fontana     memset(&new_int, 0, sizeof(new_int));
14141fc33bb9SClaudio Fontana     memset(reg_values, 0, sizeof(reg_values));
14151fc33bb9SClaudio Fontana 
14161fc33bb9SClaudio Fontana     qemu_mutex_lock_iothread();
14171fc33bb9SClaudio Fontana 
14181fc33bb9SClaudio Fontana     /* Inject NMI */
14191fc33bb9SClaudio Fontana     if (!vcpu->interruption_pending &&
14201fc33bb9SClaudio Fontana         cpu->interrupt_request & (CPU_INTERRUPT_NMI | CPU_INTERRUPT_SMI)) {
14211fc33bb9SClaudio Fontana         if (cpu->interrupt_request & CPU_INTERRUPT_NMI) {
14221fc33bb9SClaudio Fontana             cpu->interrupt_request &= ~CPU_INTERRUPT_NMI;
14231fc33bb9SClaudio Fontana             vcpu->interruptable = false;
14241fc33bb9SClaudio Fontana             new_int.InterruptionType = WHvX64PendingNmi;
14251fc33bb9SClaudio Fontana             new_int.InterruptionPending = 1;
14261fc33bb9SClaudio Fontana             new_int.InterruptionVector = 2;
14271fc33bb9SClaudio Fontana         }
14281fc33bb9SClaudio Fontana         if (cpu->interrupt_request & CPU_INTERRUPT_SMI) {
14291fc33bb9SClaudio Fontana             cpu->interrupt_request &= ~CPU_INTERRUPT_SMI;
14301fc33bb9SClaudio Fontana         }
14311fc33bb9SClaudio Fontana     }
14321fc33bb9SClaudio Fontana 
14331fc33bb9SClaudio Fontana     /*
14341fc33bb9SClaudio Fontana      * Force the VCPU out of its inner loop to process any INIT requests or
14351fc33bb9SClaudio Fontana      * commit pending TPR access.
14361fc33bb9SClaudio Fontana      */
14371fc33bb9SClaudio Fontana     if (cpu->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) {
14381fc33bb9SClaudio Fontana         if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) &&
14391fc33bb9SClaudio Fontana             !(env->hflags & HF_SMM_MASK)) {
14401fc33bb9SClaudio Fontana             cpu->exit_request = 1;
14411fc33bb9SClaudio Fontana         }
14421fc33bb9SClaudio Fontana         if (cpu->interrupt_request & CPU_INTERRUPT_TPR) {
14431fc33bb9SClaudio Fontana             cpu->exit_request = 1;
14441fc33bb9SClaudio Fontana         }
14451fc33bb9SClaudio Fontana     }
14461fc33bb9SClaudio Fontana 
14471fc33bb9SClaudio Fontana     /* Get pending hard interruption or replay one that was overwritten */
14481fc33bb9SClaudio Fontana     if (!whpx_apic_in_platform()) {
14491fc33bb9SClaudio Fontana         if (!vcpu->interruption_pending &&
14501fc33bb9SClaudio Fontana             vcpu->interruptable && (env->eflags & IF_MASK)) {
14511fc33bb9SClaudio Fontana             assert(!new_int.InterruptionPending);
14521fc33bb9SClaudio Fontana             if (cpu->interrupt_request & CPU_INTERRUPT_HARD) {
14531fc33bb9SClaudio Fontana                 cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
14541fc33bb9SClaudio Fontana                 irq = cpu_get_pic_interrupt(env);
14551fc33bb9SClaudio Fontana                 if (irq >= 0) {
14561fc33bb9SClaudio Fontana                     new_int.InterruptionType = WHvX64PendingInterrupt;
14571fc33bb9SClaudio Fontana                     new_int.InterruptionPending = 1;
14581fc33bb9SClaudio Fontana                     new_int.InterruptionVector = irq;
14591fc33bb9SClaudio Fontana                 }
14601fc33bb9SClaudio Fontana             }
14611fc33bb9SClaudio Fontana         }
14621fc33bb9SClaudio Fontana 
14631fc33bb9SClaudio Fontana         /* Setup interrupt state if new one was prepared */
14641fc33bb9SClaudio Fontana         if (new_int.InterruptionPending) {
14651fc33bb9SClaudio Fontana             reg_values[reg_count].PendingInterruption = new_int;
14661fc33bb9SClaudio Fontana             reg_names[reg_count] = WHvRegisterPendingInterruption;
14671fc33bb9SClaudio Fontana             reg_count += 1;
14681fc33bb9SClaudio Fontana         }
14691fc33bb9SClaudio Fontana     } else if (vcpu->ready_for_pic_interrupt &&
14701fc33bb9SClaudio Fontana                (cpu->interrupt_request & CPU_INTERRUPT_HARD)) {
14711fc33bb9SClaudio Fontana         cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
14721fc33bb9SClaudio Fontana         irq = cpu_get_pic_interrupt(env);
14731fc33bb9SClaudio Fontana         if (irq >= 0) {
14741fc33bb9SClaudio Fontana             reg_names[reg_count] = WHvRegisterPendingEvent;
14751fc33bb9SClaudio Fontana             reg_values[reg_count].ExtIntEvent = (WHV_X64_PENDING_EXT_INT_EVENT)
14761fc33bb9SClaudio Fontana             {
14771fc33bb9SClaudio Fontana                 .EventPending = 1,
14781fc33bb9SClaudio Fontana                 .EventType = WHvX64PendingEventExtInt,
14791fc33bb9SClaudio Fontana                 .Vector = irq,
14801fc33bb9SClaudio Fontana             };
14811fc33bb9SClaudio Fontana             reg_count += 1;
14821fc33bb9SClaudio Fontana         }
14831fc33bb9SClaudio Fontana      }
14841fc33bb9SClaudio Fontana 
14851fc33bb9SClaudio Fontana     /* Sync the TPR to the CR8 if was modified during the intercept */
14861fc33bb9SClaudio Fontana     tpr = cpu_get_apic_tpr(x86_cpu->apic_state);
14871fc33bb9SClaudio Fontana     if (tpr != vcpu->tpr) {
14881fc33bb9SClaudio Fontana         vcpu->tpr = tpr;
14891fc33bb9SClaudio Fontana         reg_values[reg_count].Reg64 = tpr;
14901fc33bb9SClaudio Fontana         cpu->exit_request = 1;
14911fc33bb9SClaudio Fontana         reg_names[reg_count] = WHvX64RegisterCr8;
14921fc33bb9SClaudio Fontana         reg_count += 1;
14931fc33bb9SClaudio Fontana     }
14941fc33bb9SClaudio Fontana 
14951fc33bb9SClaudio Fontana     /* Update the state of the interrupt delivery notification */
14961fc33bb9SClaudio Fontana     if (!vcpu->window_registered &&
14971fc33bb9SClaudio Fontana         cpu->interrupt_request & CPU_INTERRUPT_HARD) {
14981fc33bb9SClaudio Fontana         reg_values[reg_count].DeliverabilityNotifications =
14991fc33bb9SClaudio Fontana             (WHV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER) {
15001fc33bb9SClaudio Fontana                 .InterruptNotification = 1
15011fc33bb9SClaudio Fontana             };
15021fc33bb9SClaudio Fontana         vcpu->window_registered = 1;
15031fc33bb9SClaudio Fontana         reg_names[reg_count] = WHvX64RegisterDeliverabilityNotifications;
15041fc33bb9SClaudio Fontana         reg_count += 1;
15051fc33bb9SClaudio Fontana     }
15061fc33bb9SClaudio Fontana 
15071fc33bb9SClaudio Fontana     qemu_mutex_unlock_iothread();
15081fc33bb9SClaudio Fontana     vcpu->ready_for_pic_interrupt = false;
15091fc33bb9SClaudio Fontana 
15101fc33bb9SClaudio Fontana     if (reg_count) {
15111fc33bb9SClaudio Fontana         hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
15121fc33bb9SClaudio Fontana             whpx->partition, cpu->cpu_index,
15131fc33bb9SClaudio Fontana             reg_names, reg_count, reg_values);
15141fc33bb9SClaudio Fontana         if (FAILED(hr)) {
15151fc33bb9SClaudio Fontana             error_report("WHPX: Failed to set interrupt state registers,"
15161fc33bb9SClaudio Fontana                          " hr=%08lx", hr);
15171fc33bb9SClaudio Fontana         }
15181fc33bb9SClaudio Fontana     }
15191fc33bb9SClaudio Fontana 
15201fc33bb9SClaudio Fontana     return;
15211fc33bb9SClaudio Fontana }
15221fc33bb9SClaudio Fontana 
15231fc33bb9SClaudio Fontana static void whpx_vcpu_post_run(CPUState *cpu)
15241fc33bb9SClaudio Fontana {
15251fc33bb9SClaudio Fontana     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
152695e862d7SPhilippe Mathieu-Daudé     CPUX86State *env = cpu->env_ptr;
15271fc33bb9SClaudio Fontana     X86CPU *x86_cpu = X86_CPU(cpu);
15281fc33bb9SClaudio Fontana 
15291fc33bb9SClaudio Fontana     env->eflags = vcpu->exit_ctx.VpContext.Rflags;
15301fc33bb9SClaudio Fontana 
15311fc33bb9SClaudio Fontana     uint64_t tpr = vcpu->exit_ctx.VpContext.Cr8;
15321fc33bb9SClaudio Fontana     if (vcpu->tpr != tpr) {
15331fc33bb9SClaudio Fontana         vcpu->tpr = tpr;
15341fc33bb9SClaudio Fontana         qemu_mutex_lock_iothread();
15351fc33bb9SClaudio Fontana         cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr);
15361fc33bb9SClaudio Fontana         qemu_mutex_unlock_iothread();
15371fc33bb9SClaudio Fontana     }
15381fc33bb9SClaudio Fontana 
15391fc33bb9SClaudio Fontana     vcpu->interruption_pending =
15401fc33bb9SClaudio Fontana         vcpu->exit_ctx.VpContext.ExecutionState.InterruptionPending;
15411fc33bb9SClaudio Fontana 
15421fc33bb9SClaudio Fontana     vcpu->interruptable =
15431fc33bb9SClaudio Fontana         !vcpu->exit_ctx.VpContext.ExecutionState.InterruptShadow;
15441fc33bb9SClaudio Fontana 
15451fc33bb9SClaudio Fontana     return;
15461fc33bb9SClaudio Fontana }
15471fc33bb9SClaudio Fontana 
15481fc33bb9SClaudio Fontana static void whpx_vcpu_process_async_events(CPUState *cpu)
15491fc33bb9SClaudio Fontana {
155095e862d7SPhilippe Mathieu-Daudé     CPUX86State *env = cpu->env_ptr;
15511fc33bb9SClaudio Fontana     X86CPU *x86_cpu = X86_CPU(cpu);
15521fc33bb9SClaudio Fontana     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
15531fc33bb9SClaudio Fontana 
15541fc33bb9SClaudio Fontana     if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) &&
15551fc33bb9SClaudio Fontana         !(env->hflags & HF_SMM_MASK)) {
15561fc33bb9SClaudio Fontana         whpx_cpu_synchronize_state(cpu);
15571fc33bb9SClaudio Fontana         do_cpu_init(x86_cpu);
15581fc33bb9SClaudio Fontana         vcpu->interruptable = true;
15591fc33bb9SClaudio Fontana     }
15601fc33bb9SClaudio Fontana 
15611fc33bb9SClaudio Fontana     if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
15621fc33bb9SClaudio Fontana         cpu->interrupt_request &= ~CPU_INTERRUPT_POLL;
15631fc33bb9SClaudio Fontana         apic_poll_irq(x86_cpu->apic_state);
15641fc33bb9SClaudio Fontana     }
15651fc33bb9SClaudio Fontana 
15661fc33bb9SClaudio Fontana     if (((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
15671fc33bb9SClaudio Fontana          (env->eflags & IF_MASK)) ||
15681fc33bb9SClaudio Fontana         (cpu->interrupt_request & CPU_INTERRUPT_NMI)) {
15691fc33bb9SClaudio Fontana         cpu->halted = false;
15701fc33bb9SClaudio Fontana     }
15711fc33bb9SClaudio Fontana 
15721fc33bb9SClaudio Fontana     if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) {
15731fc33bb9SClaudio Fontana         whpx_cpu_synchronize_state(cpu);
15741fc33bb9SClaudio Fontana         do_cpu_sipi(x86_cpu);
15751fc33bb9SClaudio Fontana     }
15761fc33bb9SClaudio Fontana 
15771fc33bb9SClaudio Fontana     if (cpu->interrupt_request & CPU_INTERRUPT_TPR) {
15781fc33bb9SClaudio Fontana         cpu->interrupt_request &= ~CPU_INTERRUPT_TPR;
15791fc33bb9SClaudio Fontana         whpx_cpu_synchronize_state(cpu);
15801fc33bb9SClaudio Fontana         apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip,
15811fc33bb9SClaudio Fontana                                       env->tpr_access_type);
15821fc33bb9SClaudio Fontana     }
15831fc33bb9SClaudio Fontana 
15841fc33bb9SClaudio Fontana     return;
15851fc33bb9SClaudio Fontana }
15861fc33bb9SClaudio Fontana 
15871fc33bb9SClaudio Fontana static int whpx_vcpu_run(CPUState *cpu)
15881fc33bb9SClaudio Fontana {
15891fc33bb9SClaudio Fontana     HRESULT hr;
15901fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
15911fc33bb9SClaudio Fontana     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
1592*d7482ffeSIvan Shcherbakov     struct whpx_breakpoint *stepped_over_bp = NULL;
1593*d7482ffeSIvan Shcherbakov     WhpxStepMode exclusive_step_mode = WHPX_STEP_NONE;
15941fc33bb9SClaudio Fontana     int ret;
15951fc33bb9SClaudio Fontana 
1596*d7482ffeSIvan Shcherbakov     g_assert(qemu_mutex_iothread_locked());
1597*d7482ffeSIvan Shcherbakov 
1598*d7482ffeSIvan Shcherbakov     if (whpx->running_cpus++ == 0) {
1599*d7482ffeSIvan Shcherbakov         /* Insert breakpoints into memory, update exception exit bitmap. */
1600*d7482ffeSIvan Shcherbakov         ret = whpx_first_vcpu_starting(cpu);
1601*d7482ffeSIvan Shcherbakov         if (ret != 0) {
1602*d7482ffeSIvan Shcherbakov             return ret;
1603*d7482ffeSIvan Shcherbakov         }
1604*d7482ffeSIvan Shcherbakov     }
1605*d7482ffeSIvan Shcherbakov 
1606*d7482ffeSIvan Shcherbakov     if (whpx->breakpoints.breakpoints &&
1607*d7482ffeSIvan Shcherbakov         whpx->breakpoints.breakpoints->used > 0)
1608*d7482ffeSIvan Shcherbakov     {
1609*d7482ffeSIvan Shcherbakov         uint64_t pc = whpx_vcpu_get_pc(cpu, true);
1610*d7482ffeSIvan Shcherbakov         stepped_over_bp = whpx_lookup_breakpoint_by_addr(pc);
1611*d7482ffeSIvan Shcherbakov         if (stepped_over_bp && stepped_over_bp->state != WHPX_BP_SET) {
1612*d7482ffeSIvan Shcherbakov             stepped_over_bp = NULL;
1613*d7482ffeSIvan Shcherbakov         }
1614*d7482ffeSIvan Shcherbakov 
1615*d7482ffeSIvan Shcherbakov         if (stepped_over_bp) {
1616*d7482ffeSIvan Shcherbakov             /*
1617*d7482ffeSIvan Shcherbakov              * We are trying to run the instruction overwritten by an active
1618*d7482ffeSIvan Shcherbakov              * breakpoint. We will temporarily disable the breakpoint, suspend
1619*d7482ffeSIvan Shcherbakov              * other CPUs, and step over the instruction.
1620*d7482ffeSIvan Shcherbakov              */
1621*d7482ffeSIvan Shcherbakov             exclusive_step_mode = WHPX_STEP_EXCLUSIVE;
1622*d7482ffeSIvan Shcherbakov         }
1623*d7482ffeSIvan Shcherbakov     }
1624*d7482ffeSIvan Shcherbakov 
1625*d7482ffeSIvan Shcherbakov     if (exclusive_step_mode == WHPX_STEP_NONE) {
16261fc33bb9SClaudio Fontana         whpx_vcpu_process_async_events(cpu);
16271fc33bb9SClaudio Fontana         if (cpu->halted && !whpx_apic_in_platform()) {
16281fc33bb9SClaudio Fontana             cpu->exception_index = EXCP_HLT;
16291fc33bb9SClaudio Fontana             qatomic_set(&cpu->exit_request, false);
16301fc33bb9SClaudio Fontana             return 0;
16311fc33bb9SClaudio Fontana         }
1632*d7482ffeSIvan Shcherbakov     }
16331fc33bb9SClaudio Fontana 
16341fc33bb9SClaudio Fontana     qemu_mutex_unlock_iothread();
1635*d7482ffeSIvan Shcherbakov 
1636*d7482ffeSIvan Shcherbakov     if (exclusive_step_mode != WHPX_STEP_NONE) {
1637*d7482ffeSIvan Shcherbakov         start_exclusive();
1638*d7482ffeSIvan Shcherbakov         g_assert(cpu == current_cpu);
1639*d7482ffeSIvan Shcherbakov         g_assert(!cpu->running);
1640*d7482ffeSIvan Shcherbakov         cpu->running = true;
1641*d7482ffeSIvan Shcherbakov 
1642*d7482ffeSIvan Shcherbakov         hr = whpx_set_exception_exit_bitmap(
1643*d7482ffeSIvan Shcherbakov             1UL << WHvX64ExceptionTypeDebugTrapOrFault);
1644*d7482ffeSIvan Shcherbakov         if (!SUCCEEDED(hr)) {
1645*d7482ffeSIvan Shcherbakov             error_report("WHPX: Failed to update exception exit mask, "
1646*d7482ffeSIvan Shcherbakov                          "hr=%08lx.", hr);
1647*d7482ffeSIvan Shcherbakov             return 1;
1648*d7482ffeSIvan Shcherbakov         }
1649*d7482ffeSIvan Shcherbakov 
1650*d7482ffeSIvan Shcherbakov         if (stepped_over_bp) {
1651*d7482ffeSIvan Shcherbakov             /* Temporarily disable the triggered breakpoint. */
1652*d7482ffeSIvan Shcherbakov             cpu_memory_rw_debug(cpu,
1653*d7482ffeSIvan Shcherbakov                 stepped_over_bp->address,
1654*d7482ffeSIvan Shcherbakov                 &stepped_over_bp->original_instruction,
1655*d7482ffeSIvan Shcherbakov                 1,
1656*d7482ffeSIvan Shcherbakov                 true);
1657*d7482ffeSIvan Shcherbakov         }
1658*d7482ffeSIvan Shcherbakov     } else {
16591fc33bb9SClaudio Fontana         cpu_exec_start(cpu);
1660*d7482ffeSIvan Shcherbakov     }
16611fc33bb9SClaudio Fontana 
16621fc33bb9SClaudio Fontana     do {
16631fc33bb9SClaudio Fontana         if (cpu->vcpu_dirty) {
16641fc33bb9SClaudio Fontana             whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE);
16651fc33bb9SClaudio Fontana             cpu->vcpu_dirty = false;
16661fc33bb9SClaudio Fontana         }
16671fc33bb9SClaudio Fontana 
1668*d7482ffeSIvan Shcherbakov         if (exclusive_step_mode == WHPX_STEP_NONE) {
16691fc33bb9SClaudio Fontana             whpx_vcpu_pre_run(cpu);
16701fc33bb9SClaudio Fontana 
16711fc33bb9SClaudio Fontana             if (qatomic_read(&cpu->exit_request)) {
16721fc33bb9SClaudio Fontana                 whpx_vcpu_kick(cpu);
16731fc33bb9SClaudio Fontana             }
1674*d7482ffeSIvan Shcherbakov         }
1675*d7482ffeSIvan Shcherbakov 
1676*d7482ffeSIvan Shcherbakov         if (exclusive_step_mode != WHPX_STEP_NONE || cpu->singlestep_enabled) {
1677*d7482ffeSIvan Shcherbakov             whpx_vcpu_configure_single_stepping(cpu, true, NULL);
1678*d7482ffeSIvan Shcherbakov         }
16791fc33bb9SClaudio Fontana 
16801fc33bb9SClaudio Fontana         hr = whp_dispatch.WHvRunVirtualProcessor(
16811fc33bb9SClaudio Fontana             whpx->partition, cpu->cpu_index,
16821fc33bb9SClaudio Fontana             &vcpu->exit_ctx, sizeof(vcpu->exit_ctx));
16831fc33bb9SClaudio Fontana 
16841fc33bb9SClaudio Fontana         if (FAILED(hr)) {
16851fc33bb9SClaudio Fontana             error_report("WHPX: Failed to exec a virtual processor,"
16861fc33bb9SClaudio Fontana                          " hr=%08lx", hr);
16871fc33bb9SClaudio Fontana             ret = -1;
16881fc33bb9SClaudio Fontana             break;
16891fc33bb9SClaudio Fontana         }
16901fc33bb9SClaudio Fontana 
1691*d7482ffeSIvan Shcherbakov         if (exclusive_step_mode != WHPX_STEP_NONE || cpu->singlestep_enabled) {
1692*d7482ffeSIvan Shcherbakov             whpx_vcpu_configure_single_stepping(cpu,
1693*d7482ffeSIvan Shcherbakov                 false,
1694*d7482ffeSIvan Shcherbakov                 &vcpu->exit_ctx.VpContext.Rflags);
1695*d7482ffeSIvan Shcherbakov         }
1696*d7482ffeSIvan Shcherbakov 
16971fc33bb9SClaudio Fontana         whpx_vcpu_post_run(cpu);
16981fc33bb9SClaudio Fontana 
16991fc33bb9SClaudio Fontana         switch (vcpu->exit_ctx.ExitReason) {
17001fc33bb9SClaudio Fontana         case WHvRunVpExitReasonMemoryAccess:
17011fc33bb9SClaudio Fontana             ret = whpx_handle_mmio(cpu, &vcpu->exit_ctx.MemoryAccess);
17021fc33bb9SClaudio Fontana             break;
17031fc33bb9SClaudio Fontana 
17041fc33bb9SClaudio Fontana         case WHvRunVpExitReasonX64IoPortAccess:
17051fc33bb9SClaudio Fontana             ret = whpx_handle_portio(cpu, &vcpu->exit_ctx.IoPortAccess);
17061fc33bb9SClaudio Fontana             break;
17071fc33bb9SClaudio Fontana 
17081fc33bb9SClaudio Fontana         case WHvRunVpExitReasonX64InterruptWindow:
17091fc33bb9SClaudio Fontana             vcpu->ready_for_pic_interrupt = 1;
17101fc33bb9SClaudio Fontana             vcpu->window_registered = 0;
17111fc33bb9SClaudio Fontana             ret = 0;
17121fc33bb9SClaudio Fontana             break;
17131fc33bb9SClaudio Fontana 
17141fc33bb9SClaudio Fontana         case WHvRunVpExitReasonX64ApicEoi:
17151fc33bb9SClaudio Fontana             assert(whpx_apic_in_platform());
17161fc33bb9SClaudio Fontana             ioapic_eoi_broadcast(vcpu->exit_ctx.ApicEoi.InterruptVector);
17171fc33bb9SClaudio Fontana             break;
17181fc33bb9SClaudio Fontana 
17191fc33bb9SClaudio Fontana         case WHvRunVpExitReasonX64Halt:
1720*d7482ffeSIvan Shcherbakov             /*
1721*d7482ffeSIvan Shcherbakov              * WARNING: as of build 19043.1526 (21H1), this exit reason is no
1722*d7482ffeSIvan Shcherbakov              * longer used.
1723*d7482ffeSIvan Shcherbakov              */
17241fc33bb9SClaudio Fontana             ret = whpx_handle_halt(cpu);
17251fc33bb9SClaudio Fontana             break;
17261fc33bb9SClaudio Fontana 
17271fc33bb9SClaudio Fontana         case WHvRunVpExitReasonX64ApicInitSipiTrap: {
17281fc33bb9SClaudio Fontana             WHV_INTERRUPT_CONTROL ipi = {0};
17291fc33bb9SClaudio Fontana             uint64_t icr = vcpu->exit_ctx.ApicInitSipi.ApicIcr;
17301fc33bb9SClaudio Fontana             uint32_t delivery_mode =
17311fc33bb9SClaudio Fontana                 (icr & APIC_ICR_DELIV_MOD) >> APIC_ICR_DELIV_MOD_SHIFT;
17321fc33bb9SClaudio Fontana             int dest_shorthand =
17331fc33bb9SClaudio Fontana                 (icr & APIC_ICR_DEST_SHORT) >> APIC_ICR_DEST_SHORT_SHIFT;
17341fc33bb9SClaudio Fontana             bool broadcast = false;
17351fc33bb9SClaudio Fontana             bool include_self = false;
17361fc33bb9SClaudio Fontana             uint32_t i;
17371fc33bb9SClaudio Fontana 
17381fc33bb9SClaudio Fontana             /* We only registered for INIT and SIPI exits. */
17391fc33bb9SClaudio Fontana             if ((delivery_mode != APIC_DM_INIT) &&
17401fc33bb9SClaudio Fontana                 (delivery_mode != APIC_DM_SIPI)) {
17411fc33bb9SClaudio Fontana                 error_report(
17421fc33bb9SClaudio Fontana                     "WHPX: Unexpected APIC exit that is not a INIT or SIPI");
17431fc33bb9SClaudio Fontana                 break;
17441fc33bb9SClaudio Fontana             }
17451fc33bb9SClaudio Fontana 
17461fc33bb9SClaudio Fontana             if (delivery_mode == APIC_DM_INIT) {
17471fc33bb9SClaudio Fontana                 ipi.Type = WHvX64InterruptTypeInit;
17481fc33bb9SClaudio Fontana             } else {
17491fc33bb9SClaudio Fontana                 ipi.Type = WHvX64InterruptTypeSipi;
17501fc33bb9SClaudio Fontana             }
17511fc33bb9SClaudio Fontana 
17521fc33bb9SClaudio Fontana             ipi.DestinationMode =
17531fc33bb9SClaudio Fontana                 ((icr & APIC_ICR_DEST_MOD) >> APIC_ICR_DEST_MOD_SHIFT) ?
17541fc33bb9SClaudio Fontana                     WHvX64InterruptDestinationModeLogical :
17551fc33bb9SClaudio Fontana                     WHvX64InterruptDestinationModePhysical;
17561fc33bb9SClaudio Fontana 
17571fc33bb9SClaudio Fontana             ipi.TriggerMode =
17581fc33bb9SClaudio Fontana                 ((icr & APIC_ICR_TRIGGER_MOD) >> APIC_ICR_TRIGGER_MOD_SHIFT) ?
17591fc33bb9SClaudio Fontana                     WHvX64InterruptTriggerModeLevel :
17601fc33bb9SClaudio Fontana                     WHvX64InterruptTriggerModeEdge;
17611fc33bb9SClaudio Fontana 
17621fc33bb9SClaudio Fontana             ipi.Vector = icr & APIC_VECTOR_MASK;
17631fc33bb9SClaudio Fontana             switch (dest_shorthand) {
17641fc33bb9SClaudio Fontana             /* no shorthand. Bits 56-63 contain the destination. */
17651fc33bb9SClaudio Fontana             case 0:
17661fc33bb9SClaudio Fontana                 ipi.Destination = (icr >> 56) & APIC_VECTOR_MASK;
17671fc33bb9SClaudio Fontana                 hr = whp_dispatch.WHvRequestInterrupt(whpx->partition,
17681fc33bb9SClaudio Fontana                         &ipi, sizeof(ipi));
17691fc33bb9SClaudio Fontana                 if (FAILED(hr)) {
17701fc33bb9SClaudio Fontana                     error_report("WHPX: Failed to request interrupt  hr=%08lx",
17711fc33bb9SClaudio Fontana                         hr);
17721fc33bb9SClaudio Fontana                 }
17731fc33bb9SClaudio Fontana 
17741fc33bb9SClaudio Fontana                 break;
17751fc33bb9SClaudio Fontana 
17761fc33bb9SClaudio Fontana             /* self */
17771fc33bb9SClaudio Fontana             case 1:
17781fc33bb9SClaudio Fontana                 include_self = true;
17791fc33bb9SClaudio Fontana                 break;
17801fc33bb9SClaudio Fontana 
17811fc33bb9SClaudio Fontana             /* broadcast, including self */
17821fc33bb9SClaudio Fontana             case 2:
17831fc33bb9SClaudio Fontana                 broadcast = true;
17841fc33bb9SClaudio Fontana                 include_self = true;
17851fc33bb9SClaudio Fontana                 break;
17861fc33bb9SClaudio Fontana 
17871fc33bb9SClaudio Fontana             /* broadcast, excluding self */
17881fc33bb9SClaudio Fontana             case 3:
17891fc33bb9SClaudio Fontana                 broadcast = true;
17901fc33bb9SClaudio Fontana                 break;
17911fc33bb9SClaudio Fontana             }
17921fc33bb9SClaudio Fontana 
17931fc33bb9SClaudio Fontana             if (!broadcast && !include_self) {
17941fc33bb9SClaudio Fontana                 break;
17951fc33bb9SClaudio Fontana             }
17961fc33bb9SClaudio Fontana 
17971fc33bb9SClaudio Fontana             for (i = 0; i <= max_vcpu_index; i++) {
17981fc33bb9SClaudio Fontana                 if (i == cpu->cpu_index && !include_self) {
17991fc33bb9SClaudio Fontana                     continue;
18001fc33bb9SClaudio Fontana                 }
18011fc33bb9SClaudio Fontana 
18021fc33bb9SClaudio Fontana                 /*
18031fc33bb9SClaudio Fontana                  * Assuming that APIC Ids are identity mapped since
18041fc33bb9SClaudio Fontana                  * WHvX64RegisterApicId & WHvX64RegisterInitialApicId registers
18051fc33bb9SClaudio Fontana                  * are not handled yet and the hypervisor doesn't allow the
18061fc33bb9SClaudio Fontana                  * guest to modify the APIC ID.
18071fc33bb9SClaudio Fontana                  */
18081fc33bb9SClaudio Fontana                 ipi.Destination = i;
18091fc33bb9SClaudio Fontana                 hr = whp_dispatch.WHvRequestInterrupt(whpx->partition,
18101fc33bb9SClaudio Fontana                         &ipi, sizeof(ipi));
18111fc33bb9SClaudio Fontana                 if (FAILED(hr)) {
18121fc33bb9SClaudio Fontana                     error_report(
18131fc33bb9SClaudio Fontana                         "WHPX: Failed to request SIPI for %d,  hr=%08lx",
18141fc33bb9SClaudio Fontana                         i, hr);
18151fc33bb9SClaudio Fontana                 }
18161fc33bb9SClaudio Fontana             }
18171fc33bb9SClaudio Fontana 
18181fc33bb9SClaudio Fontana             break;
18191fc33bb9SClaudio Fontana         }
18201fc33bb9SClaudio Fontana 
18211fc33bb9SClaudio Fontana         case WHvRunVpExitReasonCanceled:
1822*d7482ffeSIvan Shcherbakov             if (exclusive_step_mode != WHPX_STEP_NONE) {
1823*d7482ffeSIvan Shcherbakov                 /*
1824*d7482ffeSIvan Shcherbakov                  * We are trying to step over a single instruction, and
1825*d7482ffeSIvan Shcherbakov                  * likely got a request to stop from another thread.
1826*d7482ffeSIvan Shcherbakov                  * Delay it until we are done stepping
1827*d7482ffeSIvan Shcherbakov                  * over.
1828*d7482ffeSIvan Shcherbakov                  */
1829*d7482ffeSIvan Shcherbakov                 ret = 0;
1830*d7482ffeSIvan Shcherbakov             } else {
18311fc33bb9SClaudio Fontana                 cpu->exception_index = EXCP_INTERRUPT;
18321fc33bb9SClaudio Fontana                 ret = 1;
1833*d7482ffeSIvan Shcherbakov             }
18341fc33bb9SClaudio Fontana             break;
18351fc33bb9SClaudio Fontana         case WHvRunVpExitReasonX64MsrAccess: {
18361fc33bb9SClaudio Fontana             WHV_REGISTER_VALUE reg_values[3] = {0};
18371fc33bb9SClaudio Fontana             WHV_REGISTER_NAME reg_names[3];
18381fc33bb9SClaudio Fontana             UINT32 reg_count;
18391fc33bb9SClaudio Fontana 
18401fc33bb9SClaudio Fontana             reg_names[0] = WHvX64RegisterRip;
18411fc33bb9SClaudio Fontana             reg_names[1] = WHvX64RegisterRax;
18421fc33bb9SClaudio Fontana             reg_names[2] = WHvX64RegisterRdx;
18431fc33bb9SClaudio Fontana 
18441fc33bb9SClaudio Fontana             reg_values[0].Reg64 =
18451fc33bb9SClaudio Fontana                 vcpu->exit_ctx.VpContext.Rip +
18461fc33bb9SClaudio Fontana                 vcpu->exit_ctx.VpContext.InstructionLength;
18471fc33bb9SClaudio Fontana 
18481fc33bb9SClaudio Fontana             /*
18491fc33bb9SClaudio Fontana              * For all unsupported MSR access we:
18501fc33bb9SClaudio Fontana              *     ignore writes
18511fc33bb9SClaudio Fontana              *     return 0 on read.
18521fc33bb9SClaudio Fontana              */
18531fc33bb9SClaudio Fontana             reg_count = vcpu->exit_ctx.MsrAccess.AccessInfo.IsWrite ?
18541fc33bb9SClaudio Fontana                         1 : 3;
18551fc33bb9SClaudio Fontana 
18561fc33bb9SClaudio Fontana             hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
18571fc33bb9SClaudio Fontana                 whpx->partition,
18581fc33bb9SClaudio Fontana                 cpu->cpu_index,
18591fc33bb9SClaudio Fontana                 reg_names, reg_count,
18601fc33bb9SClaudio Fontana                 reg_values);
18611fc33bb9SClaudio Fontana 
18621fc33bb9SClaudio Fontana             if (FAILED(hr)) {
18631fc33bb9SClaudio Fontana                 error_report("WHPX: Failed to set MsrAccess state "
18641fc33bb9SClaudio Fontana                              " registers, hr=%08lx", hr);
18651fc33bb9SClaudio Fontana             }
18661fc33bb9SClaudio Fontana             ret = 0;
18671fc33bb9SClaudio Fontana             break;
18681fc33bb9SClaudio Fontana         }
18691fc33bb9SClaudio Fontana         case WHvRunVpExitReasonX64Cpuid: {
18701fc33bb9SClaudio Fontana             WHV_REGISTER_VALUE reg_values[5];
18711fc33bb9SClaudio Fontana             WHV_REGISTER_NAME reg_names[5];
18721fc33bb9SClaudio Fontana             UINT32 reg_count = 5;
18731fc33bb9SClaudio Fontana             UINT64 cpuid_fn, rip = 0, rax = 0, rcx = 0, rdx = 0, rbx = 0;
18741fc33bb9SClaudio Fontana             X86CPU *x86_cpu = X86_CPU(cpu);
18751fc33bb9SClaudio Fontana             CPUX86State *env = &x86_cpu->env;
18761fc33bb9SClaudio Fontana 
18771fc33bb9SClaudio Fontana             memset(reg_values, 0, sizeof(reg_values));
18781fc33bb9SClaudio Fontana 
18791fc33bb9SClaudio Fontana             rip = vcpu->exit_ctx.VpContext.Rip +
18801fc33bb9SClaudio Fontana                   vcpu->exit_ctx.VpContext.InstructionLength;
18811fc33bb9SClaudio Fontana             cpuid_fn = vcpu->exit_ctx.CpuidAccess.Rax;
18821fc33bb9SClaudio Fontana 
18831fc33bb9SClaudio Fontana             /*
18841fc33bb9SClaudio Fontana              * Ideally, these should be supplied to the hypervisor during VCPU
18851fc33bb9SClaudio Fontana              * initialization and it should be able to satisfy this request.
18861fc33bb9SClaudio Fontana              * But, currently, WHPX doesn't support setting CPUID values in the
18871fc33bb9SClaudio Fontana              * hypervisor once the partition has been setup, which is too late
18881fc33bb9SClaudio Fontana              * since VCPUs are realized later. For now, use the values from
18891fc33bb9SClaudio Fontana              * QEMU to satisfy these requests, until WHPX adds support for
18901fc33bb9SClaudio Fontana              * being able to set these values in the hypervisor at runtime.
18911fc33bb9SClaudio Fontana              */
18921fc33bb9SClaudio Fontana             cpu_x86_cpuid(env, cpuid_fn, 0, (UINT32 *)&rax, (UINT32 *)&rbx,
18931fc33bb9SClaudio Fontana                 (UINT32 *)&rcx, (UINT32 *)&rdx);
18941fc33bb9SClaudio Fontana             switch (cpuid_fn) {
18951fc33bb9SClaudio Fontana             case 0x40000000:
18961fc33bb9SClaudio Fontana                 /* Expose the vmware cpu frequency cpuid leaf */
18971fc33bb9SClaudio Fontana                 rax = 0x40000010;
18981fc33bb9SClaudio Fontana                 rbx = rcx = rdx = 0;
18991fc33bb9SClaudio Fontana                 break;
19001fc33bb9SClaudio Fontana 
19011fc33bb9SClaudio Fontana             case 0x40000010:
19021fc33bb9SClaudio Fontana                 rax = env->tsc_khz;
19031fc33bb9SClaudio Fontana                 rbx = env->apic_bus_freq / 1000; /* Hz to KHz */
19041fc33bb9SClaudio Fontana                 rcx = rdx = 0;
19051fc33bb9SClaudio Fontana                 break;
19061fc33bb9SClaudio Fontana 
19071fc33bb9SClaudio Fontana             case 0x80000001:
19081fc33bb9SClaudio Fontana                 /* Remove any support of OSVW */
19091fc33bb9SClaudio Fontana                 rcx &= ~CPUID_EXT3_OSVW;
19101fc33bb9SClaudio Fontana                 break;
19111fc33bb9SClaudio Fontana             }
19121fc33bb9SClaudio Fontana 
19131fc33bb9SClaudio Fontana             reg_names[0] = WHvX64RegisterRip;
19141fc33bb9SClaudio Fontana             reg_names[1] = WHvX64RegisterRax;
19151fc33bb9SClaudio Fontana             reg_names[2] = WHvX64RegisterRcx;
19161fc33bb9SClaudio Fontana             reg_names[3] = WHvX64RegisterRdx;
19171fc33bb9SClaudio Fontana             reg_names[4] = WHvX64RegisterRbx;
19181fc33bb9SClaudio Fontana 
19191fc33bb9SClaudio Fontana             reg_values[0].Reg64 = rip;
19201fc33bb9SClaudio Fontana             reg_values[1].Reg64 = rax;
19211fc33bb9SClaudio Fontana             reg_values[2].Reg64 = rcx;
19221fc33bb9SClaudio Fontana             reg_values[3].Reg64 = rdx;
19231fc33bb9SClaudio Fontana             reg_values[4].Reg64 = rbx;
19241fc33bb9SClaudio Fontana 
19251fc33bb9SClaudio Fontana             hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
19261fc33bb9SClaudio Fontana                 whpx->partition, cpu->cpu_index,
19271fc33bb9SClaudio Fontana                 reg_names,
19281fc33bb9SClaudio Fontana                 reg_count,
19291fc33bb9SClaudio Fontana                 reg_values);
19301fc33bb9SClaudio Fontana 
19311fc33bb9SClaudio Fontana             if (FAILED(hr)) {
19321fc33bb9SClaudio Fontana                 error_report("WHPX: Failed to set CpuidAccess state registers,"
19331fc33bb9SClaudio Fontana                              " hr=%08lx", hr);
19341fc33bb9SClaudio Fontana             }
19351fc33bb9SClaudio Fontana             ret = 0;
19361fc33bb9SClaudio Fontana             break;
19371fc33bb9SClaudio Fontana         }
1938*d7482ffeSIvan Shcherbakov         case WHvRunVpExitReasonException:
1939*d7482ffeSIvan Shcherbakov             whpx_get_registers(cpu);
1940*d7482ffeSIvan Shcherbakov 
1941*d7482ffeSIvan Shcherbakov             if ((vcpu->exit_ctx.VpException.ExceptionType ==
1942*d7482ffeSIvan Shcherbakov                  WHvX64ExceptionTypeDebugTrapOrFault) &&
1943*d7482ffeSIvan Shcherbakov                 (vcpu->exit_ctx.VpException.InstructionByteCount >= 1) &&
1944*d7482ffeSIvan Shcherbakov                 (vcpu->exit_ctx.VpException.InstructionBytes[0] ==
1945*d7482ffeSIvan Shcherbakov                  whpx_breakpoint_instruction)) {
1946*d7482ffeSIvan Shcherbakov                 /* Stopped at a software breakpoint. */
1947*d7482ffeSIvan Shcherbakov                 cpu->exception_index = EXCP_DEBUG;
1948*d7482ffeSIvan Shcherbakov             } else if ((vcpu->exit_ctx.VpException.ExceptionType ==
1949*d7482ffeSIvan Shcherbakov                         WHvX64ExceptionTypeDebugTrapOrFault) &&
1950*d7482ffeSIvan Shcherbakov                        !cpu->singlestep_enabled) {
1951*d7482ffeSIvan Shcherbakov                 /*
1952*d7482ffeSIvan Shcherbakov                  * Just finished stepping over a breakpoint, but the
1953*d7482ffeSIvan Shcherbakov                  * gdb does not expect us to do single-stepping.
1954*d7482ffeSIvan Shcherbakov                  * Don't do anything special.
1955*d7482ffeSIvan Shcherbakov                  */
1956*d7482ffeSIvan Shcherbakov                 cpu->exception_index = EXCP_INTERRUPT;
1957*d7482ffeSIvan Shcherbakov             } else {
1958*d7482ffeSIvan Shcherbakov                 /* Another exception or debug event. Report it to GDB. */
1959*d7482ffeSIvan Shcherbakov                 cpu->exception_index = EXCP_DEBUG;
1960*d7482ffeSIvan Shcherbakov             }
1961*d7482ffeSIvan Shcherbakov 
1962*d7482ffeSIvan Shcherbakov             ret = 1;
1963*d7482ffeSIvan Shcherbakov             break;
19641fc33bb9SClaudio Fontana         case WHvRunVpExitReasonNone:
19651fc33bb9SClaudio Fontana         case WHvRunVpExitReasonUnrecoverableException:
19661fc33bb9SClaudio Fontana         case WHvRunVpExitReasonInvalidVpRegisterValue:
19671fc33bb9SClaudio Fontana         case WHvRunVpExitReasonUnsupportedFeature:
19681fc33bb9SClaudio Fontana         default:
19691fc33bb9SClaudio Fontana             error_report("WHPX: Unexpected VP exit code %d",
19701fc33bb9SClaudio Fontana                          vcpu->exit_ctx.ExitReason);
19711fc33bb9SClaudio Fontana             whpx_get_registers(cpu);
19721fc33bb9SClaudio Fontana             qemu_mutex_lock_iothread();
19731fc33bb9SClaudio Fontana             qemu_system_guest_panicked(cpu_get_crash_info(cpu));
19741fc33bb9SClaudio Fontana             qemu_mutex_unlock_iothread();
19751fc33bb9SClaudio Fontana             break;
19761fc33bb9SClaudio Fontana         }
19771fc33bb9SClaudio Fontana 
19781fc33bb9SClaudio Fontana     } while (!ret);
19791fc33bb9SClaudio Fontana 
1980*d7482ffeSIvan Shcherbakov     if (stepped_over_bp) {
1981*d7482ffeSIvan Shcherbakov         /* Restore the breakpoint we stepped over */
1982*d7482ffeSIvan Shcherbakov         cpu_memory_rw_debug(cpu,
1983*d7482ffeSIvan Shcherbakov             stepped_over_bp->address,
1984*d7482ffeSIvan Shcherbakov             (void *)&whpx_breakpoint_instruction,
1985*d7482ffeSIvan Shcherbakov             1,
1986*d7482ffeSIvan Shcherbakov             true);
1987*d7482ffeSIvan Shcherbakov     }
1988*d7482ffeSIvan Shcherbakov 
1989*d7482ffeSIvan Shcherbakov     if (exclusive_step_mode != WHPX_STEP_NONE) {
1990*d7482ffeSIvan Shcherbakov         g_assert(cpu_in_exclusive_context(cpu));
1991*d7482ffeSIvan Shcherbakov         cpu->running = false;
1992*d7482ffeSIvan Shcherbakov         end_exclusive();
1993*d7482ffeSIvan Shcherbakov 
1994*d7482ffeSIvan Shcherbakov         exclusive_step_mode = WHPX_STEP_NONE;
1995*d7482ffeSIvan Shcherbakov     } else {
19961fc33bb9SClaudio Fontana         cpu_exec_end(cpu);
1997*d7482ffeSIvan Shcherbakov     }
1998*d7482ffeSIvan Shcherbakov 
19991fc33bb9SClaudio Fontana     qemu_mutex_lock_iothread();
20001fc33bb9SClaudio Fontana     current_cpu = cpu;
20011fc33bb9SClaudio Fontana 
2002*d7482ffeSIvan Shcherbakov     if (--whpx->running_cpus == 0) {
2003*d7482ffeSIvan Shcherbakov         whpx_last_vcpu_stopping(cpu);
2004*d7482ffeSIvan Shcherbakov     }
2005*d7482ffeSIvan Shcherbakov 
20061fc33bb9SClaudio Fontana     qatomic_set(&cpu->exit_request, false);
20071fc33bb9SClaudio Fontana 
20081fc33bb9SClaudio Fontana     return ret < 0;
20091fc33bb9SClaudio Fontana }
20101fc33bb9SClaudio Fontana 
20111fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
20121fc33bb9SClaudio Fontana {
20131fc33bb9SClaudio Fontana     if (!cpu->vcpu_dirty) {
20141fc33bb9SClaudio Fontana         whpx_get_registers(cpu);
20151fc33bb9SClaudio Fontana         cpu->vcpu_dirty = true;
20161fc33bb9SClaudio Fontana     }
20171fc33bb9SClaudio Fontana }
20181fc33bb9SClaudio Fontana 
20191fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu,
20201fc33bb9SClaudio Fontana                                                run_on_cpu_data arg)
20211fc33bb9SClaudio Fontana {
20221fc33bb9SClaudio Fontana     whpx_set_registers(cpu, WHPX_SET_RESET_STATE);
20231fc33bb9SClaudio Fontana     cpu->vcpu_dirty = false;
20241fc33bb9SClaudio Fontana }
20251fc33bb9SClaudio Fontana 
20261fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,
20271fc33bb9SClaudio Fontana                                               run_on_cpu_data arg)
20281fc33bb9SClaudio Fontana {
20291fc33bb9SClaudio Fontana     whpx_set_registers(cpu, WHPX_SET_FULL_STATE);
20301fc33bb9SClaudio Fontana     cpu->vcpu_dirty = false;
20311fc33bb9SClaudio Fontana }
20321fc33bb9SClaudio Fontana 
20331fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu,
20341fc33bb9SClaudio Fontana                                                run_on_cpu_data arg)
20351fc33bb9SClaudio Fontana {
20361fc33bb9SClaudio Fontana     cpu->vcpu_dirty = true;
20371fc33bb9SClaudio Fontana }
20381fc33bb9SClaudio Fontana 
20391fc33bb9SClaudio Fontana /*
20401fc33bb9SClaudio Fontana  * CPU support.
20411fc33bb9SClaudio Fontana  */
20421fc33bb9SClaudio Fontana 
20431fc33bb9SClaudio Fontana void whpx_cpu_synchronize_state(CPUState *cpu)
20441fc33bb9SClaudio Fontana {
20451fc33bb9SClaudio Fontana     if (!cpu->vcpu_dirty) {
20461fc33bb9SClaudio Fontana         run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL);
20471fc33bb9SClaudio Fontana     }
20481fc33bb9SClaudio Fontana }
20491fc33bb9SClaudio Fontana 
20501fc33bb9SClaudio Fontana void whpx_cpu_synchronize_post_reset(CPUState *cpu)
20511fc33bb9SClaudio Fontana {
20521fc33bb9SClaudio Fontana     run_on_cpu(cpu, do_whpx_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);
20531fc33bb9SClaudio Fontana }
20541fc33bb9SClaudio Fontana 
20551fc33bb9SClaudio Fontana void whpx_cpu_synchronize_post_init(CPUState *cpu)
20561fc33bb9SClaudio Fontana {
20571fc33bb9SClaudio Fontana     run_on_cpu(cpu, do_whpx_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
20581fc33bb9SClaudio Fontana }
20591fc33bb9SClaudio Fontana 
20601fc33bb9SClaudio Fontana void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)
20611fc33bb9SClaudio Fontana {
20621fc33bb9SClaudio Fontana     run_on_cpu(cpu, do_whpx_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);
20631fc33bb9SClaudio Fontana }
20641fc33bb9SClaudio Fontana 
2065*d7482ffeSIvan Shcherbakov void whpx_cpu_synchronize_pre_resume(bool step_pending)
2066*d7482ffeSIvan Shcherbakov {
2067*d7482ffeSIvan Shcherbakov     whpx_global.step_pending = step_pending;
2068*d7482ffeSIvan Shcherbakov }
2069*d7482ffeSIvan Shcherbakov 
20701fc33bb9SClaudio Fontana /*
20711fc33bb9SClaudio Fontana  * Vcpu support.
20721fc33bb9SClaudio Fontana  */
20731fc33bb9SClaudio Fontana 
20741fc33bb9SClaudio Fontana static Error *whpx_migration_blocker;
20751fc33bb9SClaudio Fontana 
2076538f0497SPhilippe Mathieu-Daudé static void whpx_cpu_update_state(void *opaque, bool running, RunState state)
20771fc33bb9SClaudio Fontana {
20781fc33bb9SClaudio Fontana     CPUX86State *env = opaque;
20791fc33bb9SClaudio Fontana 
20801fc33bb9SClaudio Fontana     if (running) {
20811fc33bb9SClaudio Fontana         env->tsc_valid = false;
20821fc33bb9SClaudio Fontana     }
20831fc33bb9SClaudio Fontana }
20841fc33bb9SClaudio Fontana 
20851fc33bb9SClaudio Fontana int whpx_init_vcpu(CPUState *cpu)
20861fc33bb9SClaudio Fontana {
20871fc33bb9SClaudio Fontana     HRESULT hr;
20881fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
20891fc33bb9SClaudio Fontana     struct whpx_vcpu *vcpu = NULL;
20901fc33bb9SClaudio Fontana     Error *local_error = NULL;
209195e862d7SPhilippe Mathieu-Daudé     CPUX86State *env = cpu->env_ptr;
20921fc33bb9SClaudio Fontana     X86CPU *x86_cpu = X86_CPU(cpu);
20931fc33bb9SClaudio Fontana     UINT64 freq = 0;
20941fc33bb9SClaudio Fontana     int ret;
20951fc33bb9SClaudio Fontana 
20961fc33bb9SClaudio Fontana     /* Add migration blockers for all unsupported features of the
20971fc33bb9SClaudio Fontana      * Windows Hypervisor Platform
20981fc33bb9SClaudio Fontana      */
20991fc33bb9SClaudio Fontana     if (whpx_migration_blocker == NULL) {
21001fc33bb9SClaudio Fontana         error_setg(&whpx_migration_blocker,
21011fc33bb9SClaudio Fontana                "State blocked due to non-migratable CPUID feature support,"
21021fc33bb9SClaudio Fontana                "dirty memory tracking support, and XSAVE/XRSTOR support");
21031fc33bb9SClaudio Fontana 
2104436c831aSMarkus Armbruster         if (migrate_add_blocker(whpx_migration_blocker, &local_error) < 0) {
21051fc33bb9SClaudio Fontana             error_report_err(local_error);
21061fc33bb9SClaudio Fontana             error_free(whpx_migration_blocker);
21071fc33bb9SClaudio Fontana             ret = -EINVAL;
21081fc33bb9SClaudio Fontana             goto error;
21091fc33bb9SClaudio Fontana         }
21101fc33bb9SClaudio Fontana     }
21111fc33bb9SClaudio Fontana 
2112b21e2380SMarkus Armbruster     vcpu = g_new0(struct whpx_vcpu, 1);
21131fc33bb9SClaudio Fontana 
21141fc33bb9SClaudio Fontana     if (!vcpu) {
21151fc33bb9SClaudio Fontana         error_report("WHPX: Failed to allocte VCPU context.");
21161fc33bb9SClaudio Fontana         ret = -ENOMEM;
21171fc33bb9SClaudio Fontana         goto error;
21181fc33bb9SClaudio Fontana     }
21191fc33bb9SClaudio Fontana 
21201fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvEmulatorCreateEmulator(
21211fc33bb9SClaudio Fontana         &whpx_emu_callbacks,
21221fc33bb9SClaudio Fontana         &vcpu->emulator);
21231fc33bb9SClaudio Fontana     if (FAILED(hr)) {
21241fc33bb9SClaudio Fontana         error_report("WHPX: Failed to setup instruction completion support,"
21251fc33bb9SClaudio Fontana                      " hr=%08lx", hr);
21261fc33bb9SClaudio Fontana         ret = -EINVAL;
21271fc33bb9SClaudio Fontana         goto error;
21281fc33bb9SClaudio Fontana     }
21291fc33bb9SClaudio Fontana 
21301fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvCreateVirtualProcessor(
21311fc33bb9SClaudio Fontana         whpx->partition, cpu->cpu_index, 0);
21321fc33bb9SClaudio Fontana     if (FAILED(hr)) {
21331fc33bb9SClaudio Fontana         error_report("WHPX: Failed to create a virtual processor,"
21341fc33bb9SClaudio Fontana                      " hr=%08lx", hr);
21351fc33bb9SClaudio Fontana         whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
21361fc33bb9SClaudio Fontana         ret = -EINVAL;
21371fc33bb9SClaudio Fontana         goto error;
21381fc33bb9SClaudio Fontana     }
21391fc33bb9SClaudio Fontana 
21401fc33bb9SClaudio Fontana     /*
21411fc33bb9SClaudio Fontana      * vcpu's TSC frequency is either specified by user, or use the value
21421fc33bb9SClaudio Fontana      * provided by Hyper-V if the former is not present. In the latter case, we
21431fc33bb9SClaudio Fontana      * query it from Hyper-V and record in env->tsc_khz, so that vcpu's TSC
21441fc33bb9SClaudio Fontana      * frequency can be migrated later via this field.
21451fc33bb9SClaudio Fontana      */
21461fc33bb9SClaudio Fontana     if (!env->tsc_khz) {
21471fc33bb9SClaudio Fontana         hr = whp_dispatch.WHvGetCapability(
21481fc33bb9SClaudio Fontana             WHvCapabilityCodeProcessorClockFrequency, &freq, sizeof(freq),
21491fc33bb9SClaudio Fontana                 NULL);
21501fc33bb9SClaudio Fontana         if (hr != WHV_E_UNKNOWN_CAPABILITY) {
21511fc33bb9SClaudio Fontana             if (FAILED(hr)) {
21521fc33bb9SClaudio Fontana                 printf("WHPX: Failed to query tsc frequency, hr=0x%08lx\n", hr);
21531fc33bb9SClaudio Fontana             } else {
21541fc33bb9SClaudio Fontana                 env->tsc_khz = freq / 1000; /* Hz to KHz */
21551fc33bb9SClaudio Fontana             }
21561fc33bb9SClaudio Fontana         }
21571fc33bb9SClaudio Fontana     }
21581fc33bb9SClaudio Fontana 
21591fc33bb9SClaudio Fontana     env->apic_bus_freq = HYPERV_APIC_BUS_FREQUENCY;
21601fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvGetCapability(
21611fc33bb9SClaudio Fontana         WHvCapabilityCodeInterruptClockFrequency, &freq, sizeof(freq), NULL);
21621fc33bb9SClaudio Fontana     if (hr != WHV_E_UNKNOWN_CAPABILITY) {
21631fc33bb9SClaudio Fontana         if (FAILED(hr)) {
21641fc33bb9SClaudio Fontana             printf("WHPX: Failed to query apic bus frequency hr=0x%08lx\n", hr);
21651fc33bb9SClaudio Fontana         } else {
21661fc33bb9SClaudio Fontana             env->apic_bus_freq = freq;
21671fc33bb9SClaudio Fontana         }
21681fc33bb9SClaudio Fontana     }
21691fc33bb9SClaudio Fontana 
21701fc33bb9SClaudio Fontana     /*
21711fc33bb9SClaudio Fontana      * If the vmware cpuid frequency leaf option is set, and we have a valid
21721fc33bb9SClaudio Fontana      * tsc value, trap the corresponding cpuid's.
21731fc33bb9SClaudio Fontana      */
21741fc33bb9SClaudio Fontana     if (x86_cpu->vmware_cpuid_freq && env->tsc_khz) {
21751fc33bb9SClaudio Fontana         UINT32 cpuidExitList[] = {1, 0x80000001, 0x40000000, 0x40000010};
21761fc33bb9SClaudio Fontana 
21771fc33bb9SClaudio Fontana         hr = whp_dispatch.WHvSetPartitionProperty(
21781fc33bb9SClaudio Fontana                 whpx->partition,
21791fc33bb9SClaudio Fontana                 WHvPartitionPropertyCodeCpuidExitList,
21801fc33bb9SClaudio Fontana                 cpuidExitList,
21811fc33bb9SClaudio Fontana                 RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32));
21821fc33bb9SClaudio Fontana 
21831fc33bb9SClaudio Fontana         if (FAILED(hr)) {
21841fc33bb9SClaudio Fontana             error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx",
21851fc33bb9SClaudio Fontana                         hr);
21861fc33bb9SClaudio Fontana             ret = -EINVAL;
21871fc33bb9SClaudio Fontana             goto error;
21881fc33bb9SClaudio Fontana         }
21891fc33bb9SClaudio Fontana     }
21901fc33bb9SClaudio Fontana 
21911fc33bb9SClaudio Fontana     vcpu->interruptable = true;
21921fc33bb9SClaudio Fontana     cpu->vcpu_dirty = true;
21931fc33bb9SClaudio Fontana     cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu;
21941fc33bb9SClaudio Fontana     max_vcpu_index = max(max_vcpu_index, cpu->cpu_index);
21951fc33bb9SClaudio Fontana     qemu_add_vm_change_state_handler(whpx_cpu_update_state, cpu->env_ptr);
21961fc33bb9SClaudio Fontana 
21971fc33bb9SClaudio Fontana     return 0;
21981fc33bb9SClaudio Fontana 
21991fc33bb9SClaudio Fontana error:
22001fc33bb9SClaudio Fontana     g_free(vcpu);
22011fc33bb9SClaudio Fontana 
22021fc33bb9SClaudio Fontana     return ret;
22031fc33bb9SClaudio Fontana }
22041fc33bb9SClaudio Fontana 
22051fc33bb9SClaudio Fontana int whpx_vcpu_exec(CPUState *cpu)
22061fc33bb9SClaudio Fontana {
22071fc33bb9SClaudio Fontana     int ret;
22081fc33bb9SClaudio Fontana     int fatal;
22091fc33bb9SClaudio Fontana 
22101fc33bb9SClaudio Fontana     for (;;) {
22111fc33bb9SClaudio Fontana         if (cpu->exception_index >= EXCP_INTERRUPT) {
22121fc33bb9SClaudio Fontana             ret = cpu->exception_index;
22131fc33bb9SClaudio Fontana             cpu->exception_index = -1;
22141fc33bb9SClaudio Fontana             break;
22151fc33bb9SClaudio Fontana         }
22161fc33bb9SClaudio Fontana 
22171fc33bb9SClaudio Fontana         fatal = whpx_vcpu_run(cpu);
22181fc33bb9SClaudio Fontana 
22191fc33bb9SClaudio Fontana         if (fatal) {
22201fc33bb9SClaudio Fontana             error_report("WHPX: Failed to exec a virtual processor");
22211fc33bb9SClaudio Fontana             abort();
22221fc33bb9SClaudio Fontana         }
22231fc33bb9SClaudio Fontana     }
22241fc33bb9SClaudio Fontana 
22251fc33bb9SClaudio Fontana     return ret;
22261fc33bb9SClaudio Fontana }
22271fc33bb9SClaudio Fontana 
22281fc33bb9SClaudio Fontana void whpx_destroy_vcpu(CPUState *cpu)
22291fc33bb9SClaudio Fontana {
22301fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
22311fc33bb9SClaudio Fontana     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
22321fc33bb9SClaudio Fontana 
22331fc33bb9SClaudio Fontana     whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
22341fc33bb9SClaudio Fontana     whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
22351fc33bb9SClaudio Fontana     g_free(cpu->hax_vcpu);
22361fc33bb9SClaudio Fontana     return;
22371fc33bb9SClaudio Fontana }
22381fc33bb9SClaudio Fontana 
22391fc33bb9SClaudio Fontana void whpx_vcpu_kick(CPUState *cpu)
22401fc33bb9SClaudio Fontana {
22411fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
22421fc33bb9SClaudio Fontana     whp_dispatch.WHvCancelRunVirtualProcessor(
22431fc33bb9SClaudio Fontana         whpx->partition, cpu->cpu_index, 0);
22441fc33bb9SClaudio Fontana }
22451fc33bb9SClaudio Fontana 
22461fc33bb9SClaudio Fontana /*
22471fc33bb9SClaudio Fontana  * Memory support.
22481fc33bb9SClaudio Fontana  */
22491fc33bb9SClaudio Fontana 
22501fc33bb9SClaudio Fontana static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size,
22511fc33bb9SClaudio Fontana                                 void *host_va, int add, int rom,
22521fc33bb9SClaudio Fontana                                 const char *name)
22531fc33bb9SClaudio Fontana {
22541fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
22551fc33bb9SClaudio Fontana     HRESULT hr;
22561fc33bb9SClaudio Fontana 
22571fc33bb9SClaudio Fontana     /*
22581fc33bb9SClaudio Fontana     if (add) {
22591fc33bb9SClaudio Fontana         printf("WHPX: ADD PA:%p Size:%p, Host:%p, %s, '%s'\n",
22601fc33bb9SClaudio Fontana                (void*)start_pa, (void*)size, host_va,
22611fc33bb9SClaudio Fontana                (rom ? "ROM" : "RAM"), name);
22621fc33bb9SClaudio Fontana     } else {
22631fc33bb9SClaudio Fontana         printf("WHPX: DEL PA:%p Size:%p, Host:%p,      '%s'\n",
22641fc33bb9SClaudio Fontana                (void*)start_pa, (void*)size, host_va, name);
22651fc33bb9SClaudio Fontana     }
22661fc33bb9SClaudio Fontana     */
22671fc33bb9SClaudio Fontana 
22681fc33bb9SClaudio Fontana     if (add) {
22691fc33bb9SClaudio Fontana         hr = whp_dispatch.WHvMapGpaRange(whpx->partition,
22701fc33bb9SClaudio Fontana                                          host_va,
22711fc33bb9SClaudio Fontana                                          start_pa,
22721fc33bb9SClaudio Fontana                                          size,
22731fc33bb9SClaudio Fontana                                          (WHvMapGpaRangeFlagRead |
22741fc33bb9SClaudio Fontana                                           WHvMapGpaRangeFlagExecute |
22751fc33bb9SClaudio Fontana                                           (rom ? 0 : WHvMapGpaRangeFlagWrite)));
22761fc33bb9SClaudio Fontana     } else {
22771fc33bb9SClaudio Fontana         hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
22781fc33bb9SClaudio Fontana                                            start_pa,
22791fc33bb9SClaudio Fontana                                            size);
22801fc33bb9SClaudio Fontana     }
22811fc33bb9SClaudio Fontana 
22821fc33bb9SClaudio Fontana     if (FAILED(hr)) {
22831fc33bb9SClaudio Fontana         error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes,"
22841fc33bb9SClaudio Fontana                      " Host:%p, hr=%08lx",
22851fc33bb9SClaudio Fontana                      (add ? "MAP" : "UNMAP"), name,
22861fc33bb9SClaudio Fontana                      (void *)(uintptr_t)start_pa, (void *)size, host_va, hr);
22871fc33bb9SClaudio Fontana     }
22881fc33bb9SClaudio Fontana }
22891fc33bb9SClaudio Fontana 
22901fc33bb9SClaudio Fontana static void whpx_process_section(MemoryRegionSection *section, int add)
22911fc33bb9SClaudio Fontana {
22921fc33bb9SClaudio Fontana     MemoryRegion *mr = section->mr;
22931fc33bb9SClaudio Fontana     hwaddr start_pa = section->offset_within_address_space;
22941fc33bb9SClaudio Fontana     ram_addr_t size = int128_get64(section->size);
22951fc33bb9SClaudio Fontana     unsigned int delta;
22961fc33bb9SClaudio Fontana     uint64_t host_va;
22971fc33bb9SClaudio Fontana 
22981fc33bb9SClaudio Fontana     if (!memory_region_is_ram(mr)) {
22991fc33bb9SClaudio Fontana         return;
23001fc33bb9SClaudio Fontana     }
23011fc33bb9SClaudio Fontana 
23028e3b0cbbSMarc-André Lureau     delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask());
23038e3b0cbbSMarc-André Lureau     delta &= ~qemu_real_host_page_mask();
23041fc33bb9SClaudio Fontana     if (delta > size) {
23051fc33bb9SClaudio Fontana         return;
23061fc33bb9SClaudio Fontana     }
23071fc33bb9SClaudio Fontana     start_pa += delta;
23081fc33bb9SClaudio Fontana     size -= delta;
23098e3b0cbbSMarc-André Lureau     size &= qemu_real_host_page_mask();
23108e3b0cbbSMarc-André Lureau     if (!size || (start_pa & ~qemu_real_host_page_mask())) {
23111fc33bb9SClaudio Fontana         return;
23121fc33bb9SClaudio Fontana     }
23131fc33bb9SClaudio Fontana 
23141fc33bb9SClaudio Fontana     host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
23151fc33bb9SClaudio Fontana             + section->offset_within_region + delta;
23161fc33bb9SClaudio Fontana 
23171fc33bb9SClaudio Fontana     whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,
23181fc33bb9SClaudio Fontana                         memory_region_is_rom(mr), mr->name);
23191fc33bb9SClaudio Fontana }
23201fc33bb9SClaudio Fontana 
23211fc33bb9SClaudio Fontana static void whpx_region_add(MemoryListener *listener,
23221fc33bb9SClaudio Fontana                            MemoryRegionSection *section)
23231fc33bb9SClaudio Fontana {
23241fc33bb9SClaudio Fontana     memory_region_ref(section->mr);
23251fc33bb9SClaudio Fontana     whpx_process_section(section, 1);
23261fc33bb9SClaudio Fontana }
23271fc33bb9SClaudio Fontana 
23281fc33bb9SClaudio Fontana static void whpx_region_del(MemoryListener *listener,
23291fc33bb9SClaudio Fontana                            MemoryRegionSection *section)
23301fc33bb9SClaudio Fontana {
23311fc33bb9SClaudio Fontana     whpx_process_section(section, 0);
23321fc33bb9SClaudio Fontana     memory_region_unref(section->mr);
23331fc33bb9SClaudio Fontana }
23341fc33bb9SClaudio Fontana 
23351fc33bb9SClaudio Fontana static void whpx_transaction_begin(MemoryListener *listener)
23361fc33bb9SClaudio Fontana {
23371fc33bb9SClaudio Fontana }
23381fc33bb9SClaudio Fontana 
23391fc33bb9SClaudio Fontana static void whpx_transaction_commit(MemoryListener *listener)
23401fc33bb9SClaudio Fontana {
23411fc33bb9SClaudio Fontana }
23421fc33bb9SClaudio Fontana 
23431fc33bb9SClaudio Fontana static void whpx_log_sync(MemoryListener *listener,
23441fc33bb9SClaudio Fontana                          MemoryRegionSection *section)
23451fc33bb9SClaudio Fontana {
23461fc33bb9SClaudio Fontana     MemoryRegion *mr = section->mr;
23471fc33bb9SClaudio Fontana 
23481fc33bb9SClaudio Fontana     if (!memory_region_is_ram(mr)) {
23491fc33bb9SClaudio Fontana         return;
23501fc33bb9SClaudio Fontana     }
23511fc33bb9SClaudio Fontana 
23521fc33bb9SClaudio Fontana     memory_region_set_dirty(mr, 0, int128_get64(section->size));
23531fc33bb9SClaudio Fontana }
23541fc33bb9SClaudio Fontana 
23551fc33bb9SClaudio Fontana static MemoryListener whpx_memory_listener = {
2356142518bdSPeter Xu     .name = "whpx",
23571fc33bb9SClaudio Fontana     .begin = whpx_transaction_begin,
23581fc33bb9SClaudio Fontana     .commit = whpx_transaction_commit,
23591fc33bb9SClaudio Fontana     .region_add = whpx_region_add,
23601fc33bb9SClaudio Fontana     .region_del = whpx_region_del,
23611fc33bb9SClaudio Fontana     .log_sync = whpx_log_sync,
23621fc33bb9SClaudio Fontana     .priority = 10,
23631fc33bb9SClaudio Fontana };
23641fc33bb9SClaudio Fontana 
23651fc33bb9SClaudio Fontana static void whpx_memory_init(void)
23661fc33bb9SClaudio Fontana {
23671fc33bb9SClaudio Fontana     memory_listener_register(&whpx_memory_listener, &address_space_memory);
23681fc33bb9SClaudio Fontana }
23691fc33bb9SClaudio Fontana 
23701fc33bb9SClaudio Fontana /*
23711fc33bb9SClaudio Fontana  * Load the functions from the given library, using the given handle. If a
23721fc33bb9SClaudio Fontana  * handle is provided, it is used, otherwise the library is opened. The
23731fc33bb9SClaudio Fontana  * handle will be updated on return with the opened one.
23741fc33bb9SClaudio Fontana  */
23751fc33bb9SClaudio Fontana static bool load_whp_dispatch_fns(HMODULE *handle,
23761fc33bb9SClaudio Fontana     WHPFunctionList function_list)
23771fc33bb9SClaudio Fontana {
23781fc33bb9SClaudio Fontana     HMODULE hLib = *handle;
23791fc33bb9SClaudio Fontana 
23801fc33bb9SClaudio Fontana     #define WINHV_PLATFORM_DLL "WinHvPlatform.dll"
23811fc33bb9SClaudio Fontana     #define WINHV_EMULATION_DLL "WinHvEmulation.dll"
23821fc33bb9SClaudio Fontana     #define WHP_LOAD_FIELD_OPTIONAL(return_type, function_name, signature) \
23831fc33bb9SClaudio Fontana         whp_dispatch.function_name = \
23841fc33bb9SClaudio Fontana             (function_name ## _t)GetProcAddress(hLib, #function_name); \
23851fc33bb9SClaudio Fontana 
23861fc33bb9SClaudio Fontana     #define WHP_LOAD_FIELD(return_type, function_name, signature) \
23871fc33bb9SClaudio Fontana         whp_dispatch.function_name = \
23881fc33bb9SClaudio Fontana             (function_name ## _t)GetProcAddress(hLib, #function_name); \
23891fc33bb9SClaudio Fontana         if (!whp_dispatch.function_name) { \
23901fc33bb9SClaudio Fontana             error_report("Could not load function %s", #function_name); \
23911fc33bb9SClaudio Fontana             goto error; \
23921fc33bb9SClaudio Fontana         } \
23931fc33bb9SClaudio Fontana 
23941fc33bb9SClaudio Fontana     #define WHP_LOAD_LIB(lib_name, handle_lib) \
23951fc33bb9SClaudio Fontana     if (!handle_lib) { \
23961fc33bb9SClaudio Fontana         handle_lib = LoadLibrary(lib_name); \
23971fc33bb9SClaudio Fontana         if (!handle_lib) { \
23981fc33bb9SClaudio Fontana             error_report("Could not load library %s.", lib_name); \
23991fc33bb9SClaudio Fontana             goto error; \
24001fc33bb9SClaudio Fontana         } \
24011fc33bb9SClaudio Fontana     } \
24021fc33bb9SClaudio Fontana 
24031fc33bb9SClaudio Fontana     switch (function_list) {
24041fc33bb9SClaudio Fontana     case WINHV_PLATFORM_FNS_DEFAULT:
24051fc33bb9SClaudio Fontana         WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
24061fc33bb9SClaudio Fontana         LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
24071fc33bb9SClaudio Fontana         break;
24081fc33bb9SClaudio Fontana 
24091fc33bb9SClaudio Fontana     case WINHV_EMULATION_FNS_DEFAULT:
24101fc33bb9SClaudio Fontana         WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)
24111fc33bb9SClaudio Fontana         LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
24121fc33bb9SClaudio Fontana         break;
24131fc33bb9SClaudio Fontana 
24141fc33bb9SClaudio Fontana     case WINHV_PLATFORM_FNS_SUPPLEMENTAL:
24151fc33bb9SClaudio Fontana         WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
24161fc33bb9SClaudio Fontana         LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_LOAD_FIELD_OPTIONAL)
24171fc33bb9SClaudio Fontana         break;
24181fc33bb9SClaudio Fontana     }
24191fc33bb9SClaudio Fontana 
24201fc33bb9SClaudio Fontana     *handle = hLib;
24211fc33bb9SClaudio Fontana     return true;
24221fc33bb9SClaudio Fontana 
24231fc33bb9SClaudio Fontana error:
24241fc33bb9SClaudio Fontana     if (hLib) {
24251fc33bb9SClaudio Fontana         FreeLibrary(hLib);
24261fc33bb9SClaudio Fontana     }
24271fc33bb9SClaudio Fontana 
24281fc33bb9SClaudio Fontana     return false;
24291fc33bb9SClaudio Fontana }
24301fc33bb9SClaudio Fontana 
24311fc33bb9SClaudio Fontana static void whpx_set_kernel_irqchip(Object *obj, Visitor *v,
24321fc33bb9SClaudio Fontana                                    const char *name, void *opaque,
24331fc33bb9SClaudio Fontana                                    Error **errp)
24341fc33bb9SClaudio Fontana {
24351fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
24361fc33bb9SClaudio Fontana     OnOffSplit mode;
24371fc33bb9SClaudio Fontana 
24381fc33bb9SClaudio Fontana     if (!visit_type_OnOffSplit(v, name, &mode, errp)) {
24391fc33bb9SClaudio Fontana         return;
24401fc33bb9SClaudio Fontana     }
24411fc33bb9SClaudio Fontana 
24421fc33bb9SClaudio Fontana     switch (mode) {
24431fc33bb9SClaudio Fontana     case ON_OFF_SPLIT_ON:
24441fc33bb9SClaudio Fontana         whpx->kernel_irqchip_allowed = true;
24451fc33bb9SClaudio Fontana         whpx->kernel_irqchip_required = true;
24461fc33bb9SClaudio Fontana         break;
24471fc33bb9SClaudio Fontana 
24481fc33bb9SClaudio Fontana     case ON_OFF_SPLIT_OFF:
24491fc33bb9SClaudio Fontana         whpx->kernel_irqchip_allowed = false;
24501fc33bb9SClaudio Fontana         whpx->kernel_irqchip_required = false;
24511fc33bb9SClaudio Fontana         break;
24521fc33bb9SClaudio Fontana 
24531fc33bb9SClaudio Fontana     case ON_OFF_SPLIT_SPLIT:
24541fc33bb9SClaudio Fontana         error_setg(errp, "WHPX: split irqchip currently not supported");
24551fc33bb9SClaudio Fontana         error_append_hint(errp,
24561fc33bb9SClaudio Fontana             "Try without kernel-irqchip or with kernel-irqchip=on|off");
24571fc33bb9SClaudio Fontana         break;
24581fc33bb9SClaudio Fontana 
24591fc33bb9SClaudio Fontana     default:
24601fc33bb9SClaudio Fontana         /*
24611fc33bb9SClaudio Fontana          * The value was checked in visit_type_OnOffSplit() above. If
24621fc33bb9SClaudio Fontana          * we get here, then something is wrong in QEMU.
24631fc33bb9SClaudio Fontana          */
24641fc33bb9SClaudio Fontana         abort();
24651fc33bb9SClaudio Fontana     }
24661fc33bb9SClaudio Fontana }
24671fc33bb9SClaudio Fontana 
24681fc33bb9SClaudio Fontana /*
24691fc33bb9SClaudio Fontana  * Partition support
24701fc33bb9SClaudio Fontana  */
24711fc33bb9SClaudio Fontana 
24721fc33bb9SClaudio Fontana static int whpx_accel_init(MachineState *ms)
24731fc33bb9SClaudio Fontana {
24741fc33bb9SClaudio Fontana     struct whpx_state *whpx;
24751fc33bb9SClaudio Fontana     int ret;
24761fc33bb9SClaudio Fontana     HRESULT hr;
24771fc33bb9SClaudio Fontana     WHV_CAPABILITY whpx_cap;
24781fc33bb9SClaudio Fontana     UINT32 whpx_cap_size;
24791fc33bb9SClaudio Fontana     WHV_PARTITION_PROPERTY prop;
24801fc33bb9SClaudio Fontana     UINT32 cpuidExitList[] = {1, 0x80000001};
24811fc33bb9SClaudio Fontana     WHV_CAPABILITY_FEATURES features = {0};
24821fc33bb9SClaudio Fontana 
24831fc33bb9SClaudio Fontana     whpx = &whpx_global;
24841fc33bb9SClaudio Fontana 
24851fc33bb9SClaudio Fontana     if (!init_whp_dispatch()) {
24861fc33bb9SClaudio Fontana         ret = -ENOSYS;
24871fc33bb9SClaudio Fontana         goto error;
24881fc33bb9SClaudio Fontana     }
24891fc33bb9SClaudio Fontana 
24901fc33bb9SClaudio Fontana     whpx->mem_quota = ms->ram_size;
24911fc33bb9SClaudio Fontana 
24921fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvGetCapability(
24931fc33bb9SClaudio Fontana         WHvCapabilityCodeHypervisorPresent, &whpx_cap,
24941fc33bb9SClaudio Fontana         sizeof(whpx_cap), &whpx_cap_size);
24951fc33bb9SClaudio Fontana     if (FAILED(hr) || !whpx_cap.HypervisorPresent) {
24961fc33bb9SClaudio Fontana         error_report("WHPX: No accelerator found, hr=%08lx", hr);
24971fc33bb9SClaudio Fontana         ret = -ENOSPC;
24981fc33bb9SClaudio Fontana         goto error;
24991fc33bb9SClaudio Fontana     }
25001fc33bb9SClaudio Fontana 
25011fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvGetCapability(
25021fc33bb9SClaudio Fontana         WHvCapabilityCodeFeatures, &features, sizeof(features), NULL);
25031fc33bb9SClaudio Fontana     if (FAILED(hr)) {
25041fc33bb9SClaudio Fontana         error_report("WHPX: Failed to query capabilities, hr=%08lx", hr);
25051fc33bb9SClaudio Fontana         ret = -EINVAL;
25061fc33bb9SClaudio Fontana         goto error;
25071fc33bb9SClaudio Fontana     }
25081fc33bb9SClaudio Fontana 
25091fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvCreatePartition(&whpx->partition);
25101fc33bb9SClaudio Fontana     if (FAILED(hr)) {
25111fc33bb9SClaudio Fontana         error_report("WHPX: Failed to create partition, hr=%08lx", hr);
25121fc33bb9SClaudio Fontana         ret = -EINVAL;
25131fc33bb9SClaudio Fontana         goto error;
25141fc33bb9SClaudio Fontana     }
25151fc33bb9SClaudio Fontana 
25161fc33bb9SClaudio Fontana     memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
25171fc33bb9SClaudio Fontana     prop.ProcessorCount = ms->smp.cpus;
25181fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvSetPartitionProperty(
25191fc33bb9SClaudio Fontana         whpx->partition,
25201fc33bb9SClaudio Fontana         WHvPartitionPropertyCodeProcessorCount,
25211fc33bb9SClaudio Fontana         &prop,
25221fc33bb9SClaudio Fontana         sizeof(WHV_PARTITION_PROPERTY));
25231fc33bb9SClaudio Fontana 
25241fc33bb9SClaudio Fontana     if (FAILED(hr)) {
25251fc33bb9SClaudio Fontana         error_report("WHPX: Failed to set partition core count to %d,"
25261fc33bb9SClaudio Fontana                      " hr=%08lx", ms->smp.cores, hr);
25271fc33bb9SClaudio Fontana         ret = -EINVAL;
25281fc33bb9SClaudio Fontana         goto error;
25291fc33bb9SClaudio Fontana     }
25301fc33bb9SClaudio Fontana 
25311fc33bb9SClaudio Fontana     /*
25321fc33bb9SClaudio Fontana      * Error out if WHP doesn't support apic emulation and user is requiring
25331fc33bb9SClaudio Fontana      * it.
25341fc33bb9SClaudio Fontana      */
25351fc33bb9SClaudio Fontana     if (whpx->kernel_irqchip_required && (!features.LocalApicEmulation ||
25361fc33bb9SClaudio Fontana             !whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2)) {
25371fc33bb9SClaudio Fontana         error_report("WHPX: kernel irqchip requested, but unavailable. "
25381fc33bb9SClaudio Fontana             "Try without kernel-irqchip or with kernel-irqchip=off");
25391fc33bb9SClaudio Fontana         ret = -EINVAL;
25401fc33bb9SClaudio Fontana         goto error;
25411fc33bb9SClaudio Fontana     }
25421fc33bb9SClaudio Fontana 
25431fc33bb9SClaudio Fontana     if (whpx->kernel_irqchip_allowed && features.LocalApicEmulation &&
25441fc33bb9SClaudio Fontana         whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2) {
25451fc33bb9SClaudio Fontana         WHV_X64_LOCAL_APIC_EMULATION_MODE mode =
25461fc33bb9SClaudio Fontana             WHvX64LocalApicEmulationModeXApic;
25471fc33bb9SClaudio Fontana         printf("WHPX: setting APIC emulation mode in the hypervisor\n");
25481fc33bb9SClaudio Fontana         hr = whp_dispatch.WHvSetPartitionProperty(
25491fc33bb9SClaudio Fontana             whpx->partition,
25501fc33bb9SClaudio Fontana             WHvPartitionPropertyCodeLocalApicEmulationMode,
25511fc33bb9SClaudio Fontana             &mode,
25521fc33bb9SClaudio Fontana             sizeof(mode));
25531fc33bb9SClaudio Fontana         if (FAILED(hr)) {
25541fc33bb9SClaudio Fontana             error_report("WHPX: Failed to enable kernel irqchip hr=%08lx", hr);
25551fc33bb9SClaudio Fontana             if (whpx->kernel_irqchip_required) {
25561fc33bb9SClaudio Fontana                 error_report("WHPX: kernel irqchip requested, but unavailable");
25571fc33bb9SClaudio Fontana                 ret = -EINVAL;
25581fc33bb9SClaudio Fontana                 goto error;
25591fc33bb9SClaudio Fontana             }
25601fc33bb9SClaudio Fontana         } else {
25611fc33bb9SClaudio Fontana             whpx->apic_in_platform = true;
25621fc33bb9SClaudio Fontana         }
25631fc33bb9SClaudio Fontana     }
25641fc33bb9SClaudio Fontana 
25651fc33bb9SClaudio Fontana     /* Register for MSR and CPUID exits */
25661fc33bb9SClaudio Fontana     memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
25671fc33bb9SClaudio Fontana     prop.ExtendedVmExits.X64MsrExit = 1;
25681fc33bb9SClaudio Fontana     prop.ExtendedVmExits.X64CpuidExit = 1;
2569*d7482ffeSIvan Shcherbakov     prop.ExtendedVmExits.ExceptionExit = 1;
25701fc33bb9SClaudio Fontana     if (whpx_apic_in_platform()) {
25711fc33bb9SClaudio Fontana         prop.ExtendedVmExits.X64ApicInitSipiExitTrap = 1;
25721fc33bb9SClaudio Fontana     }
25731fc33bb9SClaudio Fontana 
25741fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvSetPartitionProperty(
25751fc33bb9SClaudio Fontana             whpx->partition,
25761fc33bb9SClaudio Fontana             WHvPartitionPropertyCodeExtendedVmExits,
25771fc33bb9SClaudio Fontana             &prop,
25781fc33bb9SClaudio Fontana             sizeof(WHV_PARTITION_PROPERTY));
25791fc33bb9SClaudio Fontana     if (FAILED(hr)) {
25801fc33bb9SClaudio Fontana         error_report("WHPX: Failed to enable MSR & CPUIDexit, hr=%08lx", hr);
25811fc33bb9SClaudio Fontana         ret = -EINVAL;
25821fc33bb9SClaudio Fontana         goto error;
25831fc33bb9SClaudio Fontana     }
25841fc33bb9SClaudio Fontana 
25851fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvSetPartitionProperty(
25861fc33bb9SClaudio Fontana         whpx->partition,
25871fc33bb9SClaudio Fontana         WHvPartitionPropertyCodeCpuidExitList,
25881fc33bb9SClaudio Fontana         cpuidExitList,
25891fc33bb9SClaudio Fontana         RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32));
25901fc33bb9SClaudio Fontana 
25911fc33bb9SClaudio Fontana     if (FAILED(hr)) {
25921fc33bb9SClaudio Fontana         error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx",
25931fc33bb9SClaudio Fontana                      hr);
25941fc33bb9SClaudio Fontana         ret = -EINVAL;
25951fc33bb9SClaudio Fontana         goto error;
25961fc33bb9SClaudio Fontana     }
25971fc33bb9SClaudio Fontana 
2598*d7482ffeSIvan Shcherbakov     /*
2599*d7482ffeSIvan Shcherbakov      * We do not want to intercept any exceptions from the guest,
2600*d7482ffeSIvan Shcherbakov      * until we actually start debugging with gdb.
2601*d7482ffeSIvan Shcherbakov      */
2602*d7482ffeSIvan Shcherbakov     whpx->exception_exit_bitmap = -1;
2603*d7482ffeSIvan Shcherbakov     hr = whpx_set_exception_exit_bitmap(0);
2604*d7482ffeSIvan Shcherbakov 
2605*d7482ffeSIvan Shcherbakov     if (FAILED(hr)) {
2606*d7482ffeSIvan Shcherbakov         error_report("WHPX: Failed to set exception exit bitmap, hr=%08lx", hr);
2607*d7482ffeSIvan Shcherbakov         ret = -EINVAL;
2608*d7482ffeSIvan Shcherbakov         goto error;
2609*d7482ffeSIvan Shcherbakov     }
2610*d7482ffeSIvan Shcherbakov 
26111fc33bb9SClaudio Fontana     hr = whp_dispatch.WHvSetupPartition(whpx->partition);
26121fc33bb9SClaudio Fontana     if (FAILED(hr)) {
26131fc33bb9SClaudio Fontana         error_report("WHPX: Failed to setup partition, hr=%08lx", hr);
26141fc33bb9SClaudio Fontana         ret = -EINVAL;
26151fc33bb9SClaudio Fontana         goto error;
26161fc33bb9SClaudio Fontana     }
26171fc33bb9SClaudio Fontana 
26181fc33bb9SClaudio Fontana     whpx_memory_init();
26191fc33bb9SClaudio Fontana 
26201fc33bb9SClaudio Fontana     printf("Windows Hypervisor Platform accelerator is operational\n");
26211fc33bb9SClaudio Fontana     return 0;
26221fc33bb9SClaudio Fontana 
26231fc33bb9SClaudio Fontana error:
26241fc33bb9SClaudio Fontana 
26251fc33bb9SClaudio Fontana     if (NULL != whpx->partition) {
26261fc33bb9SClaudio Fontana         whp_dispatch.WHvDeletePartition(whpx->partition);
26271fc33bb9SClaudio Fontana         whpx->partition = NULL;
26281fc33bb9SClaudio Fontana     }
26291fc33bb9SClaudio Fontana 
26301fc33bb9SClaudio Fontana     return ret;
26311fc33bb9SClaudio Fontana }
26321fc33bb9SClaudio Fontana 
26331fc33bb9SClaudio Fontana int whpx_enabled(void)
26341fc33bb9SClaudio Fontana {
26351fc33bb9SClaudio Fontana     return whpx_allowed;
26361fc33bb9SClaudio Fontana }
26371fc33bb9SClaudio Fontana 
263884f4ef17SPaolo Bonzini bool whpx_apic_in_platform(void) {
263984f4ef17SPaolo Bonzini     return whpx_global.apic_in_platform;
264084f4ef17SPaolo Bonzini }
264184f4ef17SPaolo Bonzini 
26421fc33bb9SClaudio Fontana static void whpx_accel_class_init(ObjectClass *oc, void *data)
26431fc33bb9SClaudio Fontana {
26441fc33bb9SClaudio Fontana     AccelClass *ac = ACCEL_CLASS(oc);
26451fc33bb9SClaudio Fontana     ac->name = "WHPX";
26461fc33bb9SClaudio Fontana     ac->init_machine = whpx_accel_init;
26471fc33bb9SClaudio Fontana     ac->allowed = &whpx_allowed;
26481fc33bb9SClaudio Fontana 
26491fc33bb9SClaudio Fontana     object_class_property_add(oc, "kernel-irqchip", "on|off|split",
26501fc33bb9SClaudio Fontana         NULL, whpx_set_kernel_irqchip,
26511fc33bb9SClaudio Fontana         NULL, NULL);
26521fc33bb9SClaudio Fontana     object_class_property_set_description(oc, "kernel-irqchip",
26531fc33bb9SClaudio Fontana         "Configure WHPX in-kernel irqchip");
26541fc33bb9SClaudio Fontana }
26551fc33bb9SClaudio Fontana 
26561fc33bb9SClaudio Fontana static void whpx_accel_instance_init(Object *obj)
26571fc33bb9SClaudio Fontana {
26581fc33bb9SClaudio Fontana     struct whpx_state *whpx = &whpx_global;
26591fc33bb9SClaudio Fontana 
26601fc33bb9SClaudio Fontana     memset(whpx, 0, sizeof(struct whpx_state));
26611fc33bb9SClaudio Fontana     /* Turn on kernel-irqchip, by default */
26621fc33bb9SClaudio Fontana     whpx->kernel_irqchip_allowed = true;
26631fc33bb9SClaudio Fontana }
26641fc33bb9SClaudio Fontana 
26651fc33bb9SClaudio Fontana static const TypeInfo whpx_accel_type = {
26661fc33bb9SClaudio Fontana     .name = ACCEL_CLASS_NAME("whpx"),
26671fc33bb9SClaudio Fontana     .parent = TYPE_ACCEL,
26681fc33bb9SClaudio Fontana     .instance_init = whpx_accel_instance_init,
26691fc33bb9SClaudio Fontana     .class_init = whpx_accel_class_init,
26701fc33bb9SClaudio Fontana };
26711fc33bb9SClaudio Fontana 
26721fc33bb9SClaudio Fontana static void whpx_type_init(void)
26731fc33bb9SClaudio Fontana {
26741fc33bb9SClaudio Fontana     type_register_static(&whpx_accel_type);
26751fc33bb9SClaudio Fontana }
26761fc33bb9SClaudio Fontana 
26771fc33bb9SClaudio Fontana bool init_whp_dispatch(void)
26781fc33bb9SClaudio Fontana {
26791fc33bb9SClaudio Fontana     if (whp_dispatch_initialized) {
26801fc33bb9SClaudio Fontana         return true;
26811fc33bb9SClaudio Fontana     }
26821fc33bb9SClaudio Fontana 
26831fc33bb9SClaudio Fontana     if (!load_whp_dispatch_fns(&hWinHvPlatform, WINHV_PLATFORM_FNS_DEFAULT)) {
26841fc33bb9SClaudio Fontana         goto error;
26851fc33bb9SClaudio Fontana     }
26861fc33bb9SClaudio Fontana 
26871fc33bb9SClaudio Fontana     if (!load_whp_dispatch_fns(&hWinHvEmulation, WINHV_EMULATION_FNS_DEFAULT)) {
26881fc33bb9SClaudio Fontana         goto error;
26891fc33bb9SClaudio Fontana     }
26901fc33bb9SClaudio Fontana 
26911fc33bb9SClaudio Fontana     assert(load_whp_dispatch_fns(&hWinHvPlatform,
26921fc33bb9SClaudio Fontana         WINHV_PLATFORM_FNS_SUPPLEMENTAL));
26931fc33bb9SClaudio Fontana     whp_dispatch_initialized = true;
26941fc33bb9SClaudio Fontana 
26951fc33bb9SClaudio Fontana     return true;
26961fc33bb9SClaudio Fontana error:
26971fc33bb9SClaudio Fontana     if (hWinHvPlatform) {
26981fc33bb9SClaudio Fontana         FreeLibrary(hWinHvPlatform);
26991fc33bb9SClaudio Fontana     }
27001fc33bb9SClaudio Fontana 
27011fc33bb9SClaudio Fontana     if (hWinHvEmulation) {
27021fc33bb9SClaudio Fontana         FreeLibrary(hWinHvEmulation);
27031fc33bb9SClaudio Fontana     }
27041fc33bb9SClaudio Fontana 
27051fc33bb9SClaudio Fontana     return false;
27061fc33bb9SClaudio Fontana }
27071fc33bb9SClaudio Fontana 
27081fc33bb9SClaudio Fontana type_init(whpx_type_init);
2709