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"
154ea5fe99SAlex Bennée #include "gdbstub/helpers.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"
227f54640bSBernhard Beschow #include "hw/intc/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
34641b8417SPhilippe Mathieu-Daudé #include <winhvplatform.h>
35641b8417SPhilippe Mathieu-Daudé #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
151d7482ffeSIvan Shcherbakov /*
152d7482ffeSIvan Shcherbakov * The current implementation of instruction stepping sets the TF flag
153d7482ffeSIvan Shcherbakov * in RFLAGS, causing the CPU to raise an INT1 after each instruction.
154d7482ffeSIvan Shcherbakov * This corresponds to the WHvX64ExceptionTypeDebugTrapOrFault exception.
155d7482ffeSIvan Shcherbakov *
156d7482ffeSIvan Shcherbakov * This approach has a few limitations:
157d7482ffeSIvan Shcherbakov * 1. Stepping over a PUSHF/SAHF instruction will save the TF flag
158d7482ffeSIvan Shcherbakov * along with the other flags, possibly restoring it later. It would
159d7482ffeSIvan Shcherbakov * result in another INT1 when the flags are restored, triggering
160d7482ffeSIvan Shcherbakov * a stop in gdb that could be cleared by doing another step.
161d7482ffeSIvan Shcherbakov *
162d7482ffeSIvan Shcherbakov * Stepping over a POPF/LAHF instruction will let it overwrite the
163d7482ffeSIvan Shcherbakov * TF flags, ending the stepping mode.
164d7482ffeSIvan Shcherbakov *
165d7482ffeSIvan Shcherbakov * 2. Stepping over an instruction raising an exception (e.g. INT, DIV,
166d7482ffeSIvan Shcherbakov * or anything that could result in a page fault) will save the flags
167d7482ffeSIvan Shcherbakov * to the stack, clear the TF flag, and let the guest execute the
168d7482ffeSIvan Shcherbakov * handler. Normally, the guest will restore the original flags,
169d7482ffeSIvan Shcherbakov * that will continue single-stepping.
170d7482ffeSIvan Shcherbakov *
171d7482ffeSIvan Shcherbakov * 3. Debuggers running on the guest may wish to set TF to do instruction
172d7482ffeSIvan Shcherbakov * stepping. INT1 events generated by it would be intercepted by us,
173d7482ffeSIvan Shcherbakov * as long as the gdb is connected to QEMU.
174d7482ffeSIvan Shcherbakov *
175d7482ffeSIvan Shcherbakov * In practice this means that:
176d7482ffeSIvan Shcherbakov * 1. Stepping through flags-modifying instructions may cause gdb to
177d7482ffeSIvan Shcherbakov * continue or stop in unexpected places. This will be fully recoverable
178d7482ffeSIvan Shcherbakov * and will not crash the target.
179d7482ffeSIvan Shcherbakov *
180d7482ffeSIvan Shcherbakov * 2. Stepping over an instruction that triggers an exception will step
181d7482ffeSIvan Shcherbakov * over the exception handler, not into it.
182d7482ffeSIvan Shcherbakov *
183d7482ffeSIvan Shcherbakov * 3. Debugging the guest via gdb, while running debugger on the guest
184d7482ffeSIvan Shcherbakov * at the same time may lead to unexpected effects. Removing all
185d7482ffeSIvan Shcherbakov * breakpoints set via QEMU will prevent any further interference
186d7482ffeSIvan Shcherbakov * with the guest-level debuggers.
187d7482ffeSIvan Shcherbakov *
188d7482ffeSIvan Shcherbakov * The limitations can be addressed as shown below:
189d7482ffeSIvan Shcherbakov * 1. PUSHF/SAHF/POPF/LAHF/IRET instructions can be emulated instead of
190d7482ffeSIvan Shcherbakov * stepping through them. The exact semantics of the instructions is
191d7482ffeSIvan Shcherbakov * defined in the "Combined Volume Set of Intel 64 and IA-32
192d7482ffeSIvan Shcherbakov * Architectures Software Developer's Manuals", however it involves a
193d7482ffeSIvan Shcherbakov * fair amount of corner cases due to compatibility with real mode,
194d7482ffeSIvan Shcherbakov * virtual 8086 mode, and differences between 64-bit and 32-bit modes.
195d7482ffeSIvan Shcherbakov *
196d7482ffeSIvan Shcherbakov * 2. We could step into the guest's exception handlers using the following
197d7482ffeSIvan Shcherbakov * sequence:
198d7482ffeSIvan Shcherbakov * a. Temporarily enable catching of all exception types via
199d7482ffeSIvan Shcherbakov * whpx_set_exception_exit_bitmap().
200d7482ffeSIvan Shcherbakov * b. Once an exception is intercepted, read the IDT/GDT and locate
201d7482ffeSIvan Shcherbakov * the original handler.
202d7482ffeSIvan Shcherbakov * c. Patch the original handler, injecting an INT3 at the beginning.
203d7482ffeSIvan Shcherbakov * d. Update the exception exit bitmap to only catch the
204d7482ffeSIvan Shcherbakov * WHvX64ExceptionTypeBreakpointTrap exception.
205d7482ffeSIvan Shcherbakov * e. Let the affected CPU run in the exclusive mode.
206d7482ffeSIvan Shcherbakov * f. Restore the original handler and the exception exit bitmap.
207d7482ffeSIvan Shcherbakov * Note that handling all corner cases related to IDT/GDT is harder
208d7482ffeSIvan Shcherbakov * than it may seem. See x86_cpu_get_phys_page_attrs_debug() for a
209d7482ffeSIvan Shcherbakov * rough idea.
210d7482ffeSIvan Shcherbakov *
211d7482ffeSIvan Shcherbakov * 3. In order to properly support guest-level debugging in parallel with
212d7482ffeSIvan Shcherbakov * the QEMU-level debugging, we would need to be able to pass some INT1
213d7482ffeSIvan Shcherbakov * events to the guest. This could be done via the following methods:
214d7482ffeSIvan Shcherbakov * a. Using the WHvRegisterPendingEvent register. As of Windows 21H1,
215d7482ffeSIvan Shcherbakov * it seems to only work for interrupts and not software
216d7482ffeSIvan Shcherbakov * exceptions.
217d7482ffeSIvan Shcherbakov * b. Locating and patching the original handler by parsing IDT/GDT.
218d7482ffeSIvan Shcherbakov * This involves relatively complex logic outlined in the previous
219d7482ffeSIvan Shcherbakov * paragraph.
220d7482ffeSIvan Shcherbakov * c. Emulating the exception invocation (i.e. manually updating RIP,
221d7482ffeSIvan Shcherbakov * RFLAGS, and pushing the old values to stack). This is even more
222d7482ffeSIvan Shcherbakov * complicated than the previous option, since it involves checking
223d7482ffeSIvan Shcherbakov * CPL, gate attributes, and doing various adjustments depending
224d7482ffeSIvan Shcherbakov * on the current CPU mode, whether the CPL is changing, etc.
225d7482ffeSIvan Shcherbakov */
226d7482ffeSIvan Shcherbakov typedef enum WhpxStepMode {
227d7482ffeSIvan Shcherbakov WHPX_STEP_NONE = 0,
228d7482ffeSIvan Shcherbakov /* Halt other VCPUs */
229d7482ffeSIvan Shcherbakov WHPX_STEP_EXCLUSIVE,
230d7482ffeSIvan Shcherbakov } WhpxStepMode;
231d7482ffeSIvan Shcherbakov
232b4f879a4SPhilippe Mathieu-Daudé struct AccelCPUState {
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;
2409ad49538SPhilippe Mathieu-Daudé bool dirty;
2411fc33bb9SClaudio Fontana
2421fc33bb9SClaudio Fontana /* Must be the last field as it may have a tail */
2431fc33bb9SClaudio Fontana WHV_RUN_VP_EXIT_CONTEXT exit_ctx;
2441fc33bb9SClaudio Fontana };
2451fc33bb9SClaudio Fontana
2461fc33bb9SClaudio Fontana static bool whpx_allowed;
2471fc33bb9SClaudio Fontana static bool whp_dispatch_initialized;
2481fc33bb9SClaudio Fontana static HMODULE hWinHvPlatform, hWinHvEmulation;
2491fc33bb9SClaudio Fontana static uint32_t max_vcpu_index;
250b6b3da99SSunil Muthuswamy static WHV_PROCESSOR_XSAVE_FEATURES whpx_xsave_cap;
251b6b3da99SSunil Muthuswamy
2521fc33bb9SClaudio Fontana struct whpx_state whpx_global;
2531fc33bb9SClaudio Fontana struct WHPDispatch whp_dispatch;
2541fc33bb9SClaudio Fontana
whpx_has_xsave(void)255b6b3da99SSunil Muthuswamy static bool whpx_has_xsave(void)
256b6b3da99SSunil Muthuswamy {
257b6b3da99SSunil Muthuswamy return whpx_xsave_cap.XsaveSupport;
258b6b3da99SSunil Muthuswamy }
2591fc33bb9SClaudio Fontana
whpx_seg_q2h(const SegmentCache * qs,int v86,int r86)2601fc33bb9SClaudio Fontana static WHV_X64_SEGMENT_REGISTER whpx_seg_q2h(const SegmentCache *qs, int v86,
2611fc33bb9SClaudio Fontana int r86)
2621fc33bb9SClaudio Fontana {
2631fc33bb9SClaudio Fontana WHV_X64_SEGMENT_REGISTER hs;
2641fc33bb9SClaudio Fontana unsigned flags = qs->flags;
2651fc33bb9SClaudio Fontana
2661fc33bb9SClaudio Fontana hs.Base = qs->base;
2671fc33bb9SClaudio Fontana hs.Limit = qs->limit;
2681fc33bb9SClaudio Fontana hs.Selector = qs->selector;
2691fc33bb9SClaudio Fontana
2701fc33bb9SClaudio Fontana if (v86) {
2711fc33bb9SClaudio Fontana hs.Attributes = 0;
2721fc33bb9SClaudio Fontana hs.SegmentType = 3;
2731fc33bb9SClaudio Fontana hs.Present = 1;
2741fc33bb9SClaudio Fontana hs.DescriptorPrivilegeLevel = 3;
2751fc33bb9SClaudio Fontana hs.NonSystemSegment = 1;
2761fc33bb9SClaudio Fontana
2771fc33bb9SClaudio Fontana } else {
2781fc33bb9SClaudio Fontana hs.Attributes = (flags >> DESC_TYPE_SHIFT);
2791fc33bb9SClaudio Fontana
2801fc33bb9SClaudio Fontana if (r86) {
2811fc33bb9SClaudio Fontana /* hs.Base &= 0xfffff; */
2821fc33bb9SClaudio Fontana }
2831fc33bb9SClaudio Fontana }
2841fc33bb9SClaudio Fontana
2851fc33bb9SClaudio Fontana return hs;
2861fc33bb9SClaudio Fontana }
2871fc33bb9SClaudio Fontana
whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER * hs)2881fc33bb9SClaudio Fontana static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs)
2891fc33bb9SClaudio Fontana {
2901fc33bb9SClaudio Fontana SegmentCache qs;
2911fc33bb9SClaudio Fontana
2921fc33bb9SClaudio Fontana qs.base = hs->Base;
2931fc33bb9SClaudio Fontana qs.limit = hs->Limit;
2941fc33bb9SClaudio Fontana qs.selector = hs->Selector;
2951fc33bb9SClaudio Fontana
2961fc33bb9SClaudio Fontana qs.flags = ((uint32_t)hs->Attributes) << DESC_TYPE_SHIFT;
2971fc33bb9SClaudio Fontana
2981fc33bb9SClaudio Fontana return qs;
2991fc33bb9SClaudio Fontana }
3001fc33bb9SClaudio Fontana
301b6b3da99SSunil Muthuswamy /* X64 Extended Control Registers */
whpx_set_xcrs(CPUState * cpu)302b6b3da99SSunil Muthuswamy static void whpx_set_xcrs(CPUState *cpu)
303b6b3da99SSunil Muthuswamy {
304b6b3da99SSunil Muthuswamy HRESULT hr;
305b6b3da99SSunil Muthuswamy struct whpx_state *whpx = &whpx_global;
306b6b3da99SSunil Muthuswamy WHV_REGISTER_VALUE xcr0;
307b6b3da99SSunil Muthuswamy WHV_REGISTER_NAME xcr0_name = WHvX64RegisterXCr0;
308b6b3da99SSunil Muthuswamy
309b6b3da99SSunil Muthuswamy if (!whpx_has_xsave()) {
310b6b3da99SSunil Muthuswamy return;
311b6b3da99SSunil Muthuswamy }
312b6b3da99SSunil Muthuswamy
313b6b3da99SSunil Muthuswamy /* Only xcr0 is supported by the hypervisor currently */
31494956d7bSPhilippe Mathieu-Daudé xcr0.Reg64 = cpu_env(cpu)->xcr0;
315b6b3da99SSunil Muthuswamy hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
316b6b3da99SSunil Muthuswamy whpx->partition, cpu->cpu_index, &xcr0_name, 1, &xcr0);
317b6b3da99SSunil Muthuswamy if (FAILED(hr)) {
318b6b3da99SSunil Muthuswamy error_report("WHPX: Failed to set register xcr0, hr=%08lx", hr);
319b6b3da99SSunil Muthuswamy }
320b6b3da99SSunil Muthuswamy }
321b6b3da99SSunil Muthuswamy
whpx_set_tsc(CPUState * cpu)3221fc33bb9SClaudio Fontana static int whpx_set_tsc(CPUState *cpu)
3231fc33bb9SClaudio Fontana {
3241fc33bb9SClaudio Fontana WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc;
3251fc33bb9SClaudio Fontana WHV_REGISTER_VALUE tsc_val;
3261fc33bb9SClaudio Fontana HRESULT hr;
3271fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
3281fc33bb9SClaudio Fontana
3291fc33bb9SClaudio Fontana /*
3301fc33bb9SClaudio Fontana * Suspend the partition prior to setting the TSC to reduce the variance
3311fc33bb9SClaudio Fontana * in TSC across vCPUs. When the first vCPU runs post suspend, the
3321fc33bb9SClaudio Fontana * partition is automatically resumed.
3331fc33bb9SClaudio Fontana */
3341fc33bb9SClaudio Fontana if (whp_dispatch.WHvSuspendPartitionTime) {
3351fc33bb9SClaudio Fontana
3361fc33bb9SClaudio Fontana /*
3371fc33bb9SClaudio Fontana * Unable to suspend partition while setting TSC is not a fatal
3381fc33bb9SClaudio Fontana * error. It just increases the likelihood of TSC variance between
3391fc33bb9SClaudio Fontana * vCPUs and some guest OS are able to handle that just fine.
3401fc33bb9SClaudio Fontana */
3411fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSuspendPartitionTime(whpx->partition);
3421fc33bb9SClaudio Fontana if (FAILED(hr)) {
3431fc33bb9SClaudio Fontana warn_report("WHPX: Failed to suspend partition, hr=%08lx", hr);
3441fc33bb9SClaudio Fontana }
3451fc33bb9SClaudio Fontana }
3461fc33bb9SClaudio Fontana
34794956d7bSPhilippe Mathieu-Daudé tsc_val.Reg64 = cpu_env(cpu)->tsc;
3481fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
3491fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val);
3501fc33bb9SClaudio Fontana if (FAILED(hr)) {
3511fc33bb9SClaudio Fontana error_report("WHPX: Failed to set TSC, hr=%08lx", hr);
3521fc33bb9SClaudio Fontana return -1;
3531fc33bb9SClaudio Fontana }
3541fc33bb9SClaudio Fontana
3551fc33bb9SClaudio Fontana return 0;
3561fc33bb9SClaudio Fontana }
3571fc33bb9SClaudio Fontana
3585ad93fd3SIvan Shcherbakov /*
3595ad93fd3SIvan Shcherbakov * The CR8 register in the CPU is mapped to the TPR register of the APIC,
3605ad93fd3SIvan Shcherbakov * however, they use a slightly different encoding. Specifically:
3615ad93fd3SIvan Shcherbakov *
3625ad93fd3SIvan Shcherbakov * APIC.TPR[bits 7:4] = CR8[bits 3:0]
3635ad93fd3SIvan Shcherbakov *
3645ad93fd3SIvan Shcherbakov * This mechanism is described in section 10.8.6.1 of Volume 3 of Intel 64
3655ad93fd3SIvan Shcherbakov * and IA-32 Architectures Software Developer's Manual.
366f000bc74SIvan Shcherbakov *
367f000bc74SIvan Shcherbakov * The functions below translate the value of CR8 to TPR and vice versa.
3685ad93fd3SIvan Shcherbakov */
3695ad93fd3SIvan Shcherbakov
whpx_apic_tpr_to_cr8(uint64_t tpr)3705ad93fd3SIvan Shcherbakov static uint64_t whpx_apic_tpr_to_cr8(uint64_t tpr)
3715ad93fd3SIvan Shcherbakov {
3725ad93fd3SIvan Shcherbakov return tpr >> 4;
3735ad93fd3SIvan Shcherbakov }
3745ad93fd3SIvan Shcherbakov
whpx_cr8_to_apic_tpr(uint64_t cr8)375f000bc74SIvan Shcherbakov static uint64_t whpx_cr8_to_apic_tpr(uint64_t cr8)
376f000bc74SIvan Shcherbakov {
377f000bc74SIvan Shcherbakov return cr8 << 4;
378f000bc74SIvan Shcherbakov }
379f000bc74SIvan Shcherbakov
whpx_set_registers(CPUState * cpu,int level)3801fc33bb9SClaudio Fontana static void whpx_set_registers(CPUState *cpu, int level)
3811fc33bb9SClaudio Fontana {
3821fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
383441f2449SPhilippe Mathieu-Daudé AccelCPUState *vcpu = cpu->accel;
3841fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu);
385b77af26eSRichard Henderson CPUX86State *env = &x86_cpu->env;
3861fc33bb9SClaudio Fontana struct whpx_register_set vcxt;
3871fc33bb9SClaudio Fontana HRESULT hr;
3881fc33bb9SClaudio Fontana int idx;
3891fc33bb9SClaudio Fontana int idx_next;
3901fc33bb9SClaudio Fontana int i;
3911fc33bb9SClaudio Fontana int v86, r86;
3921fc33bb9SClaudio Fontana
3931fc33bb9SClaudio Fontana assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
3941fc33bb9SClaudio Fontana
3951fc33bb9SClaudio Fontana /*
3961fc33bb9SClaudio Fontana * Following MSRs have side effects on the guest or are too heavy for
3971fc33bb9SClaudio Fontana * runtime. Limit them to full state update.
3981fc33bb9SClaudio Fontana */
3991fc33bb9SClaudio Fontana if (level >= WHPX_SET_RESET_STATE) {
4001fc33bb9SClaudio Fontana whpx_set_tsc(cpu);
4011fc33bb9SClaudio Fontana }
4021fc33bb9SClaudio Fontana
4031fc33bb9SClaudio Fontana memset(&vcxt, 0, sizeof(struct whpx_register_set));
4041fc33bb9SClaudio Fontana
4051fc33bb9SClaudio Fontana v86 = (env->eflags & VM_MASK);
4061fc33bb9SClaudio Fontana r86 = !(env->cr[0] & CR0_PE_MASK);
4071fc33bb9SClaudio Fontana
4085ad93fd3SIvan Shcherbakov vcpu->tpr = whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state));
4091fc33bb9SClaudio Fontana vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state);
4101fc33bb9SClaudio Fontana
4111fc33bb9SClaudio Fontana idx = 0;
4121fc33bb9SClaudio Fontana
4131fc33bb9SClaudio Fontana /* Indexes for first 16 registers match between HV and QEMU definitions */
4141fc33bb9SClaudio Fontana idx_next = 16;
4151fc33bb9SClaudio Fontana for (idx = 0; idx < CPU_NB_REGS; idx += 1) {
4161fc33bb9SClaudio Fontana vcxt.values[idx].Reg64 = (uint64_t)env->regs[idx];
4171fc33bb9SClaudio Fontana }
4181fc33bb9SClaudio Fontana idx = idx_next;
4191fc33bb9SClaudio Fontana
4201fc33bb9SClaudio Fontana /* Same goes for RIP and RFLAGS */
4211fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterRip);
4221fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->eip;
4231fc33bb9SClaudio Fontana
4241fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterRflags);
4251fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->eflags;
4261fc33bb9SClaudio Fontana
4271fc33bb9SClaudio Fontana /* Translate 6+4 segment registers. HV and QEMU order matches */
4281fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterEs);
4291fc33bb9SClaudio Fontana for (i = 0; i < 6; i += 1, idx += 1) {
4301fc33bb9SClaudio Fontana vcxt.values[idx].Segment = whpx_seg_q2h(&env->segs[i], v86, r86);
4311fc33bb9SClaudio Fontana }
4321fc33bb9SClaudio Fontana
4331fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterLdtr);
4341fc33bb9SClaudio Fontana vcxt.values[idx++].Segment = whpx_seg_q2h(&env->ldt, 0, 0);
4351fc33bb9SClaudio Fontana
4361fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterTr);
4371fc33bb9SClaudio Fontana vcxt.values[idx++].Segment = whpx_seg_q2h(&env->tr, 0, 0);
4381fc33bb9SClaudio Fontana
4391fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterIdtr);
4401fc33bb9SClaudio Fontana vcxt.values[idx].Table.Base = env->idt.base;
4411fc33bb9SClaudio Fontana vcxt.values[idx].Table.Limit = env->idt.limit;
4421fc33bb9SClaudio Fontana idx += 1;
4431fc33bb9SClaudio Fontana
4441fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterGdtr);
4451fc33bb9SClaudio Fontana vcxt.values[idx].Table.Base = env->gdt.base;
4461fc33bb9SClaudio Fontana vcxt.values[idx].Table.Limit = env->gdt.limit;
4471fc33bb9SClaudio Fontana idx += 1;
4481fc33bb9SClaudio Fontana
4491fc33bb9SClaudio Fontana /* CR0, 2, 3, 4, 8 */
4501fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr0);
4511fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->cr[0];
4521fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr2);
4531fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->cr[2];
4541fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr3);
4551fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->cr[3];
4561fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr4);
4571fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->cr[4];
4581fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr8);
4591fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = vcpu->tpr;
4601fc33bb9SClaudio Fontana
4611fc33bb9SClaudio Fontana /* 8 Debug Registers - Skipped */
4621fc33bb9SClaudio Fontana
463b6b3da99SSunil Muthuswamy /*
464b6b3da99SSunil Muthuswamy * Extended control registers needs to be handled separately depending
465b6b3da99SSunil Muthuswamy * on whether xsave is supported/enabled or not.
466b6b3da99SSunil Muthuswamy */
467b6b3da99SSunil Muthuswamy whpx_set_xcrs(cpu);
468b6b3da99SSunil Muthuswamy
4691fc33bb9SClaudio Fontana /* 16 XMM registers */
4701fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
4711fc33bb9SClaudio Fontana idx_next = idx + 16;
4721fc33bb9SClaudio Fontana for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
4731fc33bb9SClaudio Fontana vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);
4741fc33bb9SClaudio Fontana vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);
4751fc33bb9SClaudio Fontana }
4761fc33bb9SClaudio Fontana idx = idx_next;
4771fc33bb9SClaudio Fontana
4781fc33bb9SClaudio Fontana /* 8 FP registers */
4791fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
4801fc33bb9SClaudio Fontana for (i = 0; i < 8; i += 1, idx += 1) {
4811fc33bb9SClaudio Fontana vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0);
4821fc33bb9SClaudio Fontana /* vcxt.values[idx].Fp.AsUINT128.High64 =
4831fc33bb9SClaudio Fontana env->fpregs[i].mmx.MMX_Q(1);
4841fc33bb9SClaudio Fontana */
4851fc33bb9SClaudio Fontana }
4861fc33bb9SClaudio Fontana
4871fc33bb9SClaudio Fontana /* FP control status register */
4881fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);
4891fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.FpControl = env->fpuc;
4901fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.FpStatus =
4911fc33bb9SClaudio Fontana (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
4921fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.FpTag = 0;
4931fc33bb9SClaudio Fontana for (i = 0; i < 8; ++i) {
4941fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i;
4951fc33bb9SClaudio Fontana }
4961fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.Reserved = 0;
4971fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop;
4981fc33bb9SClaudio Fontana vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip;
4991fc33bb9SClaudio Fontana idx += 1;
5001fc33bb9SClaudio Fontana
5011fc33bb9SClaudio Fontana /* XMM control status register */
5021fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);
5031fc33bb9SClaudio Fontana vcxt.values[idx].XmmControlStatus.LastFpRdp = 0;
5041fc33bb9SClaudio Fontana vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr;
5051fc33bb9SClaudio Fontana vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff;
5061fc33bb9SClaudio Fontana idx += 1;
5071fc33bb9SClaudio Fontana
5081fc33bb9SClaudio Fontana /* MSRs */
5091fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterEfer);
5101fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->efer;
5111fc33bb9SClaudio Fontana #ifdef TARGET_X86_64
5121fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase);
5131fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->kernelgsbase;
5141fc33bb9SClaudio Fontana #endif
5151fc33bb9SClaudio Fontana
5161fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterApicBase);
5171fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = vcpu->apic_base;
5181fc33bb9SClaudio Fontana
5191fc33bb9SClaudio Fontana /* WHvX64RegisterPat - Skipped */
5201fc33bb9SClaudio Fontana
5211fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs);
5221fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->sysenter_cs;
5231fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip);
5241fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->sysenter_eip;
5251fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp);
5261fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->sysenter_esp;
5271fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterStar);
5281fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->star;
5291fc33bb9SClaudio Fontana #ifdef TARGET_X86_64
5301fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterLstar);
5311fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->lstar;
5321fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCstar);
5331fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->cstar;
5341fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSfmask);
5351fc33bb9SClaudio Fontana vcxt.values[idx++].Reg64 = env->fmask;
5361fc33bb9SClaudio Fontana #endif
5371fc33bb9SClaudio Fontana
5381fc33bb9SClaudio Fontana /* Interrupt / Event Registers - Skipped */
5391fc33bb9SClaudio Fontana
5401fc33bb9SClaudio Fontana assert(idx == RTL_NUMBER_OF(whpx_register_names));
5411fc33bb9SClaudio Fontana
5421fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
5431fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index,
5441fc33bb9SClaudio Fontana whpx_register_names,
5451fc33bb9SClaudio Fontana RTL_NUMBER_OF(whpx_register_names),
5461fc33bb9SClaudio Fontana &vcxt.values[0]);
5471fc33bb9SClaudio Fontana
5481fc33bb9SClaudio Fontana if (FAILED(hr)) {
5491fc33bb9SClaudio Fontana error_report("WHPX: Failed to set virtual processor context, hr=%08lx",
5501fc33bb9SClaudio Fontana hr);
5511fc33bb9SClaudio Fontana }
5521fc33bb9SClaudio Fontana
5531fc33bb9SClaudio Fontana return;
5541fc33bb9SClaudio Fontana }
5551fc33bb9SClaudio Fontana
whpx_get_tsc(CPUState * cpu)5561fc33bb9SClaudio Fontana static int whpx_get_tsc(CPUState *cpu)
5571fc33bb9SClaudio Fontana {
5581fc33bb9SClaudio Fontana WHV_REGISTER_NAME tsc_reg = WHvX64RegisterTsc;
5591fc33bb9SClaudio Fontana WHV_REGISTER_VALUE tsc_val;
5601fc33bb9SClaudio Fontana HRESULT hr;
5611fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
5621fc33bb9SClaudio Fontana
5631fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
5641fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, &tsc_reg, 1, &tsc_val);
5651fc33bb9SClaudio Fontana if (FAILED(hr)) {
5661fc33bb9SClaudio Fontana error_report("WHPX: Failed to get TSC, hr=%08lx", hr);
5671fc33bb9SClaudio Fontana return -1;
5681fc33bb9SClaudio Fontana }
5691fc33bb9SClaudio Fontana
57094956d7bSPhilippe Mathieu-Daudé cpu_env(cpu)->tsc = tsc_val.Reg64;
5711fc33bb9SClaudio Fontana return 0;
5721fc33bb9SClaudio Fontana }
5731fc33bb9SClaudio Fontana
574b6b3da99SSunil Muthuswamy /* X64 Extended Control Registers */
whpx_get_xcrs(CPUState * cpu)575b6b3da99SSunil Muthuswamy static void whpx_get_xcrs(CPUState *cpu)
576b6b3da99SSunil Muthuswamy {
577b6b3da99SSunil Muthuswamy HRESULT hr;
578b6b3da99SSunil Muthuswamy struct whpx_state *whpx = &whpx_global;
579b6b3da99SSunil Muthuswamy WHV_REGISTER_VALUE xcr0;
580b6b3da99SSunil Muthuswamy WHV_REGISTER_NAME xcr0_name = WHvX64RegisterXCr0;
581b6b3da99SSunil Muthuswamy
582b6b3da99SSunil Muthuswamy if (!whpx_has_xsave()) {
583b6b3da99SSunil Muthuswamy return;
584b6b3da99SSunil Muthuswamy }
585b6b3da99SSunil Muthuswamy
586b6b3da99SSunil Muthuswamy /* Only xcr0 is supported by the hypervisor currently */
587b6b3da99SSunil Muthuswamy hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
588b6b3da99SSunil Muthuswamy whpx->partition, cpu->cpu_index, &xcr0_name, 1, &xcr0);
589b6b3da99SSunil Muthuswamy if (FAILED(hr)) {
590b6b3da99SSunil Muthuswamy error_report("WHPX: Failed to get register xcr0, hr=%08lx", hr);
591b6b3da99SSunil Muthuswamy return;
592b6b3da99SSunil Muthuswamy }
593b6b3da99SSunil Muthuswamy
59494956d7bSPhilippe Mathieu-Daudé cpu_env(cpu)->xcr0 = xcr0.Reg64;
595b6b3da99SSunil Muthuswamy }
596b6b3da99SSunil Muthuswamy
whpx_get_registers(CPUState * cpu)5971fc33bb9SClaudio Fontana static void whpx_get_registers(CPUState *cpu)
5981fc33bb9SClaudio Fontana {
5991fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
600441f2449SPhilippe Mathieu-Daudé AccelCPUState *vcpu = cpu->accel;
6011fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu);
602b77af26eSRichard Henderson CPUX86State *env = &x86_cpu->env;
6031fc33bb9SClaudio Fontana struct whpx_register_set vcxt;
6041fc33bb9SClaudio Fontana uint64_t tpr, apic_base;
6051fc33bb9SClaudio Fontana HRESULT hr;
6061fc33bb9SClaudio Fontana int idx;
6071fc33bb9SClaudio Fontana int idx_next;
6081fc33bb9SClaudio Fontana int i;
6091fc33bb9SClaudio Fontana
6101fc33bb9SClaudio Fontana assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
6111fc33bb9SClaudio Fontana
6121fc33bb9SClaudio Fontana if (!env->tsc_valid) {
6131fc33bb9SClaudio Fontana whpx_get_tsc(cpu);
6141fc33bb9SClaudio Fontana env->tsc_valid = !runstate_is_running();
6151fc33bb9SClaudio Fontana }
6161fc33bb9SClaudio Fontana
6171fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
6181fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index,
6191fc33bb9SClaudio Fontana whpx_register_names,
6201fc33bb9SClaudio Fontana RTL_NUMBER_OF(whpx_register_names),
6211fc33bb9SClaudio Fontana &vcxt.values[0]);
6221fc33bb9SClaudio Fontana if (FAILED(hr)) {
6231fc33bb9SClaudio Fontana error_report("WHPX: Failed to get virtual processor context, hr=%08lx",
6241fc33bb9SClaudio Fontana hr);
6251fc33bb9SClaudio Fontana }
6261fc33bb9SClaudio Fontana
6275ad93fd3SIvan Shcherbakov if (whpx_apic_in_platform()) {
6285ad93fd3SIvan Shcherbakov /*
6295ad93fd3SIvan Shcherbakov * Fetch the TPR value from the emulated APIC. It may get overwritten
6305ad93fd3SIvan Shcherbakov * below with the value from CR8 returned by
6315ad93fd3SIvan Shcherbakov * WHvGetVirtualProcessorRegisters().
6325ad93fd3SIvan Shcherbakov */
6335ad93fd3SIvan Shcherbakov whpx_apic_get(x86_cpu->apic_state);
6345ad93fd3SIvan Shcherbakov vcpu->tpr = whpx_apic_tpr_to_cr8(
6355ad93fd3SIvan Shcherbakov cpu_get_apic_tpr(x86_cpu->apic_state));
6365ad93fd3SIvan Shcherbakov }
6375ad93fd3SIvan Shcherbakov
6381fc33bb9SClaudio Fontana idx = 0;
6391fc33bb9SClaudio Fontana
6401fc33bb9SClaudio Fontana /* Indexes for first 16 registers match between HV and QEMU definitions */
6411fc33bb9SClaudio Fontana idx_next = 16;
6421fc33bb9SClaudio Fontana for (idx = 0; idx < CPU_NB_REGS; idx += 1) {
6431fc33bb9SClaudio Fontana env->regs[idx] = vcxt.values[idx].Reg64;
6441fc33bb9SClaudio Fontana }
6451fc33bb9SClaudio Fontana idx = idx_next;
6461fc33bb9SClaudio Fontana
6471fc33bb9SClaudio Fontana /* Same goes for RIP and RFLAGS */
6481fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterRip);
6491fc33bb9SClaudio Fontana env->eip = vcxt.values[idx++].Reg64;
6501fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterRflags);
6511fc33bb9SClaudio Fontana env->eflags = vcxt.values[idx++].Reg64;
6521fc33bb9SClaudio Fontana
6531fc33bb9SClaudio Fontana /* Translate 6+4 segment registers. HV and QEMU order matches */
6541fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterEs);
6551fc33bb9SClaudio Fontana for (i = 0; i < 6; i += 1, idx += 1) {
6561fc33bb9SClaudio Fontana env->segs[i] = whpx_seg_h2q(&vcxt.values[idx].Segment);
6571fc33bb9SClaudio Fontana }
6581fc33bb9SClaudio Fontana
6591fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterLdtr);
6601fc33bb9SClaudio Fontana env->ldt = whpx_seg_h2q(&vcxt.values[idx++].Segment);
6611fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterTr);
6621fc33bb9SClaudio Fontana env->tr = whpx_seg_h2q(&vcxt.values[idx++].Segment);
6631fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterIdtr);
6641fc33bb9SClaudio Fontana env->idt.base = vcxt.values[idx].Table.Base;
6651fc33bb9SClaudio Fontana env->idt.limit = vcxt.values[idx].Table.Limit;
6661fc33bb9SClaudio Fontana idx += 1;
6671fc33bb9SClaudio Fontana assert(idx == WHvX64RegisterGdtr);
6681fc33bb9SClaudio Fontana env->gdt.base = vcxt.values[idx].Table.Base;
6691fc33bb9SClaudio Fontana env->gdt.limit = vcxt.values[idx].Table.Limit;
6701fc33bb9SClaudio Fontana idx += 1;
6711fc33bb9SClaudio Fontana
6721fc33bb9SClaudio Fontana /* CR0, 2, 3, 4, 8 */
6731fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr0);
6741fc33bb9SClaudio Fontana env->cr[0] = vcxt.values[idx++].Reg64;
6751fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr2);
6761fc33bb9SClaudio Fontana env->cr[2] = vcxt.values[idx++].Reg64;
6771fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr3);
6781fc33bb9SClaudio Fontana env->cr[3] = vcxt.values[idx++].Reg64;
6791fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr4);
6801fc33bb9SClaudio Fontana env->cr[4] = vcxt.values[idx++].Reg64;
6811fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCr8);
6821fc33bb9SClaudio Fontana tpr = vcxt.values[idx++].Reg64;
6831fc33bb9SClaudio Fontana if (tpr != vcpu->tpr) {
6841fc33bb9SClaudio Fontana vcpu->tpr = tpr;
685f000bc74SIvan Shcherbakov cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(tpr));
6861fc33bb9SClaudio Fontana }
6871fc33bb9SClaudio Fontana
6881fc33bb9SClaudio Fontana /* 8 Debug Registers - Skipped */
6891fc33bb9SClaudio Fontana
690b6b3da99SSunil Muthuswamy /*
691b6b3da99SSunil Muthuswamy * Extended control registers needs to be handled separately depending
692b6b3da99SSunil Muthuswamy * on whether xsave is supported/enabled or not.
693b6b3da99SSunil Muthuswamy */
694b6b3da99SSunil Muthuswamy whpx_get_xcrs(cpu);
695b6b3da99SSunil Muthuswamy
6961fc33bb9SClaudio Fontana /* 16 XMM registers */
6971fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
6981fc33bb9SClaudio Fontana idx_next = idx + 16;
6991fc33bb9SClaudio Fontana for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
7001fc33bb9SClaudio Fontana env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64;
7011fc33bb9SClaudio Fontana env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64;
7021fc33bb9SClaudio Fontana }
7031fc33bb9SClaudio Fontana idx = idx_next;
7041fc33bb9SClaudio Fontana
7051fc33bb9SClaudio Fontana /* 8 FP registers */
7061fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
7071fc33bb9SClaudio Fontana for (i = 0; i < 8; i += 1, idx += 1) {
7081fc33bb9SClaudio Fontana env->fpregs[i].mmx.MMX_Q(0) = vcxt.values[idx].Fp.AsUINT128.Low64;
7091fc33bb9SClaudio Fontana /* env->fpregs[i].mmx.MMX_Q(1) =
7101fc33bb9SClaudio Fontana vcxt.values[idx].Fp.AsUINT128.High64;
7111fc33bb9SClaudio Fontana */
7121fc33bb9SClaudio Fontana }
7131fc33bb9SClaudio Fontana
7141fc33bb9SClaudio Fontana /* FP control status register */
7151fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);
7161fc33bb9SClaudio Fontana env->fpuc = vcxt.values[idx].FpControlStatus.FpControl;
7171fc33bb9SClaudio Fontana env->fpstt = (vcxt.values[idx].FpControlStatus.FpStatus >> 11) & 0x7;
7181fc33bb9SClaudio Fontana env->fpus = vcxt.values[idx].FpControlStatus.FpStatus & ~0x3800;
7191fc33bb9SClaudio Fontana for (i = 0; i < 8; ++i) {
7201fc33bb9SClaudio Fontana env->fptags[i] = !((vcxt.values[idx].FpControlStatus.FpTag >> i) & 1);
7211fc33bb9SClaudio Fontana }
7221fc33bb9SClaudio Fontana env->fpop = vcxt.values[idx].FpControlStatus.LastFpOp;
7231fc33bb9SClaudio Fontana env->fpip = vcxt.values[idx].FpControlStatus.LastFpRip;
7241fc33bb9SClaudio Fontana idx += 1;
7251fc33bb9SClaudio Fontana
7261fc33bb9SClaudio Fontana /* XMM control status register */
7271fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);
7281fc33bb9SClaudio Fontana env->mxcsr = vcxt.values[idx].XmmControlStatus.XmmStatusControl;
7291fc33bb9SClaudio Fontana idx += 1;
7301fc33bb9SClaudio Fontana
7311fc33bb9SClaudio Fontana /* MSRs */
7321fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterEfer);
7331fc33bb9SClaudio Fontana env->efer = vcxt.values[idx++].Reg64;
7341fc33bb9SClaudio Fontana #ifdef TARGET_X86_64
7351fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase);
7361fc33bb9SClaudio Fontana env->kernelgsbase = vcxt.values[idx++].Reg64;
7371fc33bb9SClaudio Fontana #endif
7381fc33bb9SClaudio Fontana
7391fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterApicBase);
7401fc33bb9SClaudio Fontana apic_base = vcxt.values[idx++].Reg64;
7411fc33bb9SClaudio Fontana if (apic_base != vcpu->apic_base) {
7421fc33bb9SClaudio Fontana vcpu->apic_base = apic_base;
7431fc33bb9SClaudio Fontana cpu_set_apic_base(x86_cpu->apic_state, vcpu->apic_base);
7441fc33bb9SClaudio Fontana }
7451fc33bb9SClaudio Fontana
7461fc33bb9SClaudio Fontana /* WHvX64RegisterPat - Skipped */
7471fc33bb9SClaudio Fontana
7481fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs);
7491fc33bb9SClaudio Fontana env->sysenter_cs = vcxt.values[idx++].Reg64;
7501fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip);
7511fc33bb9SClaudio Fontana env->sysenter_eip = vcxt.values[idx++].Reg64;
7521fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp);
7531fc33bb9SClaudio Fontana env->sysenter_esp = vcxt.values[idx++].Reg64;
7541fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterStar);
7551fc33bb9SClaudio Fontana env->star = vcxt.values[idx++].Reg64;
7561fc33bb9SClaudio Fontana #ifdef TARGET_X86_64
7571fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterLstar);
7581fc33bb9SClaudio Fontana env->lstar = vcxt.values[idx++].Reg64;
7591fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterCstar);
7601fc33bb9SClaudio Fontana env->cstar = vcxt.values[idx++].Reg64;
7611fc33bb9SClaudio Fontana assert(whpx_register_names[idx] == WHvX64RegisterSfmask);
7621fc33bb9SClaudio Fontana env->fmask = vcxt.values[idx++].Reg64;
7631fc33bb9SClaudio Fontana #endif
7641fc33bb9SClaudio Fontana
7651fc33bb9SClaudio Fontana /* Interrupt / Event Registers - Skipped */
7661fc33bb9SClaudio Fontana
7671fc33bb9SClaudio Fontana assert(idx == RTL_NUMBER_OF(whpx_register_names));
7681fc33bb9SClaudio Fontana
7691fc33bb9SClaudio Fontana if (whpx_apic_in_platform()) {
7701fc33bb9SClaudio Fontana whpx_apic_get(x86_cpu->apic_state);
7711fc33bb9SClaudio Fontana }
7721fc33bb9SClaudio Fontana
773e5618908SIvan Shcherbakov x86_update_hflags(env);
774e5618908SIvan Shcherbakov
7751fc33bb9SClaudio Fontana return;
7761fc33bb9SClaudio Fontana }
7771fc33bb9SClaudio Fontana
whpx_emu_ioport_callback(void * ctx,WHV_EMULATOR_IO_ACCESS_INFO * IoAccess)7781fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_ioport_callback(
7791fc33bb9SClaudio Fontana void *ctx,
7801fc33bb9SClaudio Fontana WHV_EMULATOR_IO_ACCESS_INFO *IoAccess)
7811fc33bb9SClaudio Fontana {
7821fc33bb9SClaudio Fontana MemTxAttrs attrs = { 0 };
7831fc33bb9SClaudio Fontana address_space_rw(&address_space_io, IoAccess->Port, attrs,
7841fc33bb9SClaudio Fontana &IoAccess->Data, IoAccess->AccessSize,
7851fc33bb9SClaudio Fontana IoAccess->Direction);
7861fc33bb9SClaudio Fontana return S_OK;
7871fc33bb9SClaudio Fontana }
7881fc33bb9SClaudio Fontana
whpx_emu_mmio_callback(void * ctx,WHV_EMULATOR_MEMORY_ACCESS_INFO * ma)7891fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_mmio_callback(
7901fc33bb9SClaudio Fontana void *ctx,
7911fc33bb9SClaudio Fontana WHV_EMULATOR_MEMORY_ACCESS_INFO *ma)
7921fc33bb9SClaudio Fontana {
7931fc33bb9SClaudio Fontana cpu_physical_memory_rw(ma->GpaAddress, ma->Data, ma->AccessSize,
7941fc33bb9SClaudio Fontana ma->Direction);
7951fc33bb9SClaudio Fontana return S_OK;
7961fc33bb9SClaudio Fontana }
7971fc33bb9SClaudio Fontana
whpx_emu_getreg_callback(void * ctx,const WHV_REGISTER_NAME * RegisterNames,UINT32 RegisterCount,WHV_REGISTER_VALUE * RegisterValues)7981fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_getreg_callback(
7991fc33bb9SClaudio Fontana void *ctx,
8001fc33bb9SClaudio Fontana const WHV_REGISTER_NAME *RegisterNames,
8011fc33bb9SClaudio Fontana UINT32 RegisterCount,
8021fc33bb9SClaudio Fontana WHV_REGISTER_VALUE *RegisterValues)
8031fc33bb9SClaudio Fontana {
8041fc33bb9SClaudio Fontana HRESULT hr;
8051fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
8061fc33bb9SClaudio Fontana CPUState *cpu = (CPUState *)ctx;
8071fc33bb9SClaudio Fontana
8081fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
8091fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index,
8101fc33bb9SClaudio Fontana RegisterNames, RegisterCount,
8111fc33bb9SClaudio Fontana RegisterValues);
8121fc33bb9SClaudio Fontana if (FAILED(hr)) {
8131fc33bb9SClaudio Fontana error_report("WHPX: Failed to get virtual processor registers,"
8141fc33bb9SClaudio Fontana " hr=%08lx", hr);
8151fc33bb9SClaudio Fontana }
8161fc33bb9SClaudio Fontana
8171fc33bb9SClaudio Fontana return hr;
8181fc33bb9SClaudio Fontana }
8191fc33bb9SClaudio Fontana
whpx_emu_setreg_callback(void * ctx,const WHV_REGISTER_NAME * RegisterNames,UINT32 RegisterCount,const WHV_REGISTER_VALUE * RegisterValues)8201fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_setreg_callback(
8211fc33bb9SClaudio Fontana void *ctx,
8221fc33bb9SClaudio Fontana const WHV_REGISTER_NAME *RegisterNames,
8231fc33bb9SClaudio Fontana UINT32 RegisterCount,
8241fc33bb9SClaudio Fontana const WHV_REGISTER_VALUE *RegisterValues)
8251fc33bb9SClaudio Fontana {
8261fc33bb9SClaudio Fontana HRESULT hr;
8271fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
8281fc33bb9SClaudio Fontana CPUState *cpu = (CPUState *)ctx;
8291fc33bb9SClaudio Fontana
8301fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
8311fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index,
8321fc33bb9SClaudio Fontana RegisterNames, RegisterCount,
8331fc33bb9SClaudio Fontana RegisterValues);
8341fc33bb9SClaudio Fontana if (FAILED(hr)) {
8351fc33bb9SClaudio Fontana error_report("WHPX: Failed to set virtual processor registers,"
8361fc33bb9SClaudio Fontana " hr=%08lx", hr);
8371fc33bb9SClaudio Fontana }
8381fc33bb9SClaudio Fontana
8391fc33bb9SClaudio Fontana /*
8401fc33bb9SClaudio Fontana * The emulator just successfully wrote the register state. We clear the
8411fc33bb9SClaudio Fontana * dirty state so we avoid the double write on resume of the VP.
8421fc33bb9SClaudio Fontana */
8439ad49538SPhilippe Mathieu-Daudé cpu->accel->dirty = false;
8441fc33bb9SClaudio Fontana
8451fc33bb9SClaudio Fontana return hr;
8461fc33bb9SClaudio Fontana }
8471fc33bb9SClaudio Fontana
whpx_emu_translate_callback(void * ctx,WHV_GUEST_VIRTUAL_ADDRESS Gva,WHV_TRANSLATE_GVA_FLAGS TranslateFlags,WHV_TRANSLATE_GVA_RESULT_CODE * TranslationResult,WHV_GUEST_PHYSICAL_ADDRESS * Gpa)8481fc33bb9SClaudio Fontana static HRESULT CALLBACK whpx_emu_translate_callback(
8491fc33bb9SClaudio Fontana void *ctx,
8501fc33bb9SClaudio Fontana WHV_GUEST_VIRTUAL_ADDRESS Gva,
8511fc33bb9SClaudio Fontana WHV_TRANSLATE_GVA_FLAGS TranslateFlags,
8521fc33bb9SClaudio Fontana WHV_TRANSLATE_GVA_RESULT_CODE *TranslationResult,
8531fc33bb9SClaudio Fontana WHV_GUEST_PHYSICAL_ADDRESS *Gpa)
8541fc33bb9SClaudio Fontana {
8551fc33bb9SClaudio Fontana HRESULT hr;
8561fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
8571fc33bb9SClaudio Fontana CPUState *cpu = (CPUState *)ctx;
8581fc33bb9SClaudio Fontana WHV_TRANSLATE_GVA_RESULT res;
8591fc33bb9SClaudio Fontana
8601fc33bb9SClaudio Fontana hr = whp_dispatch.WHvTranslateGva(whpx->partition, cpu->cpu_index,
8611fc33bb9SClaudio Fontana Gva, TranslateFlags, &res, Gpa);
8621fc33bb9SClaudio Fontana if (FAILED(hr)) {
8631fc33bb9SClaudio Fontana error_report("WHPX: Failed to translate GVA, hr=%08lx", hr);
8641fc33bb9SClaudio Fontana } else {
8651fc33bb9SClaudio Fontana *TranslationResult = res.ResultCode;
8661fc33bb9SClaudio Fontana }
8671fc33bb9SClaudio Fontana
8681fc33bb9SClaudio Fontana return hr;
8691fc33bb9SClaudio Fontana }
8701fc33bb9SClaudio Fontana
8711fc33bb9SClaudio Fontana static const WHV_EMULATOR_CALLBACKS whpx_emu_callbacks = {
8721fc33bb9SClaudio Fontana .Size = sizeof(WHV_EMULATOR_CALLBACKS),
8731fc33bb9SClaudio Fontana .WHvEmulatorIoPortCallback = whpx_emu_ioport_callback,
8741fc33bb9SClaudio Fontana .WHvEmulatorMemoryCallback = whpx_emu_mmio_callback,
8751fc33bb9SClaudio Fontana .WHvEmulatorGetVirtualProcessorRegisters = whpx_emu_getreg_callback,
8761fc33bb9SClaudio Fontana .WHvEmulatorSetVirtualProcessorRegisters = whpx_emu_setreg_callback,
8771fc33bb9SClaudio Fontana .WHvEmulatorTranslateGvaPage = whpx_emu_translate_callback,
8781fc33bb9SClaudio Fontana };
8791fc33bb9SClaudio Fontana
whpx_handle_mmio(CPUState * cpu,WHV_MEMORY_ACCESS_CONTEXT * ctx)8801fc33bb9SClaudio Fontana static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx)
8811fc33bb9SClaudio Fontana {
8821fc33bb9SClaudio Fontana HRESULT hr;
883441f2449SPhilippe Mathieu-Daudé AccelCPUState *vcpu = cpu->accel;
8841fc33bb9SClaudio Fontana WHV_EMULATOR_STATUS emu_status;
8851fc33bb9SClaudio Fontana
8861fc33bb9SClaudio Fontana hr = whp_dispatch.WHvEmulatorTryMmioEmulation(
8871fc33bb9SClaudio Fontana vcpu->emulator, cpu,
8881fc33bb9SClaudio Fontana &vcpu->exit_ctx.VpContext, ctx,
8891fc33bb9SClaudio Fontana &emu_status);
8901fc33bb9SClaudio Fontana if (FAILED(hr)) {
8911fc33bb9SClaudio Fontana error_report("WHPX: Failed to parse MMIO access, hr=%08lx", hr);
8921fc33bb9SClaudio Fontana return -1;
8931fc33bb9SClaudio Fontana }
8941fc33bb9SClaudio Fontana
8951fc33bb9SClaudio Fontana if (!emu_status.EmulationSuccessful) {
8961fc33bb9SClaudio Fontana error_report("WHPX: Failed to emulate MMIO access with"
8971fc33bb9SClaudio Fontana " EmulatorReturnStatus: %u", emu_status.AsUINT32);
8981fc33bb9SClaudio Fontana return -1;
8991fc33bb9SClaudio Fontana }
9001fc33bb9SClaudio Fontana
9011fc33bb9SClaudio Fontana return 0;
9021fc33bb9SClaudio Fontana }
9031fc33bb9SClaudio Fontana
whpx_handle_portio(CPUState * cpu,WHV_X64_IO_PORT_ACCESS_CONTEXT * ctx)9041fc33bb9SClaudio Fontana static int whpx_handle_portio(CPUState *cpu,
9051fc33bb9SClaudio Fontana WHV_X64_IO_PORT_ACCESS_CONTEXT *ctx)
9061fc33bb9SClaudio Fontana {
9071fc33bb9SClaudio Fontana HRESULT hr;
908441f2449SPhilippe Mathieu-Daudé AccelCPUState *vcpu = cpu->accel;
9091fc33bb9SClaudio Fontana WHV_EMULATOR_STATUS emu_status;
9101fc33bb9SClaudio Fontana
9111fc33bb9SClaudio Fontana hr = whp_dispatch.WHvEmulatorTryIoEmulation(
9121fc33bb9SClaudio Fontana vcpu->emulator, cpu,
9131fc33bb9SClaudio Fontana &vcpu->exit_ctx.VpContext, ctx,
9141fc33bb9SClaudio Fontana &emu_status);
9151fc33bb9SClaudio Fontana if (FAILED(hr)) {
9161fc33bb9SClaudio Fontana error_report("WHPX: Failed to parse PortIO access, hr=%08lx", hr);
9171fc33bb9SClaudio Fontana return -1;
9181fc33bb9SClaudio Fontana }
9191fc33bb9SClaudio Fontana
9201fc33bb9SClaudio Fontana if (!emu_status.EmulationSuccessful) {
9211fc33bb9SClaudio Fontana error_report("WHPX: Failed to emulate PortIO access with"
9221fc33bb9SClaudio Fontana " EmulatorReturnStatus: %u", emu_status.AsUINT32);
9231fc33bb9SClaudio Fontana return -1;
9241fc33bb9SClaudio Fontana }
9251fc33bb9SClaudio Fontana
9261fc33bb9SClaudio Fontana return 0;
9271fc33bb9SClaudio Fontana }
9281fc33bb9SClaudio Fontana
929d7482ffeSIvan Shcherbakov /*
930d7482ffeSIvan Shcherbakov * Controls whether we should intercept various exceptions on the guest,
931d7482ffeSIvan Shcherbakov * namely breakpoint/single-step events.
932d7482ffeSIvan Shcherbakov *
933d7482ffeSIvan Shcherbakov * The 'exceptions' argument accepts a bitmask, e.g:
934d7482ffeSIvan Shcherbakov * (1 << WHvX64ExceptionTypeDebugTrapOrFault) | (...)
935d7482ffeSIvan Shcherbakov */
whpx_set_exception_exit_bitmap(UINT64 exceptions)936d7482ffeSIvan Shcherbakov static HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions)
937d7482ffeSIvan Shcherbakov {
938d7482ffeSIvan Shcherbakov struct whpx_state *whpx = &whpx_global;
939d7482ffeSIvan Shcherbakov WHV_PARTITION_PROPERTY prop = { 0, };
940d7482ffeSIvan Shcherbakov HRESULT hr;
941d7482ffeSIvan Shcherbakov
942d7482ffeSIvan Shcherbakov if (exceptions == whpx->exception_exit_bitmap) {
943d7482ffeSIvan Shcherbakov return S_OK;
944d7482ffeSIvan Shcherbakov }
945d7482ffeSIvan Shcherbakov
946d7482ffeSIvan Shcherbakov prop.ExceptionExitBitmap = exceptions;
947d7482ffeSIvan Shcherbakov
948d7482ffeSIvan Shcherbakov hr = whp_dispatch.WHvSetPartitionProperty(
949d7482ffeSIvan Shcherbakov whpx->partition,
950d7482ffeSIvan Shcherbakov WHvPartitionPropertyCodeExceptionExitBitmap,
951d7482ffeSIvan Shcherbakov &prop,
952d7482ffeSIvan Shcherbakov sizeof(WHV_PARTITION_PROPERTY));
953d7482ffeSIvan Shcherbakov
954d7482ffeSIvan Shcherbakov if (SUCCEEDED(hr)) {
955d7482ffeSIvan Shcherbakov whpx->exception_exit_bitmap = exceptions;
956d7482ffeSIvan Shcherbakov }
957d7482ffeSIvan Shcherbakov
958d7482ffeSIvan Shcherbakov return hr;
959d7482ffeSIvan Shcherbakov }
960d7482ffeSIvan Shcherbakov
961d7482ffeSIvan Shcherbakov
962d7482ffeSIvan Shcherbakov /*
963d7482ffeSIvan Shcherbakov * This function is called before/after stepping over a single instruction.
964d7482ffeSIvan Shcherbakov * It will update the CPU registers to arm/disarm the instruction stepping
965d7482ffeSIvan Shcherbakov * accordingly.
966d7482ffeSIvan Shcherbakov */
whpx_vcpu_configure_single_stepping(CPUState * cpu,bool set,uint64_t * exit_context_rflags)967d7482ffeSIvan Shcherbakov static HRESULT whpx_vcpu_configure_single_stepping(CPUState *cpu,
968d7482ffeSIvan Shcherbakov bool set,
969d7482ffeSIvan Shcherbakov uint64_t *exit_context_rflags)
970d7482ffeSIvan Shcherbakov {
971d7482ffeSIvan Shcherbakov WHV_REGISTER_NAME reg_name;
972d7482ffeSIvan Shcherbakov WHV_REGISTER_VALUE reg_value;
973d7482ffeSIvan Shcherbakov HRESULT hr;
974d7482ffeSIvan Shcherbakov struct whpx_state *whpx = &whpx_global;
975d7482ffeSIvan Shcherbakov
976d7482ffeSIvan Shcherbakov /*
977d7482ffeSIvan Shcherbakov * If we are trying to step over a single instruction, we need to set the
978d7482ffeSIvan Shcherbakov * TF bit in rflags. Otherwise, clear it.
979d7482ffeSIvan Shcherbakov */
980d7482ffeSIvan Shcherbakov reg_name = WHvX64RegisterRflags;
981d7482ffeSIvan Shcherbakov hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
982d7482ffeSIvan Shcherbakov whpx->partition,
983d7482ffeSIvan Shcherbakov cpu->cpu_index,
984d7482ffeSIvan Shcherbakov ®_name,
985d7482ffeSIvan Shcherbakov 1,
986d7482ffeSIvan Shcherbakov ®_value);
987d7482ffeSIvan Shcherbakov
988d7482ffeSIvan Shcherbakov if (FAILED(hr)) {
989d7482ffeSIvan Shcherbakov error_report("WHPX: Failed to get rflags, hr=%08lx", hr);
990d7482ffeSIvan Shcherbakov return hr;
991d7482ffeSIvan Shcherbakov }
992d7482ffeSIvan Shcherbakov
993d7482ffeSIvan Shcherbakov if (exit_context_rflags) {
994d7482ffeSIvan Shcherbakov assert(*exit_context_rflags == reg_value.Reg64);
995d7482ffeSIvan Shcherbakov }
996d7482ffeSIvan Shcherbakov
997d7482ffeSIvan Shcherbakov if (set) {
998d7482ffeSIvan Shcherbakov /* Raise WHvX64ExceptionTypeDebugTrapOrFault after each instruction */
999d7482ffeSIvan Shcherbakov reg_value.Reg64 |= TF_MASK;
1000d7482ffeSIvan Shcherbakov } else {
1001d7482ffeSIvan Shcherbakov reg_value.Reg64 &= ~TF_MASK;
1002d7482ffeSIvan Shcherbakov }
1003d7482ffeSIvan Shcherbakov
1004d7482ffeSIvan Shcherbakov if (exit_context_rflags) {
1005d7482ffeSIvan Shcherbakov *exit_context_rflags = reg_value.Reg64;
1006d7482ffeSIvan Shcherbakov }
1007d7482ffeSIvan Shcherbakov
1008d7482ffeSIvan Shcherbakov hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
1009d7482ffeSIvan Shcherbakov whpx->partition,
1010d7482ffeSIvan Shcherbakov cpu->cpu_index,
1011d7482ffeSIvan Shcherbakov ®_name,
1012d7482ffeSIvan Shcherbakov 1,
1013d7482ffeSIvan Shcherbakov ®_value);
1014d7482ffeSIvan Shcherbakov
1015d7482ffeSIvan Shcherbakov if (FAILED(hr)) {
1016d7482ffeSIvan Shcherbakov error_report("WHPX: Failed to set rflags,"
1017d7482ffeSIvan Shcherbakov " hr=%08lx",
1018d7482ffeSIvan Shcherbakov hr);
1019d7482ffeSIvan Shcherbakov return hr;
1020d7482ffeSIvan Shcherbakov }
1021d7482ffeSIvan Shcherbakov
1022d7482ffeSIvan Shcherbakov reg_name = WHvRegisterInterruptState;
1023d7482ffeSIvan Shcherbakov reg_value.Reg64 = 0;
1024d7482ffeSIvan Shcherbakov
1025d7482ffeSIvan Shcherbakov /* Suspend delivery of hardware interrupts during single-stepping. */
1026d7482ffeSIvan Shcherbakov reg_value.InterruptState.InterruptShadow = set != 0;
1027d7482ffeSIvan Shcherbakov
1028d7482ffeSIvan Shcherbakov hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
1029d7482ffeSIvan Shcherbakov whpx->partition,
1030d7482ffeSIvan Shcherbakov cpu->cpu_index,
1031d7482ffeSIvan Shcherbakov ®_name,
1032d7482ffeSIvan Shcherbakov 1,
1033d7482ffeSIvan Shcherbakov ®_value);
1034d7482ffeSIvan Shcherbakov
1035d7482ffeSIvan Shcherbakov if (FAILED(hr)) {
1036d7482ffeSIvan Shcherbakov error_report("WHPX: Failed to set InterruptState,"
1037d7482ffeSIvan Shcherbakov " hr=%08lx",
1038d7482ffeSIvan Shcherbakov hr);
1039d7482ffeSIvan Shcherbakov return hr;
1040d7482ffeSIvan Shcherbakov }
1041d7482ffeSIvan Shcherbakov
1042d7482ffeSIvan Shcherbakov if (!set) {
1043d7482ffeSIvan Shcherbakov /*
1044d7482ffeSIvan Shcherbakov * We have just finished stepping over a single instruction,
1045d7482ffeSIvan Shcherbakov * and intercepted the INT1 generated by it.
1046d7482ffeSIvan Shcherbakov * We need to now hide the INT1 from the guest,
1047d7482ffeSIvan Shcherbakov * as it would not be expecting it.
1048d7482ffeSIvan Shcherbakov */
1049d7482ffeSIvan Shcherbakov
1050d7482ffeSIvan Shcherbakov reg_name = WHvX64RegisterPendingDebugException;
1051d7482ffeSIvan Shcherbakov hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
1052d7482ffeSIvan Shcherbakov whpx->partition,
1053d7482ffeSIvan Shcherbakov cpu->cpu_index,
1054d7482ffeSIvan Shcherbakov ®_name,
1055d7482ffeSIvan Shcherbakov 1,
1056d7482ffeSIvan Shcherbakov ®_value);
1057d7482ffeSIvan Shcherbakov
1058d7482ffeSIvan Shcherbakov if (FAILED(hr)) {
1059d7482ffeSIvan Shcherbakov error_report("WHPX: Failed to get pending debug exceptions,"
1060d7482ffeSIvan Shcherbakov "hr=%08lx", hr);
1061d7482ffeSIvan Shcherbakov return hr;
1062d7482ffeSIvan Shcherbakov }
1063d7482ffeSIvan Shcherbakov
1064d7482ffeSIvan Shcherbakov if (reg_value.PendingDebugException.SingleStep) {
1065d7482ffeSIvan Shcherbakov reg_value.PendingDebugException.SingleStep = 0;
1066d7482ffeSIvan Shcherbakov
1067d7482ffeSIvan Shcherbakov hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
1068d7482ffeSIvan Shcherbakov whpx->partition,
1069d7482ffeSIvan Shcherbakov cpu->cpu_index,
1070d7482ffeSIvan Shcherbakov ®_name,
1071d7482ffeSIvan Shcherbakov 1,
1072d7482ffeSIvan Shcherbakov ®_value);
1073d7482ffeSIvan Shcherbakov
1074d7482ffeSIvan Shcherbakov if (FAILED(hr)) {
1075d7482ffeSIvan Shcherbakov error_report("WHPX: Failed to clear pending debug exceptions,"
1076d7482ffeSIvan Shcherbakov "hr=%08lx", hr);
1077d7482ffeSIvan Shcherbakov return hr;
1078d7482ffeSIvan Shcherbakov }
1079d7482ffeSIvan Shcherbakov }
1080d7482ffeSIvan Shcherbakov
1081d7482ffeSIvan Shcherbakov }
1082d7482ffeSIvan Shcherbakov
1083d7482ffeSIvan Shcherbakov return S_OK;
1084d7482ffeSIvan Shcherbakov }
1085d7482ffeSIvan Shcherbakov
1086d7482ffeSIvan Shcherbakov /* Tries to find a breakpoint at the specified address. */
whpx_lookup_breakpoint_by_addr(uint64_t address)1087d7482ffeSIvan Shcherbakov static struct whpx_breakpoint *whpx_lookup_breakpoint_by_addr(uint64_t address)
1088d7482ffeSIvan Shcherbakov {
1089d7482ffeSIvan Shcherbakov struct whpx_state *whpx = &whpx_global;
1090d7482ffeSIvan Shcherbakov int i;
1091d7482ffeSIvan Shcherbakov
1092d7482ffeSIvan Shcherbakov if (whpx->breakpoints.breakpoints) {
1093d7482ffeSIvan Shcherbakov for (i = 0; i < whpx->breakpoints.breakpoints->used; i++) {
1094d7482ffeSIvan Shcherbakov if (address == whpx->breakpoints.breakpoints->data[i].address) {
1095d7482ffeSIvan Shcherbakov return &whpx->breakpoints.breakpoints->data[i];
1096d7482ffeSIvan Shcherbakov }
1097d7482ffeSIvan Shcherbakov }
1098d7482ffeSIvan Shcherbakov }
1099d7482ffeSIvan Shcherbakov
1100d7482ffeSIvan Shcherbakov return NULL;
1101d7482ffeSIvan Shcherbakov }
1102d7482ffeSIvan Shcherbakov
1103d7482ffeSIvan Shcherbakov /*
1104d7482ffeSIvan Shcherbakov * Linux uses int3 (0xCC) during startup (see int3_selftest()) and for
1105d7482ffeSIvan Shcherbakov * debugging user-mode applications. Since the WHPX API does not offer
1106d7482ffeSIvan Shcherbakov * an easy way to pass the intercepted exception back to the guest, we
1107d7482ffeSIvan Shcherbakov * resort to using INT1 instead, and let the guest always handle INT3.
1108d7482ffeSIvan Shcherbakov */
1109d7482ffeSIvan Shcherbakov static const uint8_t whpx_breakpoint_instruction = 0xF1;
1110d7482ffeSIvan Shcherbakov
1111d7482ffeSIvan Shcherbakov /*
1112d7482ffeSIvan Shcherbakov * The WHPX QEMU backend implements breakpoints by writing the INT1
1113d7482ffeSIvan Shcherbakov * instruction into memory (ignoring the DRx registers). This raises a few
1114d7482ffeSIvan Shcherbakov * issues that need to be carefully handled:
1115d7482ffeSIvan Shcherbakov *
1116d7482ffeSIvan Shcherbakov * 1. Although unlikely, other parts of QEMU may set multiple breakpoints
1117d7482ffeSIvan Shcherbakov * at the same location, and later remove them in arbitrary order.
1118d7482ffeSIvan Shcherbakov * This should not cause memory corruption, and should only remove the
1119d7482ffeSIvan Shcherbakov * physical breakpoint instruction when the last QEMU breakpoint is gone.
1120d7482ffeSIvan Shcherbakov *
1121d7482ffeSIvan Shcherbakov * 2. Writing arbitrary virtual memory may fail if it's not mapped to a valid
1122d7482ffeSIvan Shcherbakov * physical location. Hence, physically adding/removing a breakpoint can
1123d7482ffeSIvan Shcherbakov * theoretically fail at any time. We need to keep track of it.
1124d7482ffeSIvan Shcherbakov *
1125d7482ffeSIvan Shcherbakov * The function below rebuilds a list of low-level breakpoints (one per
1126d7482ffeSIvan Shcherbakov * address, tracking the original instruction and any errors) from the list of
1127d7482ffeSIvan Shcherbakov * high-level breakpoints (set via cpu_breakpoint_insert()).
1128d7482ffeSIvan Shcherbakov *
1129d7482ffeSIvan Shcherbakov * In order to optimize performance, this function stores the list of
1130d7482ffeSIvan Shcherbakov * high-level breakpoints (a.k.a. CPU breakpoints) used to compute the
1131d7482ffeSIvan Shcherbakov * low-level ones, so that it won't be re-invoked until these breakpoints
1132d7482ffeSIvan Shcherbakov * change.
1133d7482ffeSIvan Shcherbakov *
1134d7482ffeSIvan Shcherbakov * Note that this function decides which breakpoints should be inserted into,
1135d7482ffeSIvan Shcherbakov * memory, but doesn't actually do it. The memory accessing is done in
1136d7482ffeSIvan Shcherbakov * whpx_apply_breakpoints().
1137d7482ffeSIvan Shcherbakov */
whpx_translate_cpu_breakpoints(struct whpx_breakpoints * breakpoints,CPUState * cpu,int cpu_breakpoint_count)1138d7482ffeSIvan Shcherbakov static void whpx_translate_cpu_breakpoints(
1139d7482ffeSIvan Shcherbakov struct whpx_breakpoints *breakpoints,
1140d7482ffeSIvan Shcherbakov CPUState *cpu,
1141d7482ffeSIvan Shcherbakov int cpu_breakpoint_count)
1142d7482ffeSIvan Shcherbakov {
1143d7482ffeSIvan Shcherbakov CPUBreakpoint *bp;
1144d7482ffeSIvan Shcherbakov int cpu_bp_index = 0;
1145d7482ffeSIvan Shcherbakov
1146d7482ffeSIvan Shcherbakov breakpoints->original_addresses =
1147d7482ffeSIvan Shcherbakov g_renew(vaddr, breakpoints->original_addresses, cpu_breakpoint_count);
1148d7482ffeSIvan Shcherbakov
1149d7482ffeSIvan Shcherbakov breakpoints->original_address_count = cpu_breakpoint_count;
1150d7482ffeSIvan Shcherbakov
1151d7482ffeSIvan Shcherbakov int max_breakpoints = cpu_breakpoint_count +
1152d7482ffeSIvan Shcherbakov (breakpoints->breakpoints ? breakpoints->breakpoints->used : 0);
1153d7482ffeSIvan Shcherbakov
1154d7482ffeSIvan Shcherbakov struct whpx_breakpoint_collection *new_breakpoints =
11550a553c12SMarkus Armbruster g_malloc0(sizeof(struct whpx_breakpoint_collection)
11560a553c12SMarkus Armbruster + max_breakpoints * sizeof(struct whpx_breakpoint));
1157d7482ffeSIvan Shcherbakov
1158d7482ffeSIvan Shcherbakov new_breakpoints->allocated = max_breakpoints;
1159d7482ffeSIvan Shcherbakov new_breakpoints->used = 0;
1160d7482ffeSIvan Shcherbakov
1161d7482ffeSIvan Shcherbakov /*
1162d7482ffeSIvan Shcherbakov * 1. Preserve all old breakpoints that could not be automatically
1163d7482ffeSIvan Shcherbakov * cleared when the CPU got stopped.
1164d7482ffeSIvan Shcherbakov */
1165d7482ffeSIvan Shcherbakov if (breakpoints->breakpoints) {
1166d7482ffeSIvan Shcherbakov int i;
1167d7482ffeSIvan Shcherbakov for (i = 0; i < breakpoints->breakpoints->used; i++) {
1168d7482ffeSIvan Shcherbakov if (breakpoints->breakpoints->data[i].state != WHPX_BP_CLEARED) {
1169d7482ffeSIvan Shcherbakov new_breakpoints->data[new_breakpoints->used++] =
1170d7482ffeSIvan Shcherbakov breakpoints->breakpoints->data[i];
1171d7482ffeSIvan Shcherbakov }
1172d7482ffeSIvan Shcherbakov }
1173d7482ffeSIvan Shcherbakov }
1174d7482ffeSIvan Shcherbakov
1175d7482ffeSIvan Shcherbakov /* 2. Map all CPU breakpoints to WHPX breakpoints */
1176d7482ffeSIvan Shcherbakov QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
1177d7482ffeSIvan Shcherbakov int i;
1178d7482ffeSIvan Shcherbakov bool found = false;
1179d7482ffeSIvan Shcherbakov
1180d7482ffeSIvan Shcherbakov /* This will be used to detect changed CPU breakpoints later. */
1181d7482ffeSIvan Shcherbakov breakpoints->original_addresses[cpu_bp_index++] = bp->pc;
1182d7482ffeSIvan Shcherbakov
1183d7482ffeSIvan Shcherbakov for (i = 0; i < new_breakpoints->used; i++) {
1184d7482ffeSIvan Shcherbakov /*
1185d7482ffeSIvan Shcherbakov * WARNING: This loop has O(N^2) complexity, where N is the
1186d7482ffeSIvan Shcherbakov * number of breakpoints. It should not be a bottleneck in
1187d7482ffeSIvan Shcherbakov * real-world scenarios, since it only needs to run once after
1188d7482ffeSIvan Shcherbakov * the breakpoints have been modified.
1189d7482ffeSIvan Shcherbakov * If this ever becomes a concern, it can be optimized by storing
1190d7482ffeSIvan Shcherbakov * high-level breakpoint objects in a tree or hash map.
1191d7482ffeSIvan Shcherbakov */
1192d7482ffeSIvan Shcherbakov
1193d7482ffeSIvan Shcherbakov if (new_breakpoints->data[i].address == bp->pc) {
1194d7482ffeSIvan Shcherbakov /* There was already a breakpoint at this address. */
1195d7482ffeSIvan Shcherbakov if (new_breakpoints->data[i].state == WHPX_BP_CLEAR_PENDING) {
1196d7482ffeSIvan Shcherbakov new_breakpoints->data[i].state = WHPX_BP_SET;
1197d7482ffeSIvan Shcherbakov } else if (new_breakpoints->data[i].state == WHPX_BP_SET) {
1198d7482ffeSIvan Shcherbakov new_breakpoints->data[i].state = WHPX_BP_SET_PENDING;
1199d7482ffeSIvan Shcherbakov }
1200d7482ffeSIvan Shcherbakov
1201d7482ffeSIvan Shcherbakov found = true;
1202d7482ffeSIvan Shcherbakov break;
1203d7482ffeSIvan Shcherbakov }
1204d7482ffeSIvan Shcherbakov }
1205d7482ffeSIvan Shcherbakov
1206d7482ffeSIvan Shcherbakov if (!found && new_breakpoints->used < new_breakpoints->allocated) {
1207d7482ffeSIvan Shcherbakov /* No WHPX breakpoint at this address. Create one. */
1208d7482ffeSIvan Shcherbakov new_breakpoints->data[new_breakpoints->used].address = bp->pc;
1209d7482ffeSIvan Shcherbakov new_breakpoints->data[new_breakpoints->used].state =
1210d7482ffeSIvan Shcherbakov WHPX_BP_SET_PENDING;
1211d7482ffeSIvan Shcherbakov new_breakpoints->used++;
1212d7482ffeSIvan Shcherbakov }
1213d7482ffeSIvan Shcherbakov }
1214d7482ffeSIvan Shcherbakov
1215d7482ffeSIvan Shcherbakov /*
1216d7482ffeSIvan Shcherbakov * Free the previous breakpoint list. This can be optimized by keeping
1217d7482ffeSIvan Shcherbakov * it as shadow buffer for the next computation instead of freeing
1218d7482ffeSIvan Shcherbakov * it immediately.
1219d7482ffeSIvan Shcherbakov */
1220d7482ffeSIvan Shcherbakov g_free(breakpoints->breakpoints);
1221d7482ffeSIvan Shcherbakov
1222d7482ffeSIvan Shcherbakov breakpoints->breakpoints = new_breakpoints;
1223d7482ffeSIvan Shcherbakov }
1224d7482ffeSIvan Shcherbakov
1225d7482ffeSIvan Shcherbakov /*
1226d7482ffeSIvan Shcherbakov * Physically inserts/removes the breakpoints by reading and writing the
1227d7482ffeSIvan Shcherbakov * physical memory, keeping a track of the failed attempts.
1228d7482ffeSIvan Shcherbakov *
1229d7482ffeSIvan Shcherbakov * Passing resuming=true will try to set all previously unset breakpoints.
1230d7482ffeSIvan Shcherbakov * Passing resuming=false will remove all inserted ones.
1231d7482ffeSIvan Shcherbakov */
whpx_apply_breakpoints(struct whpx_breakpoint_collection * breakpoints,CPUState * cpu,bool resuming)1232d7482ffeSIvan Shcherbakov static void whpx_apply_breakpoints(
1233d7482ffeSIvan Shcherbakov struct whpx_breakpoint_collection *breakpoints,
1234d7482ffeSIvan Shcherbakov CPUState *cpu,
1235d7482ffeSIvan Shcherbakov bool resuming)
1236d7482ffeSIvan Shcherbakov {
1237d7482ffeSIvan Shcherbakov int i, rc;
1238d7482ffeSIvan Shcherbakov if (!breakpoints) {
1239d7482ffeSIvan Shcherbakov return;
1240d7482ffeSIvan Shcherbakov }
1241d7482ffeSIvan Shcherbakov
1242d7482ffeSIvan Shcherbakov for (i = 0; i < breakpoints->used; i++) {
1243d7482ffeSIvan Shcherbakov /* Decide what to do right now based on the last known state. */
1244d7482ffeSIvan Shcherbakov WhpxBreakpointState state = breakpoints->data[i].state;
1245d7482ffeSIvan Shcherbakov switch (state) {
1246d7482ffeSIvan Shcherbakov case WHPX_BP_CLEARED:
1247d7482ffeSIvan Shcherbakov if (resuming) {
1248d7482ffeSIvan Shcherbakov state = WHPX_BP_SET_PENDING;
1249d7482ffeSIvan Shcherbakov }
1250d7482ffeSIvan Shcherbakov break;
1251d7482ffeSIvan Shcherbakov case WHPX_BP_SET_PENDING:
1252d7482ffeSIvan Shcherbakov if (!resuming) {
1253d7482ffeSIvan Shcherbakov state = WHPX_BP_CLEARED;
1254d7482ffeSIvan Shcherbakov }
1255d7482ffeSIvan Shcherbakov break;
1256d7482ffeSIvan Shcherbakov case WHPX_BP_SET:
1257d7482ffeSIvan Shcherbakov if (!resuming) {
1258d7482ffeSIvan Shcherbakov state = WHPX_BP_CLEAR_PENDING;
1259d7482ffeSIvan Shcherbakov }
1260d7482ffeSIvan Shcherbakov break;
1261d7482ffeSIvan Shcherbakov case WHPX_BP_CLEAR_PENDING:
1262d7482ffeSIvan Shcherbakov if (resuming) {
1263d7482ffeSIvan Shcherbakov state = WHPX_BP_SET;
1264d7482ffeSIvan Shcherbakov }
1265d7482ffeSIvan Shcherbakov break;
1266d7482ffeSIvan Shcherbakov }
1267d7482ffeSIvan Shcherbakov
1268d7482ffeSIvan Shcherbakov if (state == WHPX_BP_SET_PENDING) {
1269d7482ffeSIvan Shcherbakov /* Remember the original instruction. */
1270d7482ffeSIvan Shcherbakov rc = cpu_memory_rw_debug(cpu,
1271d7482ffeSIvan Shcherbakov breakpoints->data[i].address,
1272d7482ffeSIvan Shcherbakov &breakpoints->data[i].original_instruction,
1273d7482ffeSIvan Shcherbakov 1,
1274d7482ffeSIvan Shcherbakov false);
1275d7482ffeSIvan Shcherbakov
1276d7482ffeSIvan Shcherbakov if (!rc) {
1277d7482ffeSIvan Shcherbakov /* Write the breakpoint instruction. */
1278d7482ffeSIvan Shcherbakov rc = cpu_memory_rw_debug(cpu,
1279d7482ffeSIvan Shcherbakov breakpoints->data[i].address,
1280d7482ffeSIvan Shcherbakov (void *)&whpx_breakpoint_instruction,
1281d7482ffeSIvan Shcherbakov 1,
1282d7482ffeSIvan Shcherbakov true);
1283d7482ffeSIvan Shcherbakov }
1284d7482ffeSIvan Shcherbakov
1285d7482ffeSIvan Shcherbakov if (!rc) {
1286d7482ffeSIvan Shcherbakov state = WHPX_BP_SET;
1287d7482ffeSIvan Shcherbakov }
1288d7482ffeSIvan Shcherbakov
1289d7482ffeSIvan Shcherbakov }
1290d7482ffeSIvan Shcherbakov
1291d7482ffeSIvan Shcherbakov if (state == WHPX_BP_CLEAR_PENDING) {
1292d7482ffeSIvan Shcherbakov /* Restore the original instruction. */
1293d7482ffeSIvan Shcherbakov rc = cpu_memory_rw_debug(cpu,
1294d7482ffeSIvan Shcherbakov breakpoints->data[i].address,
1295d7482ffeSIvan Shcherbakov &breakpoints->data[i].original_instruction,
1296d7482ffeSIvan Shcherbakov 1,
1297d7482ffeSIvan Shcherbakov true);
1298d7482ffeSIvan Shcherbakov
1299d7482ffeSIvan Shcherbakov if (!rc) {
1300d7482ffeSIvan Shcherbakov state = WHPX_BP_CLEARED;
1301d7482ffeSIvan Shcherbakov }
1302d7482ffeSIvan Shcherbakov }
1303d7482ffeSIvan Shcherbakov
1304d7482ffeSIvan Shcherbakov breakpoints->data[i].state = state;
1305d7482ffeSIvan Shcherbakov }
1306d7482ffeSIvan Shcherbakov }
1307d7482ffeSIvan Shcherbakov
1308d7482ffeSIvan Shcherbakov /*
1309d7482ffeSIvan Shcherbakov * This function is called when the a VCPU is about to start and no other
1310d7482ffeSIvan Shcherbakov * VCPUs have been started so far. Since the VCPU start order could be
1311d7482ffeSIvan Shcherbakov * arbitrary, it doesn't have to be VCPU#0.
1312d7482ffeSIvan Shcherbakov *
1313d7482ffeSIvan Shcherbakov * It is used to commit the breakpoints into memory, and configure WHPX
1314d7482ffeSIvan Shcherbakov * to intercept debug exceptions.
1315d7482ffeSIvan Shcherbakov *
1316d7482ffeSIvan Shcherbakov * Note that whpx_set_exception_exit_bitmap() cannot be called if one or
1317d7482ffeSIvan Shcherbakov * more VCPUs are already running, so this is the best place to do it.
1318d7482ffeSIvan Shcherbakov */
whpx_first_vcpu_starting(CPUState * cpu)1319d7482ffeSIvan Shcherbakov static int whpx_first_vcpu_starting(CPUState *cpu)
1320d7482ffeSIvan Shcherbakov {
1321d7482ffeSIvan Shcherbakov struct whpx_state *whpx = &whpx_global;
1322d7482ffeSIvan Shcherbakov HRESULT hr;
1323d7482ffeSIvan Shcherbakov
1324195801d7SStefan Hajnoczi g_assert(bql_locked());
1325d7482ffeSIvan Shcherbakov
1326d7482ffeSIvan Shcherbakov if (!QTAILQ_EMPTY(&cpu->breakpoints) ||
1327d7482ffeSIvan Shcherbakov (whpx->breakpoints.breakpoints &&
1328d7482ffeSIvan Shcherbakov whpx->breakpoints.breakpoints->used)) {
1329d7482ffeSIvan Shcherbakov CPUBreakpoint *bp;
1330d7482ffeSIvan Shcherbakov int i = 0;
1331d7482ffeSIvan Shcherbakov bool update_pending = false;
1332d7482ffeSIvan Shcherbakov
1333d7482ffeSIvan Shcherbakov QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
1334d7482ffeSIvan Shcherbakov if (i >= whpx->breakpoints.original_address_count ||
1335d7482ffeSIvan Shcherbakov bp->pc != whpx->breakpoints.original_addresses[i]) {
1336d7482ffeSIvan Shcherbakov update_pending = true;
1337d7482ffeSIvan Shcherbakov }
1338d7482ffeSIvan Shcherbakov
1339d7482ffeSIvan Shcherbakov i++;
1340d7482ffeSIvan Shcherbakov }
1341d7482ffeSIvan Shcherbakov
1342d7482ffeSIvan Shcherbakov if (i != whpx->breakpoints.original_address_count) {
1343d7482ffeSIvan Shcherbakov update_pending = true;
1344d7482ffeSIvan Shcherbakov }
1345d7482ffeSIvan Shcherbakov
1346d7482ffeSIvan Shcherbakov if (update_pending) {
1347d7482ffeSIvan Shcherbakov /*
1348d7482ffeSIvan Shcherbakov * The CPU breakpoints have changed since the last call to
1349d7482ffeSIvan Shcherbakov * whpx_translate_cpu_breakpoints(). WHPX breakpoints must
1350d7482ffeSIvan Shcherbakov * now be recomputed.
1351d7482ffeSIvan Shcherbakov */
1352d7482ffeSIvan Shcherbakov whpx_translate_cpu_breakpoints(&whpx->breakpoints, cpu, i);
1353d7482ffeSIvan Shcherbakov }
1354d7482ffeSIvan Shcherbakov
1355d7482ffeSIvan Shcherbakov /* Actually insert the breakpoints into the memory. */
1356d7482ffeSIvan Shcherbakov whpx_apply_breakpoints(whpx->breakpoints.breakpoints, cpu, true);
1357d7482ffeSIvan Shcherbakov }
1358d7482ffeSIvan Shcherbakov
1359d7482ffeSIvan Shcherbakov uint64_t exception_mask;
1360d7482ffeSIvan Shcherbakov if (whpx->step_pending ||
1361d7482ffeSIvan Shcherbakov (whpx->breakpoints.breakpoints &&
1362d7482ffeSIvan Shcherbakov whpx->breakpoints.breakpoints->used)) {
1363d7482ffeSIvan Shcherbakov /*
1364d7482ffeSIvan Shcherbakov * We are either attempting to single-step one or more CPUs, or
1365d7482ffeSIvan Shcherbakov * have one or more breakpoints enabled. Both require intercepting
1366d7482ffeSIvan Shcherbakov * the WHvX64ExceptionTypeBreakpointTrap exception.
1367d7482ffeSIvan Shcherbakov */
1368d7482ffeSIvan Shcherbakov
1369d7482ffeSIvan Shcherbakov exception_mask = 1UL << WHvX64ExceptionTypeDebugTrapOrFault;
1370d7482ffeSIvan Shcherbakov } else {
1371d7482ffeSIvan Shcherbakov /* Let the guest handle all exceptions. */
1372d7482ffeSIvan Shcherbakov exception_mask = 0;
1373d7482ffeSIvan Shcherbakov }
1374d7482ffeSIvan Shcherbakov
1375d7482ffeSIvan Shcherbakov hr = whpx_set_exception_exit_bitmap(exception_mask);
1376d7482ffeSIvan Shcherbakov if (!SUCCEEDED(hr)) {
1377d7482ffeSIvan Shcherbakov error_report("WHPX: Failed to update exception exit mask,"
1378d7482ffeSIvan Shcherbakov "hr=%08lx.", hr);
1379d7482ffeSIvan Shcherbakov return 1;
1380d7482ffeSIvan Shcherbakov }
1381d7482ffeSIvan Shcherbakov
1382d7482ffeSIvan Shcherbakov return 0;
1383d7482ffeSIvan Shcherbakov }
1384d7482ffeSIvan Shcherbakov
1385d7482ffeSIvan Shcherbakov /*
1386d7482ffeSIvan Shcherbakov * This function is called when the last VCPU has finished running.
1387d7482ffeSIvan Shcherbakov * It is used to remove any previously set breakpoints from memory.
1388d7482ffeSIvan Shcherbakov */
whpx_last_vcpu_stopping(CPUState * cpu)1389d7482ffeSIvan Shcherbakov static int whpx_last_vcpu_stopping(CPUState *cpu)
1390d7482ffeSIvan Shcherbakov {
1391d7482ffeSIvan Shcherbakov whpx_apply_breakpoints(whpx_global.breakpoints.breakpoints, cpu, false);
1392d7482ffeSIvan Shcherbakov return 0;
1393d7482ffeSIvan Shcherbakov }
1394d7482ffeSIvan Shcherbakov
1395d7482ffeSIvan Shcherbakov /* Returns the address of the next instruction that is about to be executed. */
whpx_vcpu_get_pc(CPUState * cpu,bool exit_context_valid)1396d7482ffeSIvan Shcherbakov static vaddr whpx_vcpu_get_pc(CPUState *cpu, bool exit_context_valid)
1397d7482ffeSIvan Shcherbakov {
13989ad49538SPhilippe Mathieu-Daudé if (cpu->accel->dirty) {
1399d7482ffeSIvan Shcherbakov /* The CPU registers have been modified by other parts of QEMU. */
140094956d7bSPhilippe Mathieu-Daudé return cpu_env(cpu)->eip;
1401d7482ffeSIvan Shcherbakov } else if (exit_context_valid) {
1402d7482ffeSIvan Shcherbakov /*
1403d7482ffeSIvan Shcherbakov * The CPU registers have not been modified by neither other parts
1404d7482ffeSIvan Shcherbakov * of QEMU, nor this port by calling WHvSetVirtualProcessorRegisters().
1405d7482ffeSIvan Shcherbakov * This is the most common case.
1406d7482ffeSIvan Shcherbakov */
1407441f2449SPhilippe Mathieu-Daudé AccelCPUState *vcpu = cpu->accel;
1408d7482ffeSIvan Shcherbakov return vcpu->exit_ctx.VpContext.Rip;
1409d7482ffeSIvan Shcherbakov } else {
1410d7482ffeSIvan Shcherbakov /*
1411d7482ffeSIvan Shcherbakov * The CPU registers have been modified by a call to
1412d7482ffeSIvan Shcherbakov * WHvSetVirtualProcessorRegisters() and must be re-queried from
1413d7482ffeSIvan Shcherbakov * the target.
1414d7482ffeSIvan Shcherbakov */
1415d7482ffeSIvan Shcherbakov WHV_REGISTER_VALUE reg_value;
1416d7482ffeSIvan Shcherbakov WHV_REGISTER_NAME reg_name = WHvX64RegisterRip;
1417d7482ffeSIvan Shcherbakov HRESULT hr;
1418d7482ffeSIvan Shcherbakov struct whpx_state *whpx = &whpx_global;
1419d7482ffeSIvan Shcherbakov
1420d7482ffeSIvan Shcherbakov hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
1421d7482ffeSIvan Shcherbakov whpx->partition,
1422d7482ffeSIvan Shcherbakov cpu->cpu_index,
1423d7482ffeSIvan Shcherbakov ®_name,
1424d7482ffeSIvan Shcherbakov 1,
1425d7482ffeSIvan Shcherbakov ®_value);
1426d7482ffeSIvan Shcherbakov
1427d7482ffeSIvan Shcherbakov if (FAILED(hr)) {
1428d7482ffeSIvan Shcherbakov error_report("WHPX: Failed to get PC, hr=%08lx", hr);
1429d7482ffeSIvan Shcherbakov return 0;
1430d7482ffeSIvan Shcherbakov }
1431d7482ffeSIvan Shcherbakov
1432d7482ffeSIvan Shcherbakov return reg_value.Reg64;
1433d7482ffeSIvan Shcherbakov }
1434d7482ffeSIvan Shcherbakov }
1435d7482ffeSIvan Shcherbakov
whpx_handle_halt(CPUState * cpu)14361fc33bb9SClaudio Fontana static int whpx_handle_halt(CPUState *cpu)
14371fc33bb9SClaudio Fontana {
14381fc33bb9SClaudio Fontana int ret = 0;
14391fc33bb9SClaudio Fontana
1440195801d7SStefan Hajnoczi bql_lock();
14411fc33bb9SClaudio Fontana if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
144294956d7bSPhilippe Mathieu-Daudé (cpu_env(cpu)->eflags & IF_MASK)) &&
14431fc33bb9SClaudio Fontana !(cpu->interrupt_request & CPU_INTERRUPT_NMI)) {
14441fc33bb9SClaudio Fontana cpu->exception_index = EXCP_HLT;
14451fc33bb9SClaudio Fontana cpu->halted = true;
14461fc33bb9SClaudio Fontana ret = 1;
14471fc33bb9SClaudio Fontana }
1448195801d7SStefan Hajnoczi bql_unlock();
14491fc33bb9SClaudio Fontana
14501fc33bb9SClaudio Fontana return ret;
14511fc33bb9SClaudio Fontana }
14521fc33bb9SClaudio Fontana
whpx_vcpu_pre_run(CPUState * cpu)14531fc33bb9SClaudio Fontana static void whpx_vcpu_pre_run(CPUState *cpu)
14541fc33bb9SClaudio Fontana {
14551fc33bb9SClaudio Fontana HRESULT hr;
14561fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
1457441f2449SPhilippe Mathieu-Daudé AccelCPUState *vcpu = cpu->accel;
14581fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu);
1459b77af26eSRichard Henderson CPUX86State *env = &x86_cpu->env;
14601fc33bb9SClaudio Fontana int irq;
14611fc33bb9SClaudio Fontana uint8_t tpr;
14621fc33bb9SClaudio Fontana WHV_X64_PENDING_INTERRUPTION_REGISTER new_int;
14631fc33bb9SClaudio Fontana UINT32 reg_count = 0;
14641fc33bb9SClaudio Fontana WHV_REGISTER_VALUE reg_values[3];
14651fc33bb9SClaudio Fontana WHV_REGISTER_NAME reg_names[3];
14661fc33bb9SClaudio Fontana
14671fc33bb9SClaudio Fontana memset(&new_int, 0, sizeof(new_int));
14681fc33bb9SClaudio Fontana memset(reg_values, 0, sizeof(reg_values));
14691fc33bb9SClaudio Fontana
1470195801d7SStefan Hajnoczi bql_lock();
14711fc33bb9SClaudio Fontana
14721fc33bb9SClaudio Fontana /* Inject NMI */
14731fc33bb9SClaudio Fontana if (!vcpu->interruption_pending &&
14741fc33bb9SClaudio Fontana cpu->interrupt_request & (CPU_INTERRUPT_NMI | CPU_INTERRUPT_SMI)) {
14751fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_NMI) {
14761fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_NMI;
14771fc33bb9SClaudio Fontana vcpu->interruptable = false;
14781fc33bb9SClaudio Fontana new_int.InterruptionType = WHvX64PendingNmi;
14791fc33bb9SClaudio Fontana new_int.InterruptionPending = 1;
14801fc33bb9SClaudio Fontana new_int.InterruptionVector = 2;
14811fc33bb9SClaudio Fontana }
14821fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_SMI) {
14831fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_SMI;
14841fc33bb9SClaudio Fontana }
14851fc33bb9SClaudio Fontana }
14861fc33bb9SClaudio Fontana
14871fc33bb9SClaudio Fontana /*
14881fc33bb9SClaudio Fontana * Force the VCPU out of its inner loop to process any INIT requests or
14891fc33bb9SClaudio Fontana * commit pending TPR access.
14901fc33bb9SClaudio Fontana */
14911fc33bb9SClaudio Fontana if (cpu->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) {
14921fc33bb9SClaudio Fontana if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) &&
14931fc33bb9SClaudio Fontana !(env->hflags & HF_SMM_MASK)) {
14941fc33bb9SClaudio Fontana cpu->exit_request = 1;
14951fc33bb9SClaudio Fontana }
14961fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_TPR) {
14971fc33bb9SClaudio Fontana cpu->exit_request = 1;
14981fc33bb9SClaudio Fontana }
14991fc33bb9SClaudio Fontana }
15001fc33bb9SClaudio Fontana
15011fc33bb9SClaudio Fontana /* Get pending hard interruption or replay one that was overwritten */
15021fc33bb9SClaudio Fontana if (!whpx_apic_in_platform()) {
15031fc33bb9SClaudio Fontana if (!vcpu->interruption_pending &&
15041fc33bb9SClaudio Fontana vcpu->interruptable && (env->eflags & IF_MASK)) {
15051fc33bb9SClaudio Fontana assert(!new_int.InterruptionPending);
15061fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_HARD) {
15071fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
15081fc33bb9SClaudio Fontana irq = cpu_get_pic_interrupt(env);
15091fc33bb9SClaudio Fontana if (irq >= 0) {
15101fc33bb9SClaudio Fontana new_int.InterruptionType = WHvX64PendingInterrupt;
15111fc33bb9SClaudio Fontana new_int.InterruptionPending = 1;
15121fc33bb9SClaudio Fontana new_int.InterruptionVector = irq;
15131fc33bb9SClaudio Fontana }
15141fc33bb9SClaudio Fontana }
15151fc33bb9SClaudio Fontana }
15161fc33bb9SClaudio Fontana
15171fc33bb9SClaudio Fontana /* Setup interrupt state if new one was prepared */
15181fc33bb9SClaudio Fontana if (new_int.InterruptionPending) {
15191fc33bb9SClaudio Fontana reg_values[reg_count].PendingInterruption = new_int;
15201fc33bb9SClaudio Fontana reg_names[reg_count] = WHvRegisterPendingInterruption;
15211fc33bb9SClaudio Fontana reg_count += 1;
15221fc33bb9SClaudio Fontana }
15231fc33bb9SClaudio Fontana } else if (vcpu->ready_for_pic_interrupt &&
15241fc33bb9SClaudio Fontana (cpu->interrupt_request & CPU_INTERRUPT_HARD)) {
15251fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
15261fc33bb9SClaudio Fontana irq = cpu_get_pic_interrupt(env);
15271fc33bb9SClaudio Fontana if (irq >= 0) {
15281fc33bb9SClaudio Fontana reg_names[reg_count] = WHvRegisterPendingEvent;
15291fc33bb9SClaudio Fontana reg_values[reg_count].ExtIntEvent = (WHV_X64_PENDING_EXT_INT_EVENT)
15301fc33bb9SClaudio Fontana {
15311fc33bb9SClaudio Fontana .EventPending = 1,
15321fc33bb9SClaudio Fontana .EventType = WHvX64PendingEventExtInt,
15331fc33bb9SClaudio Fontana .Vector = irq,
15341fc33bb9SClaudio Fontana };
15351fc33bb9SClaudio Fontana reg_count += 1;
15361fc33bb9SClaudio Fontana }
15371fc33bb9SClaudio Fontana }
15381fc33bb9SClaudio Fontana
15391fc33bb9SClaudio Fontana /* Sync the TPR to the CR8 if was modified during the intercept */
1540f000bc74SIvan Shcherbakov tpr = whpx_apic_tpr_to_cr8(cpu_get_apic_tpr(x86_cpu->apic_state));
15411fc33bb9SClaudio Fontana if (tpr != vcpu->tpr) {
15421fc33bb9SClaudio Fontana vcpu->tpr = tpr;
15431fc33bb9SClaudio Fontana reg_values[reg_count].Reg64 = tpr;
15441fc33bb9SClaudio Fontana cpu->exit_request = 1;
15451fc33bb9SClaudio Fontana reg_names[reg_count] = WHvX64RegisterCr8;
15461fc33bb9SClaudio Fontana reg_count += 1;
15471fc33bb9SClaudio Fontana }
15481fc33bb9SClaudio Fontana
15491fc33bb9SClaudio Fontana /* Update the state of the interrupt delivery notification */
15501fc33bb9SClaudio Fontana if (!vcpu->window_registered &&
15511fc33bb9SClaudio Fontana cpu->interrupt_request & CPU_INTERRUPT_HARD) {
15521fc33bb9SClaudio Fontana reg_values[reg_count].DeliverabilityNotifications =
15531fc33bb9SClaudio Fontana (WHV_X64_DELIVERABILITY_NOTIFICATIONS_REGISTER) {
15541fc33bb9SClaudio Fontana .InterruptNotification = 1
15551fc33bb9SClaudio Fontana };
15561fc33bb9SClaudio Fontana vcpu->window_registered = 1;
15571fc33bb9SClaudio Fontana reg_names[reg_count] = WHvX64RegisterDeliverabilityNotifications;
15581fc33bb9SClaudio Fontana reg_count += 1;
15591fc33bb9SClaudio Fontana }
15601fc33bb9SClaudio Fontana
1561195801d7SStefan Hajnoczi bql_unlock();
15621fc33bb9SClaudio Fontana vcpu->ready_for_pic_interrupt = false;
15631fc33bb9SClaudio Fontana
15641fc33bb9SClaudio Fontana if (reg_count) {
15651fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
15661fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index,
15671fc33bb9SClaudio Fontana reg_names, reg_count, reg_values);
15681fc33bb9SClaudio Fontana if (FAILED(hr)) {
15691fc33bb9SClaudio Fontana error_report("WHPX: Failed to set interrupt state registers,"
15701fc33bb9SClaudio Fontana " hr=%08lx", hr);
15711fc33bb9SClaudio Fontana }
15721fc33bb9SClaudio Fontana }
15731fc33bb9SClaudio Fontana
15741fc33bb9SClaudio Fontana return;
15751fc33bb9SClaudio Fontana }
15761fc33bb9SClaudio Fontana
whpx_vcpu_post_run(CPUState * cpu)15771fc33bb9SClaudio Fontana static void whpx_vcpu_post_run(CPUState *cpu)
15781fc33bb9SClaudio Fontana {
1579441f2449SPhilippe Mathieu-Daudé AccelCPUState *vcpu = cpu->accel;
15801fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu);
1581b77af26eSRichard Henderson CPUX86State *env = &x86_cpu->env;
15821fc33bb9SClaudio Fontana
15831fc33bb9SClaudio Fontana env->eflags = vcpu->exit_ctx.VpContext.Rflags;
15841fc33bb9SClaudio Fontana
15851fc33bb9SClaudio Fontana uint64_t tpr = vcpu->exit_ctx.VpContext.Cr8;
15861fc33bb9SClaudio Fontana if (vcpu->tpr != tpr) {
15871fc33bb9SClaudio Fontana vcpu->tpr = tpr;
1588195801d7SStefan Hajnoczi bql_lock();
1589f000bc74SIvan Shcherbakov cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(vcpu->tpr));
1590195801d7SStefan Hajnoczi bql_unlock();
15911fc33bb9SClaudio Fontana }
15921fc33bb9SClaudio Fontana
15931fc33bb9SClaudio Fontana vcpu->interruption_pending =
15941fc33bb9SClaudio Fontana vcpu->exit_ctx.VpContext.ExecutionState.InterruptionPending;
15951fc33bb9SClaudio Fontana
15961fc33bb9SClaudio Fontana vcpu->interruptable =
15971fc33bb9SClaudio Fontana !vcpu->exit_ctx.VpContext.ExecutionState.InterruptShadow;
15981fc33bb9SClaudio Fontana
15991fc33bb9SClaudio Fontana return;
16001fc33bb9SClaudio Fontana }
16011fc33bb9SClaudio Fontana
whpx_vcpu_process_async_events(CPUState * cpu)16021fc33bb9SClaudio Fontana static void whpx_vcpu_process_async_events(CPUState *cpu)
16031fc33bb9SClaudio Fontana {
16041fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu);
1605b77af26eSRichard Henderson CPUX86State *env = &x86_cpu->env;
1606441f2449SPhilippe Mathieu-Daudé AccelCPUState *vcpu = cpu->accel;
16071fc33bb9SClaudio Fontana
16081fc33bb9SClaudio Fontana if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) &&
16091fc33bb9SClaudio Fontana !(env->hflags & HF_SMM_MASK)) {
16101fc33bb9SClaudio Fontana whpx_cpu_synchronize_state(cpu);
16111fc33bb9SClaudio Fontana do_cpu_init(x86_cpu);
16121fc33bb9SClaudio Fontana vcpu->interruptable = true;
16131fc33bb9SClaudio Fontana }
16141fc33bb9SClaudio Fontana
16151fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
16161fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_POLL;
16171fc33bb9SClaudio Fontana apic_poll_irq(x86_cpu->apic_state);
16181fc33bb9SClaudio Fontana }
16191fc33bb9SClaudio Fontana
16201fc33bb9SClaudio Fontana if (((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
16211fc33bb9SClaudio Fontana (env->eflags & IF_MASK)) ||
16221fc33bb9SClaudio Fontana (cpu->interrupt_request & CPU_INTERRUPT_NMI)) {
16231fc33bb9SClaudio Fontana cpu->halted = false;
16241fc33bb9SClaudio Fontana }
16251fc33bb9SClaudio Fontana
16261fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) {
16271fc33bb9SClaudio Fontana whpx_cpu_synchronize_state(cpu);
16281fc33bb9SClaudio Fontana do_cpu_sipi(x86_cpu);
16291fc33bb9SClaudio Fontana }
16301fc33bb9SClaudio Fontana
16311fc33bb9SClaudio Fontana if (cpu->interrupt_request & CPU_INTERRUPT_TPR) {
16321fc33bb9SClaudio Fontana cpu->interrupt_request &= ~CPU_INTERRUPT_TPR;
16331fc33bb9SClaudio Fontana whpx_cpu_synchronize_state(cpu);
16341fc33bb9SClaudio Fontana apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip,
16351fc33bb9SClaudio Fontana env->tpr_access_type);
16361fc33bb9SClaudio Fontana }
16371fc33bb9SClaudio Fontana
16381fc33bb9SClaudio Fontana return;
16391fc33bb9SClaudio Fontana }
16401fc33bb9SClaudio Fontana
whpx_vcpu_run(CPUState * cpu)16411fc33bb9SClaudio Fontana static int whpx_vcpu_run(CPUState *cpu)
16421fc33bb9SClaudio Fontana {
16431fc33bb9SClaudio Fontana HRESULT hr;
16441fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
1645441f2449SPhilippe Mathieu-Daudé AccelCPUState *vcpu = cpu->accel;
1646d7482ffeSIvan Shcherbakov struct whpx_breakpoint *stepped_over_bp = NULL;
1647d7482ffeSIvan Shcherbakov WhpxStepMode exclusive_step_mode = WHPX_STEP_NONE;
16481fc33bb9SClaudio Fontana int ret;
16491fc33bb9SClaudio Fontana
1650195801d7SStefan Hajnoczi g_assert(bql_locked());
1651d7482ffeSIvan Shcherbakov
1652d7482ffeSIvan Shcherbakov if (whpx->running_cpus++ == 0) {
1653d7482ffeSIvan Shcherbakov /* Insert breakpoints into memory, update exception exit bitmap. */
1654d7482ffeSIvan Shcherbakov ret = whpx_first_vcpu_starting(cpu);
1655d7482ffeSIvan Shcherbakov if (ret != 0) {
1656d7482ffeSIvan Shcherbakov return ret;
1657d7482ffeSIvan Shcherbakov }
1658d7482ffeSIvan Shcherbakov }
1659d7482ffeSIvan Shcherbakov
1660d7482ffeSIvan Shcherbakov if (whpx->breakpoints.breakpoints &&
1661d7482ffeSIvan Shcherbakov whpx->breakpoints.breakpoints->used > 0)
1662d7482ffeSIvan Shcherbakov {
1663d7482ffeSIvan Shcherbakov uint64_t pc = whpx_vcpu_get_pc(cpu, true);
1664d7482ffeSIvan Shcherbakov stepped_over_bp = whpx_lookup_breakpoint_by_addr(pc);
1665d7482ffeSIvan Shcherbakov if (stepped_over_bp && stepped_over_bp->state != WHPX_BP_SET) {
1666d7482ffeSIvan Shcherbakov stepped_over_bp = NULL;
1667d7482ffeSIvan Shcherbakov }
1668d7482ffeSIvan Shcherbakov
1669d7482ffeSIvan Shcherbakov if (stepped_over_bp) {
1670d7482ffeSIvan Shcherbakov /*
1671d7482ffeSIvan Shcherbakov * We are trying to run the instruction overwritten by an active
1672d7482ffeSIvan Shcherbakov * breakpoint. We will temporarily disable the breakpoint, suspend
1673d7482ffeSIvan Shcherbakov * other CPUs, and step over the instruction.
1674d7482ffeSIvan Shcherbakov */
1675d7482ffeSIvan Shcherbakov exclusive_step_mode = WHPX_STEP_EXCLUSIVE;
1676d7482ffeSIvan Shcherbakov }
1677d7482ffeSIvan Shcherbakov }
1678d7482ffeSIvan Shcherbakov
1679d7482ffeSIvan Shcherbakov if (exclusive_step_mode == WHPX_STEP_NONE) {
16801fc33bb9SClaudio Fontana whpx_vcpu_process_async_events(cpu);
16811fc33bb9SClaudio Fontana if (cpu->halted && !whpx_apic_in_platform()) {
16821fc33bb9SClaudio Fontana cpu->exception_index = EXCP_HLT;
16831fc33bb9SClaudio Fontana qatomic_set(&cpu->exit_request, false);
16841fc33bb9SClaudio Fontana return 0;
16851fc33bb9SClaudio Fontana }
1686d7482ffeSIvan Shcherbakov }
16871fc33bb9SClaudio Fontana
1688195801d7SStefan Hajnoczi bql_unlock();
1689d7482ffeSIvan Shcherbakov
1690d7482ffeSIvan Shcherbakov if (exclusive_step_mode != WHPX_STEP_NONE) {
1691d7482ffeSIvan Shcherbakov start_exclusive();
1692d7482ffeSIvan Shcherbakov g_assert(cpu == current_cpu);
1693d7482ffeSIvan Shcherbakov g_assert(!cpu->running);
1694d7482ffeSIvan Shcherbakov cpu->running = true;
1695d7482ffeSIvan Shcherbakov
1696d7482ffeSIvan Shcherbakov hr = whpx_set_exception_exit_bitmap(
1697d7482ffeSIvan Shcherbakov 1UL << WHvX64ExceptionTypeDebugTrapOrFault);
1698d7482ffeSIvan Shcherbakov if (!SUCCEEDED(hr)) {
1699d7482ffeSIvan Shcherbakov error_report("WHPX: Failed to update exception exit mask, "
1700d7482ffeSIvan Shcherbakov "hr=%08lx.", hr);
1701d7482ffeSIvan Shcherbakov return 1;
1702d7482ffeSIvan Shcherbakov }
1703d7482ffeSIvan Shcherbakov
1704d7482ffeSIvan Shcherbakov if (stepped_over_bp) {
1705d7482ffeSIvan Shcherbakov /* Temporarily disable the triggered breakpoint. */
1706d7482ffeSIvan Shcherbakov cpu_memory_rw_debug(cpu,
1707d7482ffeSIvan Shcherbakov stepped_over_bp->address,
1708d7482ffeSIvan Shcherbakov &stepped_over_bp->original_instruction,
1709d7482ffeSIvan Shcherbakov 1,
1710d7482ffeSIvan Shcherbakov true);
1711d7482ffeSIvan Shcherbakov }
1712d7482ffeSIvan Shcherbakov } else {
17131fc33bb9SClaudio Fontana cpu_exec_start(cpu);
1714d7482ffeSIvan Shcherbakov }
17151fc33bb9SClaudio Fontana
17161fc33bb9SClaudio Fontana do {
17179ad49538SPhilippe Mathieu-Daudé if (cpu->accel->dirty) {
17181fc33bb9SClaudio Fontana whpx_set_registers(cpu, WHPX_SET_RUNTIME_STATE);
17199ad49538SPhilippe Mathieu-Daudé cpu->accel->dirty = false;
17201fc33bb9SClaudio Fontana }
17211fc33bb9SClaudio Fontana
1722d7482ffeSIvan Shcherbakov if (exclusive_step_mode == WHPX_STEP_NONE) {
17231fc33bb9SClaudio Fontana whpx_vcpu_pre_run(cpu);
17241fc33bb9SClaudio Fontana
17251fc33bb9SClaudio Fontana if (qatomic_read(&cpu->exit_request)) {
17261fc33bb9SClaudio Fontana whpx_vcpu_kick(cpu);
17271fc33bb9SClaudio Fontana }
1728d7482ffeSIvan Shcherbakov }
1729d7482ffeSIvan Shcherbakov
1730d7482ffeSIvan Shcherbakov if (exclusive_step_mode != WHPX_STEP_NONE || cpu->singlestep_enabled) {
1731d7482ffeSIvan Shcherbakov whpx_vcpu_configure_single_stepping(cpu, true, NULL);
1732d7482ffeSIvan Shcherbakov }
17331fc33bb9SClaudio Fontana
17341fc33bb9SClaudio Fontana hr = whp_dispatch.WHvRunVirtualProcessor(
17351fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index,
17361fc33bb9SClaudio Fontana &vcpu->exit_ctx, sizeof(vcpu->exit_ctx));
17371fc33bb9SClaudio Fontana
17381fc33bb9SClaudio Fontana if (FAILED(hr)) {
17391fc33bb9SClaudio Fontana error_report("WHPX: Failed to exec a virtual processor,"
17401fc33bb9SClaudio Fontana " hr=%08lx", hr);
17411fc33bb9SClaudio Fontana ret = -1;
17421fc33bb9SClaudio Fontana break;
17431fc33bb9SClaudio Fontana }
17441fc33bb9SClaudio Fontana
1745d7482ffeSIvan Shcherbakov if (exclusive_step_mode != WHPX_STEP_NONE || cpu->singlestep_enabled) {
1746d7482ffeSIvan Shcherbakov whpx_vcpu_configure_single_stepping(cpu,
1747d7482ffeSIvan Shcherbakov false,
1748d7482ffeSIvan Shcherbakov &vcpu->exit_ctx.VpContext.Rflags);
1749d7482ffeSIvan Shcherbakov }
1750d7482ffeSIvan Shcherbakov
17511fc33bb9SClaudio Fontana whpx_vcpu_post_run(cpu);
17521fc33bb9SClaudio Fontana
17531fc33bb9SClaudio Fontana switch (vcpu->exit_ctx.ExitReason) {
17541fc33bb9SClaudio Fontana case WHvRunVpExitReasonMemoryAccess:
17551fc33bb9SClaudio Fontana ret = whpx_handle_mmio(cpu, &vcpu->exit_ctx.MemoryAccess);
17561fc33bb9SClaudio Fontana break;
17571fc33bb9SClaudio Fontana
17581fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64IoPortAccess:
17591fc33bb9SClaudio Fontana ret = whpx_handle_portio(cpu, &vcpu->exit_ctx.IoPortAccess);
17601fc33bb9SClaudio Fontana break;
17611fc33bb9SClaudio Fontana
17621fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64InterruptWindow:
17631fc33bb9SClaudio Fontana vcpu->ready_for_pic_interrupt = 1;
17641fc33bb9SClaudio Fontana vcpu->window_registered = 0;
17651fc33bb9SClaudio Fontana ret = 0;
17661fc33bb9SClaudio Fontana break;
17671fc33bb9SClaudio Fontana
17681fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64ApicEoi:
17691fc33bb9SClaudio Fontana assert(whpx_apic_in_platform());
17701fc33bb9SClaudio Fontana ioapic_eoi_broadcast(vcpu->exit_ctx.ApicEoi.InterruptVector);
17711fc33bb9SClaudio Fontana break;
17721fc33bb9SClaudio Fontana
17731fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64Halt:
1774d7482ffeSIvan Shcherbakov /*
1775d7482ffeSIvan Shcherbakov * WARNING: as of build 19043.1526 (21H1), this exit reason is no
1776d7482ffeSIvan Shcherbakov * longer used.
1777d7482ffeSIvan Shcherbakov */
17781fc33bb9SClaudio Fontana ret = whpx_handle_halt(cpu);
17791fc33bb9SClaudio Fontana break;
17801fc33bb9SClaudio Fontana
17811fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64ApicInitSipiTrap: {
17821fc33bb9SClaudio Fontana WHV_INTERRUPT_CONTROL ipi = {0};
17831fc33bb9SClaudio Fontana uint64_t icr = vcpu->exit_ctx.ApicInitSipi.ApicIcr;
17841fc33bb9SClaudio Fontana uint32_t delivery_mode =
17851fc33bb9SClaudio Fontana (icr & APIC_ICR_DELIV_MOD) >> APIC_ICR_DELIV_MOD_SHIFT;
17861fc33bb9SClaudio Fontana int dest_shorthand =
17871fc33bb9SClaudio Fontana (icr & APIC_ICR_DEST_SHORT) >> APIC_ICR_DEST_SHORT_SHIFT;
17881fc33bb9SClaudio Fontana bool broadcast = false;
17891fc33bb9SClaudio Fontana bool include_self = false;
17901fc33bb9SClaudio Fontana uint32_t i;
17911fc33bb9SClaudio Fontana
17921fc33bb9SClaudio Fontana /* We only registered for INIT and SIPI exits. */
17931fc33bb9SClaudio Fontana if ((delivery_mode != APIC_DM_INIT) &&
17941fc33bb9SClaudio Fontana (delivery_mode != APIC_DM_SIPI)) {
17951fc33bb9SClaudio Fontana error_report(
17961fc33bb9SClaudio Fontana "WHPX: Unexpected APIC exit that is not a INIT or SIPI");
17971fc33bb9SClaudio Fontana break;
17981fc33bb9SClaudio Fontana }
17991fc33bb9SClaudio Fontana
18001fc33bb9SClaudio Fontana if (delivery_mode == APIC_DM_INIT) {
18011fc33bb9SClaudio Fontana ipi.Type = WHvX64InterruptTypeInit;
18021fc33bb9SClaudio Fontana } else {
18031fc33bb9SClaudio Fontana ipi.Type = WHvX64InterruptTypeSipi;
18041fc33bb9SClaudio Fontana }
18051fc33bb9SClaudio Fontana
18061fc33bb9SClaudio Fontana ipi.DestinationMode =
18071fc33bb9SClaudio Fontana ((icr & APIC_ICR_DEST_MOD) >> APIC_ICR_DEST_MOD_SHIFT) ?
18081fc33bb9SClaudio Fontana WHvX64InterruptDestinationModeLogical :
18091fc33bb9SClaudio Fontana WHvX64InterruptDestinationModePhysical;
18101fc33bb9SClaudio Fontana
18111fc33bb9SClaudio Fontana ipi.TriggerMode =
18121fc33bb9SClaudio Fontana ((icr & APIC_ICR_TRIGGER_MOD) >> APIC_ICR_TRIGGER_MOD_SHIFT) ?
18131fc33bb9SClaudio Fontana WHvX64InterruptTriggerModeLevel :
18141fc33bb9SClaudio Fontana WHvX64InterruptTriggerModeEdge;
18151fc33bb9SClaudio Fontana
18161fc33bb9SClaudio Fontana ipi.Vector = icr & APIC_VECTOR_MASK;
18171fc33bb9SClaudio Fontana switch (dest_shorthand) {
18181fc33bb9SClaudio Fontana /* no shorthand. Bits 56-63 contain the destination. */
18191fc33bb9SClaudio Fontana case 0:
18201fc33bb9SClaudio Fontana ipi.Destination = (icr >> 56) & APIC_VECTOR_MASK;
18211fc33bb9SClaudio Fontana hr = whp_dispatch.WHvRequestInterrupt(whpx->partition,
18221fc33bb9SClaudio Fontana &ipi, sizeof(ipi));
18231fc33bb9SClaudio Fontana if (FAILED(hr)) {
18241fc33bb9SClaudio Fontana error_report("WHPX: Failed to request interrupt hr=%08lx",
18251fc33bb9SClaudio Fontana hr);
18261fc33bb9SClaudio Fontana }
18271fc33bb9SClaudio Fontana
18281fc33bb9SClaudio Fontana break;
18291fc33bb9SClaudio Fontana
18301fc33bb9SClaudio Fontana /* self */
18311fc33bb9SClaudio Fontana case 1:
18321fc33bb9SClaudio Fontana include_self = true;
18331fc33bb9SClaudio Fontana break;
18341fc33bb9SClaudio Fontana
18351fc33bb9SClaudio Fontana /* broadcast, including self */
18361fc33bb9SClaudio Fontana case 2:
18371fc33bb9SClaudio Fontana broadcast = true;
18381fc33bb9SClaudio Fontana include_self = true;
18391fc33bb9SClaudio Fontana break;
18401fc33bb9SClaudio Fontana
18411fc33bb9SClaudio Fontana /* broadcast, excluding self */
18421fc33bb9SClaudio Fontana case 3:
18431fc33bb9SClaudio Fontana broadcast = true;
18441fc33bb9SClaudio Fontana break;
18451fc33bb9SClaudio Fontana }
18461fc33bb9SClaudio Fontana
18471fc33bb9SClaudio Fontana if (!broadcast && !include_self) {
18481fc33bb9SClaudio Fontana break;
18491fc33bb9SClaudio Fontana }
18501fc33bb9SClaudio Fontana
18511fc33bb9SClaudio Fontana for (i = 0; i <= max_vcpu_index; i++) {
18521fc33bb9SClaudio Fontana if (i == cpu->cpu_index && !include_self) {
18531fc33bb9SClaudio Fontana continue;
18541fc33bb9SClaudio Fontana }
18551fc33bb9SClaudio Fontana
18561fc33bb9SClaudio Fontana /*
18571fc33bb9SClaudio Fontana * Assuming that APIC Ids are identity mapped since
18581fc33bb9SClaudio Fontana * WHvX64RegisterApicId & WHvX64RegisterInitialApicId registers
18591fc33bb9SClaudio Fontana * are not handled yet and the hypervisor doesn't allow the
18601fc33bb9SClaudio Fontana * guest to modify the APIC ID.
18611fc33bb9SClaudio Fontana */
18621fc33bb9SClaudio Fontana ipi.Destination = i;
18631fc33bb9SClaudio Fontana hr = whp_dispatch.WHvRequestInterrupt(whpx->partition,
18641fc33bb9SClaudio Fontana &ipi, sizeof(ipi));
18651fc33bb9SClaudio Fontana if (FAILED(hr)) {
18661fc33bb9SClaudio Fontana error_report(
18671fc33bb9SClaudio Fontana "WHPX: Failed to request SIPI for %d, hr=%08lx",
18681fc33bb9SClaudio Fontana i, hr);
18691fc33bb9SClaudio Fontana }
18701fc33bb9SClaudio Fontana }
18711fc33bb9SClaudio Fontana
18721fc33bb9SClaudio Fontana break;
18731fc33bb9SClaudio Fontana }
18741fc33bb9SClaudio Fontana
18751fc33bb9SClaudio Fontana case WHvRunVpExitReasonCanceled:
1876d7482ffeSIvan Shcherbakov if (exclusive_step_mode != WHPX_STEP_NONE) {
1877d7482ffeSIvan Shcherbakov /*
1878d7482ffeSIvan Shcherbakov * We are trying to step over a single instruction, and
1879d7482ffeSIvan Shcherbakov * likely got a request to stop from another thread.
1880d7482ffeSIvan Shcherbakov * Delay it until we are done stepping
1881d7482ffeSIvan Shcherbakov * over.
1882d7482ffeSIvan Shcherbakov */
1883d7482ffeSIvan Shcherbakov ret = 0;
1884d7482ffeSIvan Shcherbakov } else {
18851fc33bb9SClaudio Fontana cpu->exception_index = EXCP_INTERRUPT;
18861fc33bb9SClaudio Fontana ret = 1;
1887d7482ffeSIvan Shcherbakov }
18881fc33bb9SClaudio Fontana break;
18891fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64MsrAccess: {
18901fc33bb9SClaudio Fontana WHV_REGISTER_VALUE reg_values[3] = {0};
18911fc33bb9SClaudio Fontana WHV_REGISTER_NAME reg_names[3];
18921fc33bb9SClaudio Fontana UINT32 reg_count;
18931fc33bb9SClaudio Fontana
18941fc33bb9SClaudio Fontana reg_names[0] = WHvX64RegisterRip;
18951fc33bb9SClaudio Fontana reg_names[1] = WHvX64RegisterRax;
18961fc33bb9SClaudio Fontana reg_names[2] = WHvX64RegisterRdx;
18971fc33bb9SClaudio Fontana
18981fc33bb9SClaudio Fontana reg_values[0].Reg64 =
18991fc33bb9SClaudio Fontana vcpu->exit_ctx.VpContext.Rip +
19001fc33bb9SClaudio Fontana vcpu->exit_ctx.VpContext.InstructionLength;
19011fc33bb9SClaudio Fontana
19021fc33bb9SClaudio Fontana /*
19031fc33bb9SClaudio Fontana * For all unsupported MSR access we:
19041fc33bb9SClaudio Fontana * ignore writes
19051fc33bb9SClaudio Fontana * return 0 on read.
19061fc33bb9SClaudio Fontana */
19071fc33bb9SClaudio Fontana reg_count = vcpu->exit_ctx.MsrAccess.AccessInfo.IsWrite ?
19081fc33bb9SClaudio Fontana 1 : 3;
19091fc33bb9SClaudio Fontana
19101fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
19111fc33bb9SClaudio Fontana whpx->partition,
19121fc33bb9SClaudio Fontana cpu->cpu_index,
19131fc33bb9SClaudio Fontana reg_names, reg_count,
19141fc33bb9SClaudio Fontana reg_values);
19151fc33bb9SClaudio Fontana
19161fc33bb9SClaudio Fontana if (FAILED(hr)) {
19171fc33bb9SClaudio Fontana error_report("WHPX: Failed to set MsrAccess state "
19181fc33bb9SClaudio Fontana " registers, hr=%08lx", hr);
19191fc33bb9SClaudio Fontana }
19201fc33bb9SClaudio Fontana ret = 0;
19211fc33bb9SClaudio Fontana break;
19221fc33bb9SClaudio Fontana }
19231fc33bb9SClaudio Fontana case WHvRunVpExitReasonX64Cpuid: {
19241fc33bb9SClaudio Fontana WHV_REGISTER_VALUE reg_values[5];
19251fc33bb9SClaudio Fontana WHV_REGISTER_NAME reg_names[5];
19261fc33bb9SClaudio Fontana UINT32 reg_count = 5;
19271fc33bb9SClaudio Fontana UINT64 cpuid_fn, rip = 0, rax = 0, rcx = 0, rdx = 0, rbx = 0;
19281fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu);
19291fc33bb9SClaudio Fontana CPUX86State *env = &x86_cpu->env;
19301fc33bb9SClaudio Fontana
19311fc33bb9SClaudio Fontana memset(reg_values, 0, sizeof(reg_values));
19321fc33bb9SClaudio Fontana
19331fc33bb9SClaudio Fontana rip = vcpu->exit_ctx.VpContext.Rip +
19341fc33bb9SClaudio Fontana vcpu->exit_ctx.VpContext.InstructionLength;
19351fc33bb9SClaudio Fontana cpuid_fn = vcpu->exit_ctx.CpuidAccess.Rax;
19361fc33bb9SClaudio Fontana
19371fc33bb9SClaudio Fontana /*
19381fc33bb9SClaudio Fontana * Ideally, these should be supplied to the hypervisor during VCPU
19391fc33bb9SClaudio Fontana * initialization and it should be able to satisfy this request.
19401fc33bb9SClaudio Fontana * But, currently, WHPX doesn't support setting CPUID values in the
19411fc33bb9SClaudio Fontana * hypervisor once the partition has been setup, which is too late
19421fc33bb9SClaudio Fontana * since VCPUs are realized later. For now, use the values from
19431fc33bb9SClaudio Fontana * QEMU to satisfy these requests, until WHPX adds support for
19441fc33bb9SClaudio Fontana * being able to set these values in the hypervisor at runtime.
19451fc33bb9SClaudio Fontana */
19461fc33bb9SClaudio Fontana cpu_x86_cpuid(env, cpuid_fn, 0, (UINT32 *)&rax, (UINT32 *)&rbx,
19471fc33bb9SClaudio Fontana (UINT32 *)&rcx, (UINT32 *)&rdx);
19481fc33bb9SClaudio Fontana switch (cpuid_fn) {
19491fc33bb9SClaudio Fontana case 0x40000000:
19501fc33bb9SClaudio Fontana /* Expose the vmware cpu frequency cpuid leaf */
19511fc33bb9SClaudio Fontana rax = 0x40000010;
19521fc33bb9SClaudio Fontana rbx = rcx = rdx = 0;
19531fc33bb9SClaudio Fontana break;
19541fc33bb9SClaudio Fontana
19551fc33bb9SClaudio Fontana case 0x40000010:
19561fc33bb9SClaudio Fontana rax = env->tsc_khz;
19571fc33bb9SClaudio Fontana rbx = env->apic_bus_freq / 1000; /* Hz to KHz */
19581fc33bb9SClaudio Fontana rcx = rdx = 0;
19591fc33bb9SClaudio Fontana break;
19601fc33bb9SClaudio Fontana
19611fc33bb9SClaudio Fontana case 0x80000001:
19621fc33bb9SClaudio Fontana /* Remove any support of OSVW */
19631fc33bb9SClaudio Fontana rcx &= ~CPUID_EXT3_OSVW;
19641fc33bb9SClaudio Fontana break;
19651fc33bb9SClaudio Fontana }
19661fc33bb9SClaudio Fontana
19671fc33bb9SClaudio Fontana reg_names[0] = WHvX64RegisterRip;
19681fc33bb9SClaudio Fontana reg_names[1] = WHvX64RegisterRax;
19691fc33bb9SClaudio Fontana reg_names[2] = WHvX64RegisterRcx;
19701fc33bb9SClaudio Fontana reg_names[3] = WHvX64RegisterRdx;
19711fc33bb9SClaudio Fontana reg_names[4] = WHvX64RegisterRbx;
19721fc33bb9SClaudio Fontana
19731fc33bb9SClaudio Fontana reg_values[0].Reg64 = rip;
19741fc33bb9SClaudio Fontana reg_values[1].Reg64 = rax;
19751fc33bb9SClaudio Fontana reg_values[2].Reg64 = rcx;
19761fc33bb9SClaudio Fontana reg_values[3].Reg64 = rdx;
19771fc33bb9SClaudio Fontana reg_values[4].Reg64 = rbx;
19781fc33bb9SClaudio Fontana
19791fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
19801fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index,
19811fc33bb9SClaudio Fontana reg_names,
19821fc33bb9SClaudio Fontana reg_count,
19831fc33bb9SClaudio Fontana reg_values);
19841fc33bb9SClaudio Fontana
19851fc33bb9SClaudio Fontana if (FAILED(hr)) {
19861fc33bb9SClaudio Fontana error_report("WHPX: Failed to set CpuidAccess state registers,"
19871fc33bb9SClaudio Fontana " hr=%08lx", hr);
19881fc33bb9SClaudio Fontana }
19891fc33bb9SClaudio Fontana ret = 0;
19901fc33bb9SClaudio Fontana break;
19911fc33bb9SClaudio Fontana }
1992d7482ffeSIvan Shcherbakov case WHvRunVpExitReasonException:
1993d7482ffeSIvan Shcherbakov whpx_get_registers(cpu);
1994d7482ffeSIvan Shcherbakov
1995d7482ffeSIvan Shcherbakov if ((vcpu->exit_ctx.VpException.ExceptionType ==
1996d7482ffeSIvan Shcherbakov WHvX64ExceptionTypeDebugTrapOrFault) &&
1997d7482ffeSIvan Shcherbakov (vcpu->exit_ctx.VpException.InstructionByteCount >= 1) &&
1998d7482ffeSIvan Shcherbakov (vcpu->exit_ctx.VpException.InstructionBytes[0] ==
1999d7482ffeSIvan Shcherbakov whpx_breakpoint_instruction)) {
2000d7482ffeSIvan Shcherbakov /* Stopped at a software breakpoint. */
2001d7482ffeSIvan Shcherbakov cpu->exception_index = EXCP_DEBUG;
2002d7482ffeSIvan Shcherbakov } else if ((vcpu->exit_ctx.VpException.ExceptionType ==
2003d7482ffeSIvan Shcherbakov WHvX64ExceptionTypeDebugTrapOrFault) &&
2004d7482ffeSIvan Shcherbakov !cpu->singlestep_enabled) {
2005d7482ffeSIvan Shcherbakov /*
2006d7482ffeSIvan Shcherbakov * Just finished stepping over a breakpoint, but the
2007d7482ffeSIvan Shcherbakov * gdb does not expect us to do single-stepping.
2008d7482ffeSIvan Shcherbakov * Don't do anything special.
2009d7482ffeSIvan Shcherbakov */
2010d7482ffeSIvan Shcherbakov cpu->exception_index = EXCP_INTERRUPT;
2011d7482ffeSIvan Shcherbakov } else {
2012d7482ffeSIvan Shcherbakov /* Another exception or debug event. Report it to GDB. */
2013d7482ffeSIvan Shcherbakov cpu->exception_index = EXCP_DEBUG;
2014d7482ffeSIvan Shcherbakov }
2015d7482ffeSIvan Shcherbakov
2016d7482ffeSIvan Shcherbakov ret = 1;
2017d7482ffeSIvan Shcherbakov break;
20181fc33bb9SClaudio Fontana case WHvRunVpExitReasonNone:
20191fc33bb9SClaudio Fontana case WHvRunVpExitReasonUnrecoverableException:
20201fc33bb9SClaudio Fontana case WHvRunVpExitReasonInvalidVpRegisterValue:
20211fc33bb9SClaudio Fontana case WHvRunVpExitReasonUnsupportedFeature:
20221fc33bb9SClaudio Fontana default:
20231fc33bb9SClaudio Fontana error_report("WHPX: Unexpected VP exit code %d",
20241fc33bb9SClaudio Fontana vcpu->exit_ctx.ExitReason);
20251fc33bb9SClaudio Fontana whpx_get_registers(cpu);
2026195801d7SStefan Hajnoczi bql_lock();
20271fc33bb9SClaudio Fontana qemu_system_guest_panicked(cpu_get_crash_info(cpu));
2028195801d7SStefan Hajnoczi bql_unlock();
20291fc33bb9SClaudio Fontana break;
20301fc33bb9SClaudio Fontana }
20311fc33bb9SClaudio Fontana
20321fc33bb9SClaudio Fontana } while (!ret);
20331fc33bb9SClaudio Fontana
2034d7482ffeSIvan Shcherbakov if (stepped_over_bp) {
2035d7482ffeSIvan Shcherbakov /* Restore the breakpoint we stepped over */
2036d7482ffeSIvan Shcherbakov cpu_memory_rw_debug(cpu,
2037d7482ffeSIvan Shcherbakov stepped_over_bp->address,
2038d7482ffeSIvan Shcherbakov (void *)&whpx_breakpoint_instruction,
2039d7482ffeSIvan Shcherbakov 1,
2040d7482ffeSIvan Shcherbakov true);
2041d7482ffeSIvan Shcherbakov }
2042d7482ffeSIvan Shcherbakov
2043d7482ffeSIvan Shcherbakov if (exclusive_step_mode != WHPX_STEP_NONE) {
2044d7482ffeSIvan Shcherbakov g_assert(cpu_in_exclusive_context(cpu));
2045d7482ffeSIvan Shcherbakov cpu->running = false;
2046d7482ffeSIvan Shcherbakov end_exclusive();
2047d7482ffeSIvan Shcherbakov
2048d7482ffeSIvan Shcherbakov exclusive_step_mode = WHPX_STEP_NONE;
2049d7482ffeSIvan Shcherbakov } else {
20501fc33bb9SClaudio Fontana cpu_exec_end(cpu);
2051d7482ffeSIvan Shcherbakov }
2052d7482ffeSIvan Shcherbakov
2053195801d7SStefan Hajnoczi bql_lock();
20541fc33bb9SClaudio Fontana current_cpu = cpu;
20551fc33bb9SClaudio Fontana
2056d7482ffeSIvan Shcherbakov if (--whpx->running_cpus == 0) {
2057d7482ffeSIvan Shcherbakov whpx_last_vcpu_stopping(cpu);
2058d7482ffeSIvan Shcherbakov }
2059d7482ffeSIvan Shcherbakov
20601fc33bb9SClaudio Fontana qatomic_set(&cpu->exit_request, false);
20611fc33bb9SClaudio Fontana
20621fc33bb9SClaudio Fontana return ret < 0;
20631fc33bb9SClaudio Fontana }
20641fc33bb9SClaudio Fontana
do_whpx_cpu_synchronize_state(CPUState * cpu,run_on_cpu_data arg)20651fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
20661fc33bb9SClaudio Fontana {
20679ad49538SPhilippe Mathieu-Daudé if (!cpu->accel->dirty) {
20681fc33bb9SClaudio Fontana whpx_get_registers(cpu);
20699ad49538SPhilippe Mathieu-Daudé cpu->accel->dirty = true;
20701fc33bb9SClaudio Fontana }
20711fc33bb9SClaudio Fontana }
20721fc33bb9SClaudio Fontana
do_whpx_cpu_synchronize_post_reset(CPUState * cpu,run_on_cpu_data arg)20731fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu,
20741fc33bb9SClaudio Fontana run_on_cpu_data arg)
20751fc33bb9SClaudio Fontana {
20761fc33bb9SClaudio Fontana whpx_set_registers(cpu, WHPX_SET_RESET_STATE);
20779ad49538SPhilippe Mathieu-Daudé cpu->accel->dirty = false;
20781fc33bb9SClaudio Fontana }
20791fc33bb9SClaudio Fontana
do_whpx_cpu_synchronize_post_init(CPUState * cpu,run_on_cpu_data arg)20801fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,
20811fc33bb9SClaudio Fontana run_on_cpu_data arg)
20821fc33bb9SClaudio Fontana {
20831fc33bb9SClaudio Fontana whpx_set_registers(cpu, WHPX_SET_FULL_STATE);
20849ad49538SPhilippe Mathieu-Daudé cpu->accel->dirty = false;
20851fc33bb9SClaudio Fontana }
20861fc33bb9SClaudio Fontana
do_whpx_cpu_synchronize_pre_loadvm(CPUState * cpu,run_on_cpu_data arg)20871fc33bb9SClaudio Fontana static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu,
20881fc33bb9SClaudio Fontana run_on_cpu_data arg)
20891fc33bb9SClaudio Fontana {
20909ad49538SPhilippe Mathieu-Daudé cpu->accel->dirty = true;
20911fc33bb9SClaudio Fontana }
20921fc33bb9SClaudio Fontana
20931fc33bb9SClaudio Fontana /*
20941fc33bb9SClaudio Fontana * CPU support.
20951fc33bb9SClaudio Fontana */
20961fc33bb9SClaudio Fontana
whpx_cpu_synchronize_state(CPUState * cpu)20971fc33bb9SClaudio Fontana void whpx_cpu_synchronize_state(CPUState *cpu)
20981fc33bb9SClaudio Fontana {
20999ad49538SPhilippe Mathieu-Daudé if (!cpu->accel->dirty) {
21001fc33bb9SClaudio Fontana run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL);
21011fc33bb9SClaudio Fontana }
21021fc33bb9SClaudio Fontana }
21031fc33bb9SClaudio Fontana
whpx_cpu_synchronize_post_reset(CPUState * cpu)21041fc33bb9SClaudio Fontana void whpx_cpu_synchronize_post_reset(CPUState *cpu)
21051fc33bb9SClaudio Fontana {
21061fc33bb9SClaudio Fontana run_on_cpu(cpu, do_whpx_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);
21071fc33bb9SClaudio Fontana }
21081fc33bb9SClaudio Fontana
whpx_cpu_synchronize_post_init(CPUState * cpu)21091fc33bb9SClaudio Fontana void whpx_cpu_synchronize_post_init(CPUState *cpu)
21101fc33bb9SClaudio Fontana {
21111fc33bb9SClaudio Fontana run_on_cpu(cpu, do_whpx_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
21121fc33bb9SClaudio Fontana }
21131fc33bb9SClaudio Fontana
whpx_cpu_synchronize_pre_loadvm(CPUState * cpu)21141fc33bb9SClaudio Fontana void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)
21151fc33bb9SClaudio Fontana {
21161fc33bb9SClaudio Fontana run_on_cpu(cpu, do_whpx_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);
21171fc33bb9SClaudio Fontana }
21181fc33bb9SClaudio Fontana
whpx_cpu_synchronize_pre_resume(bool step_pending)2119d7482ffeSIvan Shcherbakov void whpx_cpu_synchronize_pre_resume(bool step_pending)
2120d7482ffeSIvan Shcherbakov {
2121d7482ffeSIvan Shcherbakov whpx_global.step_pending = step_pending;
2122d7482ffeSIvan Shcherbakov }
2123d7482ffeSIvan Shcherbakov
21241fc33bb9SClaudio Fontana /*
21251fc33bb9SClaudio Fontana * Vcpu support.
21261fc33bb9SClaudio Fontana */
21271fc33bb9SClaudio Fontana
21281fc33bb9SClaudio Fontana static Error *whpx_migration_blocker;
21291fc33bb9SClaudio Fontana
whpx_cpu_update_state(void * opaque,bool running,RunState state)2130538f0497SPhilippe Mathieu-Daudé static void whpx_cpu_update_state(void *opaque, bool running, RunState state)
21311fc33bb9SClaudio Fontana {
21321fc33bb9SClaudio Fontana CPUX86State *env = opaque;
21331fc33bb9SClaudio Fontana
21341fc33bb9SClaudio Fontana if (running) {
21351fc33bb9SClaudio Fontana env->tsc_valid = false;
21361fc33bb9SClaudio Fontana }
21371fc33bb9SClaudio Fontana }
21381fc33bb9SClaudio Fontana
whpx_init_vcpu(CPUState * cpu)21391fc33bb9SClaudio Fontana int whpx_init_vcpu(CPUState *cpu)
21401fc33bb9SClaudio Fontana {
21411fc33bb9SClaudio Fontana HRESULT hr;
21421fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
2143b4f879a4SPhilippe Mathieu-Daudé AccelCPUState *vcpu = NULL;
21441fc33bb9SClaudio Fontana Error *local_error = NULL;
21451fc33bb9SClaudio Fontana X86CPU *x86_cpu = X86_CPU(cpu);
2146b77af26eSRichard Henderson CPUX86State *env = &x86_cpu->env;
21471fc33bb9SClaudio Fontana UINT64 freq = 0;
21481fc33bb9SClaudio Fontana int ret;
21491fc33bb9SClaudio Fontana
21501fc33bb9SClaudio Fontana /* Add migration blockers for all unsupported features of the
21511fc33bb9SClaudio Fontana * Windows Hypervisor Platform
21521fc33bb9SClaudio Fontana */
21531fc33bb9SClaudio Fontana if (whpx_migration_blocker == NULL) {
21541fc33bb9SClaudio Fontana error_setg(&whpx_migration_blocker,
21551fc33bb9SClaudio Fontana "State blocked due to non-migratable CPUID feature support,"
21561fc33bb9SClaudio Fontana "dirty memory tracking support, and XSAVE/XRSTOR support");
21571fc33bb9SClaudio Fontana
2158c8a7fc51SSteve Sistare if (migrate_add_blocker(&whpx_migration_blocker, &local_error) < 0) {
21591fc33bb9SClaudio Fontana error_report_err(local_error);
21601fc33bb9SClaudio Fontana ret = -EINVAL;
21611fc33bb9SClaudio Fontana goto error;
21621fc33bb9SClaudio Fontana }
21631fc33bb9SClaudio Fontana }
21641fc33bb9SClaudio Fontana
2165b4f879a4SPhilippe Mathieu-Daudé vcpu = g_new0(AccelCPUState, 1);
21661fc33bb9SClaudio Fontana
21671fc33bb9SClaudio Fontana hr = whp_dispatch.WHvEmulatorCreateEmulator(
21681fc33bb9SClaudio Fontana &whpx_emu_callbacks,
21691fc33bb9SClaudio Fontana &vcpu->emulator);
21701fc33bb9SClaudio Fontana if (FAILED(hr)) {
21711fc33bb9SClaudio Fontana error_report("WHPX: Failed to setup instruction completion support,"
21721fc33bb9SClaudio Fontana " hr=%08lx", hr);
21731fc33bb9SClaudio Fontana ret = -EINVAL;
21741fc33bb9SClaudio Fontana goto error;
21751fc33bb9SClaudio Fontana }
21761fc33bb9SClaudio Fontana
21771fc33bb9SClaudio Fontana hr = whp_dispatch.WHvCreateVirtualProcessor(
21781fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 0);
21791fc33bb9SClaudio Fontana if (FAILED(hr)) {
21801fc33bb9SClaudio Fontana error_report("WHPX: Failed to create a virtual processor,"
21811fc33bb9SClaudio Fontana " hr=%08lx", hr);
21821fc33bb9SClaudio Fontana whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
21831fc33bb9SClaudio Fontana ret = -EINVAL;
21841fc33bb9SClaudio Fontana goto error;
21851fc33bb9SClaudio Fontana }
21861fc33bb9SClaudio Fontana
21871fc33bb9SClaudio Fontana /*
21881fc33bb9SClaudio Fontana * vcpu's TSC frequency is either specified by user, or use the value
21891fc33bb9SClaudio Fontana * provided by Hyper-V if the former is not present. In the latter case, we
21901fc33bb9SClaudio Fontana * query it from Hyper-V and record in env->tsc_khz, so that vcpu's TSC
21911fc33bb9SClaudio Fontana * frequency can be migrated later via this field.
21921fc33bb9SClaudio Fontana */
21931fc33bb9SClaudio Fontana if (!env->tsc_khz) {
21941fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetCapability(
21951fc33bb9SClaudio Fontana WHvCapabilityCodeProcessorClockFrequency, &freq, sizeof(freq),
21961fc33bb9SClaudio Fontana NULL);
21971fc33bb9SClaudio Fontana if (hr != WHV_E_UNKNOWN_CAPABILITY) {
21981fc33bb9SClaudio Fontana if (FAILED(hr)) {
21991fc33bb9SClaudio Fontana printf("WHPX: Failed to query tsc frequency, hr=0x%08lx\n", hr);
22001fc33bb9SClaudio Fontana } else {
22011fc33bb9SClaudio Fontana env->tsc_khz = freq / 1000; /* Hz to KHz */
22021fc33bb9SClaudio Fontana }
22031fc33bb9SClaudio Fontana }
22041fc33bb9SClaudio Fontana }
22051fc33bb9SClaudio Fontana
22061fc33bb9SClaudio Fontana env->apic_bus_freq = HYPERV_APIC_BUS_FREQUENCY;
22071fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetCapability(
22081fc33bb9SClaudio Fontana WHvCapabilityCodeInterruptClockFrequency, &freq, sizeof(freq), NULL);
22091fc33bb9SClaudio Fontana if (hr != WHV_E_UNKNOWN_CAPABILITY) {
22101fc33bb9SClaudio Fontana if (FAILED(hr)) {
22111fc33bb9SClaudio Fontana printf("WHPX: Failed to query apic bus frequency hr=0x%08lx\n", hr);
22121fc33bb9SClaudio Fontana } else {
22131fc33bb9SClaudio Fontana env->apic_bus_freq = freq;
22141fc33bb9SClaudio Fontana }
22151fc33bb9SClaudio Fontana }
22161fc33bb9SClaudio Fontana
22171fc33bb9SClaudio Fontana /*
22181fc33bb9SClaudio Fontana * If the vmware cpuid frequency leaf option is set, and we have a valid
22191fc33bb9SClaudio Fontana * tsc value, trap the corresponding cpuid's.
22201fc33bb9SClaudio Fontana */
22211fc33bb9SClaudio Fontana if (x86_cpu->vmware_cpuid_freq && env->tsc_khz) {
22221fc33bb9SClaudio Fontana UINT32 cpuidExitList[] = {1, 0x80000001, 0x40000000, 0x40000010};
22231fc33bb9SClaudio Fontana
22241fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetPartitionProperty(
22251fc33bb9SClaudio Fontana whpx->partition,
22261fc33bb9SClaudio Fontana WHvPartitionPropertyCodeCpuidExitList,
22271fc33bb9SClaudio Fontana cpuidExitList,
22281fc33bb9SClaudio Fontana RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32));
22291fc33bb9SClaudio Fontana
22301fc33bb9SClaudio Fontana if (FAILED(hr)) {
22311fc33bb9SClaudio Fontana error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx",
22321fc33bb9SClaudio Fontana hr);
22331fc33bb9SClaudio Fontana ret = -EINVAL;
22341fc33bb9SClaudio Fontana goto error;
22351fc33bb9SClaudio Fontana }
22361fc33bb9SClaudio Fontana }
22371fc33bb9SClaudio Fontana
22381fc33bb9SClaudio Fontana vcpu->interruptable = true;
2239*083367dbSPhilippe Mathieu-Daudé vcpu->dirty = true;
2240f861b3f3SPhilippe Mathieu-Daudé cpu->accel = vcpu;
22411fc33bb9SClaudio Fontana max_vcpu_index = max(max_vcpu_index, cpu->cpu_index);
2242b77af26eSRichard Henderson qemu_add_vm_change_state_handler(whpx_cpu_update_state, env);
22431fc33bb9SClaudio Fontana
22441fc33bb9SClaudio Fontana return 0;
22451fc33bb9SClaudio Fontana
22461fc33bb9SClaudio Fontana error:
22471fc33bb9SClaudio Fontana g_free(vcpu);
22481fc33bb9SClaudio Fontana
22491fc33bb9SClaudio Fontana return ret;
22501fc33bb9SClaudio Fontana }
22511fc33bb9SClaudio Fontana
whpx_vcpu_exec(CPUState * cpu)22521fc33bb9SClaudio Fontana int whpx_vcpu_exec(CPUState *cpu)
22531fc33bb9SClaudio Fontana {
22541fc33bb9SClaudio Fontana int ret;
22551fc33bb9SClaudio Fontana int fatal;
22561fc33bb9SClaudio Fontana
22571fc33bb9SClaudio Fontana for (;;) {
22581fc33bb9SClaudio Fontana if (cpu->exception_index >= EXCP_INTERRUPT) {
22591fc33bb9SClaudio Fontana ret = cpu->exception_index;
22601fc33bb9SClaudio Fontana cpu->exception_index = -1;
22611fc33bb9SClaudio Fontana break;
22621fc33bb9SClaudio Fontana }
22631fc33bb9SClaudio Fontana
22641fc33bb9SClaudio Fontana fatal = whpx_vcpu_run(cpu);
22651fc33bb9SClaudio Fontana
22661fc33bb9SClaudio Fontana if (fatal) {
22671fc33bb9SClaudio Fontana error_report("WHPX: Failed to exec a virtual processor");
22681fc33bb9SClaudio Fontana abort();
22691fc33bb9SClaudio Fontana }
22701fc33bb9SClaudio Fontana }
22711fc33bb9SClaudio Fontana
22721fc33bb9SClaudio Fontana return ret;
22731fc33bb9SClaudio Fontana }
22741fc33bb9SClaudio Fontana
whpx_destroy_vcpu(CPUState * cpu)22751fc33bb9SClaudio Fontana void whpx_destroy_vcpu(CPUState *cpu)
22761fc33bb9SClaudio Fontana {
22771fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
2278441f2449SPhilippe Mathieu-Daudé AccelCPUState *vcpu = cpu->accel;
22791fc33bb9SClaudio Fontana
22801fc33bb9SClaudio Fontana whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
22811fc33bb9SClaudio Fontana whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
22826ecd2cd0SPhilippe Mathieu-Daudé g_free(cpu->accel);
22831fc33bb9SClaudio Fontana return;
22841fc33bb9SClaudio Fontana }
22851fc33bb9SClaudio Fontana
whpx_vcpu_kick(CPUState * cpu)22861fc33bb9SClaudio Fontana void whpx_vcpu_kick(CPUState *cpu)
22871fc33bb9SClaudio Fontana {
22881fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
22891fc33bb9SClaudio Fontana whp_dispatch.WHvCancelRunVirtualProcessor(
22901fc33bb9SClaudio Fontana whpx->partition, cpu->cpu_index, 0);
22911fc33bb9SClaudio Fontana }
22921fc33bb9SClaudio Fontana
22931fc33bb9SClaudio Fontana /*
22941fc33bb9SClaudio Fontana * Memory support.
22951fc33bb9SClaudio Fontana */
22961fc33bb9SClaudio Fontana
whpx_update_mapping(hwaddr start_pa,ram_addr_t size,void * host_va,int add,int rom,const char * name)22971fc33bb9SClaudio Fontana static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size,
22981fc33bb9SClaudio Fontana void *host_va, int add, int rom,
22991fc33bb9SClaudio Fontana const char *name)
23001fc33bb9SClaudio Fontana {
23011fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
23021fc33bb9SClaudio Fontana HRESULT hr;
23031fc33bb9SClaudio Fontana
23041fc33bb9SClaudio Fontana /*
23051fc33bb9SClaudio Fontana if (add) {
23061fc33bb9SClaudio Fontana printf("WHPX: ADD PA:%p Size:%p, Host:%p, %s, '%s'\n",
23071fc33bb9SClaudio Fontana (void*)start_pa, (void*)size, host_va,
23081fc33bb9SClaudio Fontana (rom ? "ROM" : "RAM"), name);
23091fc33bb9SClaudio Fontana } else {
23101fc33bb9SClaudio Fontana printf("WHPX: DEL PA:%p Size:%p, Host:%p, '%s'\n",
23111fc33bb9SClaudio Fontana (void*)start_pa, (void*)size, host_va, name);
23121fc33bb9SClaudio Fontana }
23131fc33bb9SClaudio Fontana */
23141fc33bb9SClaudio Fontana
23151fc33bb9SClaudio Fontana if (add) {
23161fc33bb9SClaudio Fontana hr = whp_dispatch.WHvMapGpaRange(whpx->partition,
23171fc33bb9SClaudio Fontana host_va,
23181fc33bb9SClaudio Fontana start_pa,
23191fc33bb9SClaudio Fontana size,
23201fc33bb9SClaudio Fontana (WHvMapGpaRangeFlagRead |
23211fc33bb9SClaudio Fontana WHvMapGpaRangeFlagExecute |
23221fc33bb9SClaudio Fontana (rom ? 0 : WHvMapGpaRangeFlagWrite)));
23231fc33bb9SClaudio Fontana } else {
23241fc33bb9SClaudio Fontana hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
23251fc33bb9SClaudio Fontana start_pa,
23261fc33bb9SClaudio Fontana size);
23271fc33bb9SClaudio Fontana }
23281fc33bb9SClaudio Fontana
23291fc33bb9SClaudio Fontana if (FAILED(hr)) {
23301fc33bb9SClaudio Fontana error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes,"
23311fc33bb9SClaudio Fontana " Host:%p, hr=%08lx",
23321fc33bb9SClaudio Fontana (add ? "MAP" : "UNMAP"), name,
23331fc33bb9SClaudio Fontana (void *)(uintptr_t)start_pa, (void *)size, host_va, hr);
23341fc33bb9SClaudio Fontana }
23351fc33bb9SClaudio Fontana }
23361fc33bb9SClaudio Fontana
whpx_process_section(MemoryRegionSection * section,int add)23371fc33bb9SClaudio Fontana static void whpx_process_section(MemoryRegionSection *section, int add)
23381fc33bb9SClaudio Fontana {
23391fc33bb9SClaudio Fontana MemoryRegion *mr = section->mr;
23401fc33bb9SClaudio Fontana hwaddr start_pa = section->offset_within_address_space;
23411fc33bb9SClaudio Fontana ram_addr_t size = int128_get64(section->size);
23421fc33bb9SClaudio Fontana unsigned int delta;
23431fc33bb9SClaudio Fontana uint64_t host_va;
23441fc33bb9SClaudio Fontana
23451fc33bb9SClaudio Fontana if (!memory_region_is_ram(mr)) {
23461fc33bb9SClaudio Fontana return;
23471fc33bb9SClaudio Fontana }
23481fc33bb9SClaudio Fontana
23498e3b0cbbSMarc-André Lureau delta = qemu_real_host_page_size() - (start_pa & ~qemu_real_host_page_mask());
23508e3b0cbbSMarc-André Lureau delta &= ~qemu_real_host_page_mask();
23511fc33bb9SClaudio Fontana if (delta > size) {
23521fc33bb9SClaudio Fontana return;
23531fc33bb9SClaudio Fontana }
23541fc33bb9SClaudio Fontana start_pa += delta;
23551fc33bb9SClaudio Fontana size -= delta;
23568e3b0cbbSMarc-André Lureau size &= qemu_real_host_page_mask();
23578e3b0cbbSMarc-André Lureau if (!size || (start_pa & ~qemu_real_host_page_mask())) {
23581fc33bb9SClaudio Fontana return;
23591fc33bb9SClaudio Fontana }
23601fc33bb9SClaudio Fontana
23611fc33bb9SClaudio Fontana host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
23621fc33bb9SClaudio Fontana + section->offset_within_region + delta;
23631fc33bb9SClaudio Fontana
23641fc33bb9SClaudio Fontana whpx_update_mapping(start_pa, size, (void *)(uintptr_t)host_va, add,
23651fc33bb9SClaudio Fontana memory_region_is_rom(mr), mr->name);
23661fc33bb9SClaudio Fontana }
23671fc33bb9SClaudio Fontana
whpx_region_add(MemoryListener * listener,MemoryRegionSection * section)23681fc33bb9SClaudio Fontana static void whpx_region_add(MemoryListener *listener,
23691fc33bb9SClaudio Fontana MemoryRegionSection *section)
23701fc33bb9SClaudio Fontana {
23711fc33bb9SClaudio Fontana memory_region_ref(section->mr);
23721fc33bb9SClaudio Fontana whpx_process_section(section, 1);
23731fc33bb9SClaudio Fontana }
23741fc33bb9SClaudio Fontana
whpx_region_del(MemoryListener * listener,MemoryRegionSection * section)23751fc33bb9SClaudio Fontana static void whpx_region_del(MemoryListener *listener,
23761fc33bb9SClaudio Fontana MemoryRegionSection *section)
23771fc33bb9SClaudio Fontana {
23781fc33bb9SClaudio Fontana whpx_process_section(section, 0);
23791fc33bb9SClaudio Fontana memory_region_unref(section->mr);
23801fc33bb9SClaudio Fontana }
23811fc33bb9SClaudio Fontana
whpx_transaction_begin(MemoryListener * listener)23821fc33bb9SClaudio Fontana static void whpx_transaction_begin(MemoryListener *listener)
23831fc33bb9SClaudio Fontana {
23841fc33bb9SClaudio Fontana }
23851fc33bb9SClaudio Fontana
whpx_transaction_commit(MemoryListener * listener)23861fc33bb9SClaudio Fontana static void whpx_transaction_commit(MemoryListener *listener)
23871fc33bb9SClaudio Fontana {
23881fc33bb9SClaudio Fontana }
23891fc33bb9SClaudio Fontana
whpx_log_sync(MemoryListener * listener,MemoryRegionSection * section)23901fc33bb9SClaudio Fontana static void whpx_log_sync(MemoryListener *listener,
23911fc33bb9SClaudio Fontana MemoryRegionSection *section)
23921fc33bb9SClaudio Fontana {
23931fc33bb9SClaudio Fontana MemoryRegion *mr = section->mr;
23941fc33bb9SClaudio Fontana
23951fc33bb9SClaudio Fontana if (!memory_region_is_ram(mr)) {
23961fc33bb9SClaudio Fontana return;
23971fc33bb9SClaudio Fontana }
23981fc33bb9SClaudio Fontana
23991fc33bb9SClaudio Fontana memory_region_set_dirty(mr, 0, int128_get64(section->size));
24001fc33bb9SClaudio Fontana }
24011fc33bb9SClaudio Fontana
24021fc33bb9SClaudio Fontana static MemoryListener whpx_memory_listener = {
2403142518bdSPeter Xu .name = "whpx",
24041fc33bb9SClaudio Fontana .begin = whpx_transaction_begin,
24051fc33bb9SClaudio Fontana .commit = whpx_transaction_commit,
24061fc33bb9SClaudio Fontana .region_add = whpx_region_add,
24071fc33bb9SClaudio Fontana .region_del = whpx_region_del,
24081fc33bb9SClaudio Fontana .log_sync = whpx_log_sync,
24095369a36cSIsaku Yamahata .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
24101fc33bb9SClaudio Fontana };
24111fc33bb9SClaudio Fontana
whpx_memory_init(void)24121fc33bb9SClaudio Fontana static void whpx_memory_init(void)
24131fc33bb9SClaudio Fontana {
24141fc33bb9SClaudio Fontana memory_listener_register(&whpx_memory_listener, &address_space_memory);
24151fc33bb9SClaudio Fontana }
24161fc33bb9SClaudio Fontana
24171fc33bb9SClaudio Fontana /*
24181fc33bb9SClaudio Fontana * Load the functions from the given library, using the given handle. If a
24191fc33bb9SClaudio Fontana * handle is provided, it is used, otherwise the library is opened. The
24201fc33bb9SClaudio Fontana * handle will be updated on return with the opened one.
24211fc33bb9SClaudio Fontana */
load_whp_dispatch_fns(HMODULE * handle,WHPFunctionList function_list)24221fc33bb9SClaudio Fontana static bool load_whp_dispatch_fns(HMODULE *handle,
24231fc33bb9SClaudio Fontana WHPFunctionList function_list)
24241fc33bb9SClaudio Fontana {
24251fc33bb9SClaudio Fontana HMODULE hLib = *handle;
24261fc33bb9SClaudio Fontana
24271fc33bb9SClaudio Fontana #define WINHV_PLATFORM_DLL "WinHvPlatform.dll"
24281fc33bb9SClaudio Fontana #define WINHV_EMULATION_DLL "WinHvEmulation.dll"
24291fc33bb9SClaudio Fontana #define WHP_LOAD_FIELD_OPTIONAL(return_type, function_name, signature) \
24301fc33bb9SClaudio Fontana whp_dispatch.function_name = \
24311fc33bb9SClaudio Fontana (function_name ## _t)GetProcAddress(hLib, #function_name); \
24321fc33bb9SClaudio Fontana
24331fc33bb9SClaudio Fontana #define WHP_LOAD_FIELD(return_type, function_name, signature) \
24341fc33bb9SClaudio Fontana whp_dispatch.function_name = \
24351fc33bb9SClaudio Fontana (function_name ## _t)GetProcAddress(hLib, #function_name); \
24361fc33bb9SClaudio Fontana if (!whp_dispatch.function_name) { \
24371fc33bb9SClaudio Fontana error_report("Could not load function %s", #function_name); \
24381fc33bb9SClaudio Fontana goto error; \
24391fc33bb9SClaudio Fontana } \
24401fc33bb9SClaudio Fontana
24411fc33bb9SClaudio Fontana #define WHP_LOAD_LIB(lib_name, handle_lib) \
24421fc33bb9SClaudio Fontana if (!handle_lib) { \
24431fc33bb9SClaudio Fontana handle_lib = LoadLibrary(lib_name); \
24441fc33bb9SClaudio Fontana if (!handle_lib) { \
24451fc33bb9SClaudio Fontana error_report("Could not load library %s.", lib_name); \
24461fc33bb9SClaudio Fontana goto error; \
24471fc33bb9SClaudio Fontana } \
24481fc33bb9SClaudio Fontana } \
24491fc33bb9SClaudio Fontana
24501fc33bb9SClaudio Fontana switch (function_list) {
24511fc33bb9SClaudio Fontana case WINHV_PLATFORM_FNS_DEFAULT:
24521fc33bb9SClaudio Fontana WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
24531fc33bb9SClaudio Fontana LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
24541fc33bb9SClaudio Fontana break;
24551fc33bb9SClaudio Fontana
24561fc33bb9SClaudio Fontana case WINHV_EMULATION_FNS_DEFAULT:
24571fc33bb9SClaudio Fontana WHP_LOAD_LIB(WINHV_EMULATION_DLL, hLib)
24581fc33bb9SClaudio Fontana LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
24591fc33bb9SClaudio Fontana break;
24601fc33bb9SClaudio Fontana
24611fc33bb9SClaudio Fontana case WINHV_PLATFORM_FNS_SUPPLEMENTAL:
24621fc33bb9SClaudio Fontana WHP_LOAD_LIB(WINHV_PLATFORM_DLL, hLib)
24631fc33bb9SClaudio Fontana LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL(WHP_LOAD_FIELD_OPTIONAL)
24641fc33bb9SClaudio Fontana break;
24651fc33bb9SClaudio Fontana }
24661fc33bb9SClaudio Fontana
24671fc33bb9SClaudio Fontana *handle = hLib;
24681fc33bb9SClaudio Fontana return true;
24691fc33bb9SClaudio Fontana
24701fc33bb9SClaudio Fontana error:
24711fc33bb9SClaudio Fontana if (hLib) {
24721fc33bb9SClaudio Fontana FreeLibrary(hLib);
24731fc33bb9SClaudio Fontana }
24741fc33bb9SClaudio Fontana
24751fc33bb9SClaudio Fontana return false;
24761fc33bb9SClaudio Fontana }
24771fc33bb9SClaudio Fontana
whpx_set_kernel_irqchip(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)24781fc33bb9SClaudio Fontana static void whpx_set_kernel_irqchip(Object *obj, Visitor *v,
24791fc33bb9SClaudio Fontana const char *name, void *opaque,
24801fc33bb9SClaudio Fontana Error **errp)
24811fc33bb9SClaudio Fontana {
24821fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
24831fc33bb9SClaudio Fontana OnOffSplit mode;
24841fc33bb9SClaudio Fontana
24851fc33bb9SClaudio Fontana if (!visit_type_OnOffSplit(v, name, &mode, errp)) {
24861fc33bb9SClaudio Fontana return;
24871fc33bb9SClaudio Fontana }
24881fc33bb9SClaudio Fontana
24891fc33bb9SClaudio Fontana switch (mode) {
24901fc33bb9SClaudio Fontana case ON_OFF_SPLIT_ON:
24911fc33bb9SClaudio Fontana whpx->kernel_irqchip_allowed = true;
24921fc33bb9SClaudio Fontana whpx->kernel_irqchip_required = true;
24931fc33bb9SClaudio Fontana break;
24941fc33bb9SClaudio Fontana
24951fc33bb9SClaudio Fontana case ON_OFF_SPLIT_OFF:
24961fc33bb9SClaudio Fontana whpx->kernel_irqchip_allowed = false;
24971fc33bb9SClaudio Fontana whpx->kernel_irqchip_required = false;
24981fc33bb9SClaudio Fontana break;
24991fc33bb9SClaudio Fontana
25001fc33bb9SClaudio Fontana case ON_OFF_SPLIT_SPLIT:
25011fc33bb9SClaudio Fontana error_setg(errp, "WHPX: split irqchip currently not supported");
25021fc33bb9SClaudio Fontana error_append_hint(errp,
25031fc33bb9SClaudio Fontana "Try without kernel-irqchip or with kernel-irqchip=on|off");
25041fc33bb9SClaudio Fontana break;
25051fc33bb9SClaudio Fontana
25061fc33bb9SClaudio Fontana default:
25071fc33bb9SClaudio Fontana /*
25081fc33bb9SClaudio Fontana * The value was checked in visit_type_OnOffSplit() above. If
25091fc33bb9SClaudio Fontana * we get here, then something is wrong in QEMU.
25101fc33bb9SClaudio Fontana */
25111fc33bb9SClaudio Fontana abort();
25121fc33bb9SClaudio Fontana }
25131fc33bb9SClaudio Fontana }
25141fc33bb9SClaudio Fontana
25151fc33bb9SClaudio Fontana /*
25161fc33bb9SClaudio Fontana * Partition support
25171fc33bb9SClaudio Fontana */
25181fc33bb9SClaudio Fontana
whpx_accel_init(MachineState * ms)25191fc33bb9SClaudio Fontana static int whpx_accel_init(MachineState *ms)
25201fc33bb9SClaudio Fontana {
25211fc33bb9SClaudio Fontana struct whpx_state *whpx;
25221fc33bb9SClaudio Fontana int ret;
25231fc33bb9SClaudio Fontana HRESULT hr;
25241fc33bb9SClaudio Fontana WHV_CAPABILITY whpx_cap;
25251fc33bb9SClaudio Fontana UINT32 whpx_cap_size;
25261fc33bb9SClaudio Fontana WHV_PARTITION_PROPERTY prop;
25271fc33bb9SClaudio Fontana UINT32 cpuidExitList[] = {1, 0x80000001};
25281fc33bb9SClaudio Fontana WHV_CAPABILITY_FEATURES features = {0};
25291fc33bb9SClaudio Fontana
25301fc33bb9SClaudio Fontana whpx = &whpx_global;
25311fc33bb9SClaudio Fontana
25321fc33bb9SClaudio Fontana if (!init_whp_dispatch()) {
25331fc33bb9SClaudio Fontana ret = -ENOSYS;
25341fc33bb9SClaudio Fontana goto error;
25351fc33bb9SClaudio Fontana }
25361fc33bb9SClaudio Fontana
25371fc33bb9SClaudio Fontana whpx->mem_quota = ms->ram_size;
25381fc33bb9SClaudio Fontana
25391fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetCapability(
25401fc33bb9SClaudio Fontana WHvCapabilityCodeHypervisorPresent, &whpx_cap,
25411fc33bb9SClaudio Fontana sizeof(whpx_cap), &whpx_cap_size);
25421fc33bb9SClaudio Fontana if (FAILED(hr) || !whpx_cap.HypervisorPresent) {
25431fc33bb9SClaudio Fontana error_report("WHPX: No accelerator found, hr=%08lx", hr);
25441fc33bb9SClaudio Fontana ret = -ENOSPC;
25451fc33bb9SClaudio Fontana goto error;
25461fc33bb9SClaudio Fontana }
25471fc33bb9SClaudio Fontana
25481fc33bb9SClaudio Fontana hr = whp_dispatch.WHvGetCapability(
25491fc33bb9SClaudio Fontana WHvCapabilityCodeFeatures, &features, sizeof(features), NULL);
25501fc33bb9SClaudio Fontana if (FAILED(hr)) {
25511fc33bb9SClaudio Fontana error_report("WHPX: Failed to query capabilities, hr=%08lx", hr);
25521fc33bb9SClaudio Fontana ret = -EINVAL;
25531fc33bb9SClaudio Fontana goto error;
25541fc33bb9SClaudio Fontana }
25551fc33bb9SClaudio Fontana
25561fc33bb9SClaudio Fontana hr = whp_dispatch.WHvCreatePartition(&whpx->partition);
25571fc33bb9SClaudio Fontana if (FAILED(hr)) {
25581fc33bb9SClaudio Fontana error_report("WHPX: Failed to create partition, hr=%08lx", hr);
25591fc33bb9SClaudio Fontana ret = -EINVAL;
25601fc33bb9SClaudio Fontana goto error;
25611fc33bb9SClaudio Fontana }
25621fc33bb9SClaudio Fontana
2563b6b3da99SSunil Muthuswamy /*
2564b6b3da99SSunil Muthuswamy * Query the XSAVE capability of the partition. Any error here is not
2565b6b3da99SSunil Muthuswamy * considered fatal.
2566b6b3da99SSunil Muthuswamy */
2567b6b3da99SSunil Muthuswamy hr = whp_dispatch.WHvGetPartitionProperty(
2568b6b3da99SSunil Muthuswamy whpx->partition,
2569b6b3da99SSunil Muthuswamy WHvPartitionPropertyCodeProcessorXsaveFeatures,
2570b6b3da99SSunil Muthuswamy &whpx_xsave_cap,
2571b6b3da99SSunil Muthuswamy sizeof(whpx_xsave_cap),
2572b6b3da99SSunil Muthuswamy &whpx_cap_size);
2573b6b3da99SSunil Muthuswamy
2574b6b3da99SSunil Muthuswamy /*
2575b6b3da99SSunil Muthuswamy * Windows version which don't support this property will return with the
2576b6b3da99SSunil Muthuswamy * specific error code.
2577b6b3da99SSunil Muthuswamy */
2578b6b3da99SSunil Muthuswamy if (FAILED(hr) && hr != WHV_E_UNKNOWN_PROPERTY) {
2579b6b3da99SSunil Muthuswamy error_report("WHPX: Failed to query XSAVE capability, hr=%08lx", hr);
2580b6b3da99SSunil Muthuswamy }
2581b6b3da99SSunil Muthuswamy
2582b6b3da99SSunil Muthuswamy if (!whpx_has_xsave()) {
2583b6b3da99SSunil Muthuswamy printf("WHPX: Partition is not XSAVE capable\n");
2584b6b3da99SSunil Muthuswamy }
2585b6b3da99SSunil Muthuswamy
25861fc33bb9SClaudio Fontana memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
25871fc33bb9SClaudio Fontana prop.ProcessorCount = ms->smp.cpus;
25881fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetPartitionProperty(
25891fc33bb9SClaudio Fontana whpx->partition,
25901fc33bb9SClaudio Fontana WHvPartitionPropertyCodeProcessorCount,
25911fc33bb9SClaudio Fontana &prop,
25921fc33bb9SClaudio Fontana sizeof(WHV_PARTITION_PROPERTY));
25931fc33bb9SClaudio Fontana
25941fc33bb9SClaudio Fontana if (FAILED(hr)) {
2595db5a06b3SZhao Liu error_report("WHPX: Failed to set partition processor count to %u,"
2596db5a06b3SZhao Liu " hr=%08lx", prop.ProcessorCount, hr);
25971fc33bb9SClaudio Fontana ret = -EINVAL;
25981fc33bb9SClaudio Fontana goto error;
25991fc33bb9SClaudio Fontana }
26001fc33bb9SClaudio Fontana
26011fc33bb9SClaudio Fontana /*
26021fc33bb9SClaudio Fontana * Error out if WHP doesn't support apic emulation and user is requiring
26031fc33bb9SClaudio Fontana * it.
26041fc33bb9SClaudio Fontana */
26051fc33bb9SClaudio Fontana if (whpx->kernel_irqchip_required && (!features.LocalApicEmulation ||
26061fc33bb9SClaudio Fontana !whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2)) {
26071fc33bb9SClaudio Fontana error_report("WHPX: kernel irqchip requested, but unavailable. "
26081fc33bb9SClaudio Fontana "Try without kernel-irqchip or with kernel-irqchip=off");
26091fc33bb9SClaudio Fontana ret = -EINVAL;
26101fc33bb9SClaudio Fontana goto error;
26111fc33bb9SClaudio Fontana }
26121fc33bb9SClaudio Fontana
26131fc33bb9SClaudio Fontana if (whpx->kernel_irqchip_allowed && features.LocalApicEmulation &&
26141fc33bb9SClaudio Fontana whp_dispatch.WHvSetVirtualProcessorInterruptControllerState2) {
26151fc33bb9SClaudio Fontana WHV_X64_LOCAL_APIC_EMULATION_MODE mode =
26161fc33bb9SClaudio Fontana WHvX64LocalApicEmulationModeXApic;
26171fc33bb9SClaudio Fontana printf("WHPX: setting APIC emulation mode in the hypervisor\n");
26181fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetPartitionProperty(
26191fc33bb9SClaudio Fontana whpx->partition,
26201fc33bb9SClaudio Fontana WHvPartitionPropertyCodeLocalApicEmulationMode,
26211fc33bb9SClaudio Fontana &mode,
26221fc33bb9SClaudio Fontana sizeof(mode));
26231fc33bb9SClaudio Fontana if (FAILED(hr)) {
26241fc33bb9SClaudio Fontana error_report("WHPX: Failed to enable kernel irqchip hr=%08lx", hr);
26251fc33bb9SClaudio Fontana if (whpx->kernel_irqchip_required) {
26261fc33bb9SClaudio Fontana error_report("WHPX: kernel irqchip requested, but unavailable");
26271fc33bb9SClaudio Fontana ret = -EINVAL;
26281fc33bb9SClaudio Fontana goto error;
26291fc33bb9SClaudio Fontana }
26301fc33bb9SClaudio Fontana } else {
26311fc33bb9SClaudio Fontana whpx->apic_in_platform = true;
26321fc33bb9SClaudio Fontana }
26331fc33bb9SClaudio Fontana }
26341fc33bb9SClaudio Fontana
26351fc33bb9SClaudio Fontana /* Register for MSR and CPUID exits */
26361fc33bb9SClaudio Fontana memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
26371fc33bb9SClaudio Fontana prop.ExtendedVmExits.X64MsrExit = 1;
26381fc33bb9SClaudio Fontana prop.ExtendedVmExits.X64CpuidExit = 1;
2639d7482ffeSIvan Shcherbakov prop.ExtendedVmExits.ExceptionExit = 1;
26401fc33bb9SClaudio Fontana if (whpx_apic_in_platform()) {
26411fc33bb9SClaudio Fontana prop.ExtendedVmExits.X64ApicInitSipiExitTrap = 1;
26421fc33bb9SClaudio Fontana }
26431fc33bb9SClaudio Fontana
26441fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetPartitionProperty(
26451fc33bb9SClaudio Fontana whpx->partition,
26461fc33bb9SClaudio Fontana WHvPartitionPropertyCodeExtendedVmExits,
26471fc33bb9SClaudio Fontana &prop,
26481fc33bb9SClaudio Fontana sizeof(WHV_PARTITION_PROPERTY));
26491fc33bb9SClaudio Fontana if (FAILED(hr)) {
26501fc33bb9SClaudio Fontana error_report("WHPX: Failed to enable MSR & CPUIDexit, hr=%08lx", hr);
26511fc33bb9SClaudio Fontana ret = -EINVAL;
26521fc33bb9SClaudio Fontana goto error;
26531fc33bb9SClaudio Fontana }
26541fc33bb9SClaudio Fontana
26551fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetPartitionProperty(
26561fc33bb9SClaudio Fontana whpx->partition,
26571fc33bb9SClaudio Fontana WHvPartitionPropertyCodeCpuidExitList,
26581fc33bb9SClaudio Fontana cpuidExitList,
26591fc33bb9SClaudio Fontana RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32));
26601fc33bb9SClaudio Fontana
26611fc33bb9SClaudio Fontana if (FAILED(hr)) {
26621fc33bb9SClaudio Fontana error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx",
26631fc33bb9SClaudio Fontana hr);
26641fc33bb9SClaudio Fontana ret = -EINVAL;
26651fc33bb9SClaudio Fontana goto error;
26661fc33bb9SClaudio Fontana }
26671fc33bb9SClaudio Fontana
2668d7482ffeSIvan Shcherbakov /*
2669d7482ffeSIvan Shcherbakov * We do not want to intercept any exceptions from the guest,
2670d7482ffeSIvan Shcherbakov * until we actually start debugging with gdb.
2671d7482ffeSIvan Shcherbakov */
2672d7482ffeSIvan Shcherbakov whpx->exception_exit_bitmap = -1;
2673d7482ffeSIvan Shcherbakov hr = whpx_set_exception_exit_bitmap(0);
2674d7482ffeSIvan Shcherbakov
2675d7482ffeSIvan Shcherbakov if (FAILED(hr)) {
2676d7482ffeSIvan Shcherbakov error_report("WHPX: Failed to set exception exit bitmap, hr=%08lx", hr);
2677d7482ffeSIvan Shcherbakov ret = -EINVAL;
2678d7482ffeSIvan Shcherbakov goto error;
2679d7482ffeSIvan Shcherbakov }
2680d7482ffeSIvan Shcherbakov
26811fc33bb9SClaudio Fontana hr = whp_dispatch.WHvSetupPartition(whpx->partition);
26821fc33bb9SClaudio Fontana if (FAILED(hr)) {
26831fc33bb9SClaudio Fontana error_report("WHPX: Failed to setup partition, hr=%08lx", hr);
26841fc33bb9SClaudio Fontana ret = -EINVAL;
26851fc33bb9SClaudio Fontana goto error;
26861fc33bb9SClaudio Fontana }
26871fc33bb9SClaudio Fontana
26881fc33bb9SClaudio Fontana whpx_memory_init();
26891fc33bb9SClaudio Fontana
26901fc33bb9SClaudio Fontana printf("Windows Hypervisor Platform accelerator is operational\n");
26911fc33bb9SClaudio Fontana return 0;
26921fc33bb9SClaudio Fontana
26931fc33bb9SClaudio Fontana error:
26941fc33bb9SClaudio Fontana
26951fc33bb9SClaudio Fontana if (NULL != whpx->partition) {
26961fc33bb9SClaudio Fontana whp_dispatch.WHvDeletePartition(whpx->partition);
26971fc33bb9SClaudio Fontana whpx->partition = NULL;
26981fc33bb9SClaudio Fontana }
26991fc33bb9SClaudio Fontana
27001fc33bb9SClaudio Fontana return ret;
27011fc33bb9SClaudio Fontana }
27021fc33bb9SClaudio Fontana
whpx_enabled(void)27031fc33bb9SClaudio Fontana int whpx_enabled(void)
27041fc33bb9SClaudio Fontana {
27051fc33bb9SClaudio Fontana return whpx_allowed;
27061fc33bb9SClaudio Fontana }
27071fc33bb9SClaudio Fontana
whpx_apic_in_platform(void)270884f4ef17SPaolo Bonzini bool whpx_apic_in_platform(void) {
270984f4ef17SPaolo Bonzini return whpx_global.apic_in_platform;
271084f4ef17SPaolo Bonzini }
271184f4ef17SPaolo Bonzini
whpx_accel_class_init(ObjectClass * oc,void * data)27121fc33bb9SClaudio Fontana static void whpx_accel_class_init(ObjectClass *oc, void *data)
27131fc33bb9SClaudio Fontana {
27141fc33bb9SClaudio Fontana AccelClass *ac = ACCEL_CLASS(oc);
27151fc33bb9SClaudio Fontana ac->name = "WHPX";
27161fc33bb9SClaudio Fontana ac->init_machine = whpx_accel_init;
27171fc33bb9SClaudio Fontana ac->allowed = &whpx_allowed;
27181fc33bb9SClaudio Fontana
27191fc33bb9SClaudio Fontana object_class_property_add(oc, "kernel-irqchip", "on|off|split",
27201fc33bb9SClaudio Fontana NULL, whpx_set_kernel_irqchip,
27211fc33bb9SClaudio Fontana NULL, NULL);
27221fc33bb9SClaudio Fontana object_class_property_set_description(oc, "kernel-irqchip",
27231fc33bb9SClaudio Fontana "Configure WHPX in-kernel irqchip");
27241fc33bb9SClaudio Fontana }
27251fc33bb9SClaudio Fontana
whpx_accel_instance_init(Object * obj)27261fc33bb9SClaudio Fontana static void whpx_accel_instance_init(Object *obj)
27271fc33bb9SClaudio Fontana {
27281fc33bb9SClaudio Fontana struct whpx_state *whpx = &whpx_global;
27291fc33bb9SClaudio Fontana
27301fc33bb9SClaudio Fontana memset(whpx, 0, sizeof(struct whpx_state));
27311fc33bb9SClaudio Fontana /* Turn on kernel-irqchip, by default */
27321fc33bb9SClaudio Fontana whpx->kernel_irqchip_allowed = true;
27331fc33bb9SClaudio Fontana }
27341fc33bb9SClaudio Fontana
27351fc33bb9SClaudio Fontana static const TypeInfo whpx_accel_type = {
27361fc33bb9SClaudio Fontana .name = ACCEL_CLASS_NAME("whpx"),
27371fc33bb9SClaudio Fontana .parent = TYPE_ACCEL,
27381fc33bb9SClaudio Fontana .instance_init = whpx_accel_instance_init,
27391fc33bb9SClaudio Fontana .class_init = whpx_accel_class_init,
27401fc33bb9SClaudio Fontana };
27411fc33bb9SClaudio Fontana
whpx_type_init(void)27421fc33bb9SClaudio Fontana static void whpx_type_init(void)
27431fc33bb9SClaudio Fontana {
27441fc33bb9SClaudio Fontana type_register_static(&whpx_accel_type);
27451fc33bb9SClaudio Fontana }
27461fc33bb9SClaudio Fontana
init_whp_dispatch(void)27471fc33bb9SClaudio Fontana bool init_whp_dispatch(void)
27481fc33bb9SClaudio Fontana {
27491fc33bb9SClaudio Fontana if (whp_dispatch_initialized) {
27501fc33bb9SClaudio Fontana return true;
27511fc33bb9SClaudio Fontana }
27521fc33bb9SClaudio Fontana
27531fc33bb9SClaudio Fontana if (!load_whp_dispatch_fns(&hWinHvPlatform, WINHV_PLATFORM_FNS_DEFAULT)) {
27541fc33bb9SClaudio Fontana goto error;
27551fc33bb9SClaudio Fontana }
27561fc33bb9SClaudio Fontana
27571fc33bb9SClaudio Fontana if (!load_whp_dispatch_fns(&hWinHvEmulation, WINHV_EMULATION_FNS_DEFAULT)) {
27581fc33bb9SClaudio Fontana goto error;
27591fc33bb9SClaudio Fontana }
27601fc33bb9SClaudio Fontana
27611fc33bb9SClaudio Fontana assert(load_whp_dispatch_fns(&hWinHvPlatform,
27621fc33bb9SClaudio Fontana WINHV_PLATFORM_FNS_SUPPLEMENTAL));
27631fc33bb9SClaudio Fontana whp_dispatch_initialized = true;
27641fc33bb9SClaudio Fontana
27651fc33bb9SClaudio Fontana return true;
27661fc33bb9SClaudio Fontana error:
27671fc33bb9SClaudio Fontana if (hWinHvPlatform) {
27681fc33bb9SClaudio Fontana FreeLibrary(hWinHvPlatform);
27691fc33bb9SClaudio Fontana }
27701fc33bb9SClaudio Fontana
27711fc33bb9SClaudio Fontana if (hWinHvEmulation) {
27721fc33bb9SClaudio Fontana FreeLibrary(hWinHvEmulation);
27731fc33bb9SClaudio Fontana }
27741fc33bb9SClaudio Fontana
27751fc33bb9SClaudio Fontana return false;
27761fc33bb9SClaudio Fontana }
27771fc33bb9SClaudio Fontana
27781fc33bb9SClaudio Fontana type_init(whpx_type_init);
2779