]> Git Repo - qemu.git/blob - target/i386/whpx-all.c
WHPX: dynamically load WHP libraries
[qemu.git] / target / i386 / whpx-all.c
1 /*
2  * QEMU Windows Hypervisor Platform accelerator (WHPX)
3  *
4  * Copyright Microsoft Corp. 2017
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2 or later.
7  * See the COPYING file in the top-level directory.
8  *
9  */
10
11 #include "qemu/osdep.h"
12 #include "cpu.h"
13 #include "exec/address-spaces.h"
14 #include "exec/ioport.h"
15 #include "qemu-common.h"
16 #include "strings.h"
17 #include "sysemu/accel.h"
18 #include "sysemu/whpx.h"
19 #include "sysemu/sysemu.h"
20 #include "sysemu/cpus.h"
21 #include "qemu/main-loop.h"
22 #include "hw/boards.h"
23 #include "qemu/error-report.h"
24 #include "qemu/queue.h"
25 #include "qapi/error.h"
26 #include "migration/blocker.h"
27 #include "whp-dispatch.h"
28
29 #include <WinHvPlatform.h>
30 #include <WinHvEmulation.h>
31
32 struct whpx_state {
33     uint64_t mem_quota;
34     WHV_PARTITION_HANDLE partition;
35 };
36
37 static const WHV_REGISTER_NAME whpx_register_names[] = {
38
39     /* X64 General purpose registers */
40     WHvX64RegisterRax,
41     WHvX64RegisterRcx,
42     WHvX64RegisterRdx,
43     WHvX64RegisterRbx,
44     WHvX64RegisterRsp,
45     WHvX64RegisterRbp,
46     WHvX64RegisterRsi,
47     WHvX64RegisterRdi,
48     WHvX64RegisterR8,
49     WHvX64RegisterR9,
50     WHvX64RegisterR10,
51     WHvX64RegisterR11,
52     WHvX64RegisterR12,
53     WHvX64RegisterR13,
54     WHvX64RegisterR14,
55     WHvX64RegisterR15,
56     WHvX64RegisterRip,
57     WHvX64RegisterRflags,
58
59     /* X64 Segment registers */
60     WHvX64RegisterEs,
61     WHvX64RegisterCs,
62     WHvX64RegisterSs,
63     WHvX64RegisterDs,
64     WHvX64RegisterFs,
65     WHvX64RegisterGs,
66     WHvX64RegisterLdtr,
67     WHvX64RegisterTr,
68
69     /* X64 Table registers */
70     WHvX64RegisterIdtr,
71     WHvX64RegisterGdtr,
72
73     /* X64 Control Registers */
74     WHvX64RegisterCr0,
75     WHvX64RegisterCr2,
76     WHvX64RegisterCr3,
77     WHvX64RegisterCr4,
78     WHvX64RegisterCr8,
79
80     /* X64 Debug Registers */
81     /*
82      * WHvX64RegisterDr0,
83      * WHvX64RegisterDr1,
84      * WHvX64RegisterDr2,
85      * WHvX64RegisterDr3,
86      * WHvX64RegisterDr6,
87      * WHvX64RegisterDr7,
88      */
89
90     /* X64 Floating Point and Vector Registers */
91     WHvX64RegisterXmm0,
92     WHvX64RegisterXmm1,
93     WHvX64RegisterXmm2,
94     WHvX64RegisterXmm3,
95     WHvX64RegisterXmm4,
96     WHvX64RegisterXmm5,
97     WHvX64RegisterXmm6,
98     WHvX64RegisterXmm7,
99     WHvX64RegisterXmm8,
100     WHvX64RegisterXmm9,
101     WHvX64RegisterXmm10,
102     WHvX64RegisterXmm11,
103     WHvX64RegisterXmm12,
104     WHvX64RegisterXmm13,
105     WHvX64RegisterXmm14,
106     WHvX64RegisterXmm15,
107     WHvX64RegisterFpMmx0,
108     WHvX64RegisterFpMmx1,
109     WHvX64RegisterFpMmx2,
110     WHvX64RegisterFpMmx3,
111     WHvX64RegisterFpMmx4,
112     WHvX64RegisterFpMmx5,
113     WHvX64RegisterFpMmx6,
114     WHvX64RegisterFpMmx7,
115     WHvX64RegisterFpControlStatus,
116     WHvX64RegisterXmmControlStatus,
117
118     /* X64 MSRs */
119     WHvX64RegisterTsc,
120     WHvX64RegisterEfer,
121 #ifdef TARGET_X86_64
122     WHvX64RegisterKernelGsBase,
123 #endif
124     WHvX64RegisterApicBase,
125     /* WHvX64RegisterPat, */
126     WHvX64RegisterSysenterCs,
127     WHvX64RegisterSysenterEip,
128     WHvX64RegisterSysenterEsp,
129     WHvX64RegisterStar,
130 #ifdef TARGET_X86_64
131     WHvX64RegisterLstar,
132     WHvX64RegisterCstar,
133     WHvX64RegisterSfmask,
134 #endif
135
136     /* Interrupt / Event Registers */
137     /*
138      * WHvRegisterPendingInterruption,
139      * WHvRegisterInterruptState,
140      * WHvRegisterPendingEvent0,
141      * WHvRegisterPendingEvent1
142      * WHvX64RegisterDeliverabilityNotifications,
143      */
144 };
145
146 struct whpx_register_set {
147     WHV_REGISTER_VALUE values[RTL_NUMBER_OF(whpx_register_names)];
148 };
149
150 struct whpx_vcpu {
151     WHV_EMULATOR_HANDLE emulator;
152     bool window_registered;
153     bool interruptable;
154     uint64_t tpr;
155     uint64_t apic_base;
156     bool interruption_pending;
157
158     /* Must be the last field as it may have a tail */
159     WHV_RUN_VP_EXIT_CONTEXT exit_ctx;
160 };
161
162 static bool whpx_allowed;
163 static bool whp_dispatch_initialized;
164 static HMODULE hWinHvPlatform, hWinHvEmulation;
165
166 struct whpx_state whpx_global;
167 struct WHPDispatch whp_dispatch;
168
169
170 /*
171  * VP support
172  */
173
174 static struct whpx_vcpu *get_whpx_vcpu(CPUState *cpu)
175 {
176     return (struct whpx_vcpu *)cpu->hax_vcpu;
177 }
178
179 static WHV_X64_SEGMENT_REGISTER whpx_seg_q2h(const SegmentCache *qs, int v86,
180                                              int r86)
181 {
182     WHV_X64_SEGMENT_REGISTER hs;
183     unsigned flags = qs->flags;
184
185     hs.Base = qs->base;
186     hs.Limit = qs->limit;
187     hs.Selector = qs->selector;
188
189     if (v86) {
190         hs.Attributes = 0;
191         hs.SegmentType = 3;
192         hs.Present = 1;
193         hs.DescriptorPrivilegeLevel = 3;
194         hs.NonSystemSegment = 1;
195
196     } else {
197         hs.Attributes = (flags >> DESC_TYPE_SHIFT);
198
199         if (r86) {
200             /* hs.Base &= 0xfffff; */
201         }
202     }
203
204     return hs;
205 }
206
207 static SegmentCache whpx_seg_h2q(const WHV_X64_SEGMENT_REGISTER *hs)
208 {
209     SegmentCache qs;
210
211     qs.base = hs->Base;
212     qs.limit = hs->Limit;
213     qs.selector = hs->Selector;
214
215     qs.flags = ((uint32_t)hs->Attributes) << DESC_TYPE_SHIFT;
216
217     return qs;
218 }
219
220 static void whpx_set_registers(CPUState *cpu)
221 {
222     struct whpx_state *whpx = &whpx_global;
223     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
224     struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
225     X86CPU *x86_cpu = X86_CPU(cpu);
226     struct whpx_register_set vcxt = {0};
227     HRESULT hr;
228     int idx = 0;
229     int i;
230     int v86, r86;
231
232     assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
233
234     v86 = (env->eflags & VM_MASK);
235     r86 = !(env->cr[0] & CR0_PE_MASK);
236
237     vcpu->tpr = cpu_get_apic_tpr(x86_cpu->apic_state);
238     vcpu->apic_base = cpu_get_apic_base(x86_cpu->apic_state);
239
240     /* Indexes for first 16 registers match between HV and QEMU definitions */
241     for (idx = 0; idx < CPU_NB_REGS64; idx += 1) {
242         vcxt.values[idx].Reg64 = env->regs[idx];
243     }
244
245     /* Same goes for RIP and RFLAGS */
246     assert(whpx_register_names[idx] == WHvX64RegisterRip);
247     vcxt.values[idx++].Reg64 = env->eip;
248
249     assert(whpx_register_names[idx] == WHvX64RegisterRflags);
250     vcxt.values[idx++].Reg64 = env->eflags;
251
252     /* Translate 6+4 segment registers. HV and QEMU order matches  */
253     assert(idx == WHvX64RegisterEs);
254     for (i = 0; i < 6; i += 1, idx += 1) {
255         vcxt.values[idx].Segment = whpx_seg_q2h(&env->segs[i], v86, r86);
256     }
257
258     assert(idx == WHvX64RegisterLdtr);
259     vcxt.values[idx++].Segment = whpx_seg_q2h(&env->ldt, 0, 0);
260
261     assert(idx == WHvX64RegisterTr);
262     vcxt.values[idx++].Segment = whpx_seg_q2h(&env->tr, 0, 0);
263
264     assert(idx == WHvX64RegisterIdtr);
265     vcxt.values[idx].Table.Base = env->idt.base;
266     vcxt.values[idx].Table.Limit = env->idt.limit;
267     idx += 1;
268
269     assert(idx == WHvX64RegisterGdtr);
270     vcxt.values[idx].Table.Base = env->gdt.base;
271     vcxt.values[idx].Table.Limit = env->gdt.limit;
272     idx += 1;
273
274     /* CR0, 2, 3, 4, 8 */
275     assert(whpx_register_names[idx] == WHvX64RegisterCr0);
276     vcxt.values[idx++].Reg64 = env->cr[0];
277     assert(whpx_register_names[idx] == WHvX64RegisterCr2);
278     vcxt.values[idx++].Reg64 = env->cr[2];
279     assert(whpx_register_names[idx] == WHvX64RegisterCr3);
280     vcxt.values[idx++].Reg64 = env->cr[3];
281     assert(whpx_register_names[idx] == WHvX64RegisterCr4);
282     vcxt.values[idx++].Reg64 = env->cr[4];
283     assert(whpx_register_names[idx] == WHvX64RegisterCr8);
284     vcxt.values[idx++].Reg64 = vcpu->tpr;
285
286     /* 8 Debug Registers - Skipped */
287
288     /* 16 XMM registers */
289     assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
290     for (i = 0; i < 16; i += 1, idx += 1) {
291         vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);
292         vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);
293     }
294
295     /* 8 FP registers */
296     assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
297     for (i = 0; i < 8; i += 1, idx += 1) {
298         vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0);
299         /* vcxt.values[idx].Fp.AsUINT128.High64 =
300                env->fpregs[i].mmx.MMX_Q(1);
301         */
302     }
303
304     /* FP control status register */
305     assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);
306     vcxt.values[idx].FpControlStatus.FpControl = env->fpuc;
307     vcxt.values[idx].FpControlStatus.FpStatus =
308         (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
309     vcxt.values[idx].FpControlStatus.FpTag = 0;
310     for (i = 0; i < 8; ++i) {
311         vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i;
312     }
313     vcxt.values[idx].FpControlStatus.Reserved = 0;
314     vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop;
315     vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip;
316     idx += 1;
317
318     /* XMM control status register */
319     assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);
320     vcxt.values[idx].XmmControlStatus.LastFpRdp = 0;
321     vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr;
322     vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff;
323     idx += 1;
324
325     /* MSRs */
326     assert(whpx_register_names[idx] == WHvX64RegisterTsc);
327     vcxt.values[idx++].Reg64 = env->tsc;
328     assert(whpx_register_names[idx] == WHvX64RegisterEfer);
329     vcxt.values[idx++].Reg64 = env->efer;
330 #ifdef TARGET_X86_64
331     assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase);
332     vcxt.values[idx++].Reg64 = env->kernelgsbase;
333 #endif
334
335     assert(whpx_register_names[idx] == WHvX64RegisterApicBase);
336     vcxt.values[idx++].Reg64 = vcpu->apic_base;
337
338     /* WHvX64RegisterPat - Skipped */
339
340     assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs);
341     vcxt.values[idx++].Reg64 = env->sysenter_cs;
342     assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip);
343     vcxt.values[idx++].Reg64 = env->sysenter_eip;
344     assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp);
345     vcxt.values[idx++].Reg64 = env->sysenter_esp;
346     assert(whpx_register_names[idx] == WHvX64RegisterStar);
347     vcxt.values[idx++].Reg64 = env->star;
348 #ifdef TARGET_X86_64
349     assert(whpx_register_names[idx] == WHvX64RegisterLstar);
350     vcxt.values[idx++].Reg64 = env->lstar;
351     assert(whpx_register_names[idx] == WHvX64RegisterCstar);
352     vcxt.values[idx++].Reg64 = env->cstar;
353     assert(whpx_register_names[idx] == WHvX64RegisterSfmask);
354     vcxt.values[idx++].Reg64 = env->fmask;
355 #endif
356
357     /* Interrupt / Event Registers - Skipped */
358
359     assert(idx == RTL_NUMBER_OF(whpx_register_names));
360
361     hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
362         whpx->partition, cpu->cpu_index,
363         whpx_register_names,
364         RTL_NUMBER_OF(whpx_register_names),
365         &vcxt.values[0]);
366
367     if (FAILED(hr)) {
368         error_report("WHPX: Failed to set virtual processor context, hr=%08lx",
369                      hr);
370     }
371
372     return;
373 }
374
375 static void whpx_get_registers(CPUState *cpu)
376 {
377     struct whpx_state *whpx = &whpx_global;
378     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
379     struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
380     X86CPU *x86_cpu = X86_CPU(cpu);
381     struct whpx_register_set vcxt;
382     uint64_t tpr, apic_base;
383     HRESULT hr;
384     int idx = 0;
385     int i;
386
387     assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
388
389     hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
390         whpx->partition, cpu->cpu_index,
391         whpx_register_names,
392         RTL_NUMBER_OF(whpx_register_names),
393         &vcxt.values[0]);
394     if (FAILED(hr)) {
395         error_report("WHPX: Failed to get virtual processor context, hr=%08lx",
396                      hr);
397     }
398
399     /* Indexes for first 16 registers match between HV and QEMU definitions */
400     for (idx = 0; idx < CPU_NB_REGS64; idx += 1) {
401         env->regs[idx] = vcxt.values[idx].Reg64;
402     }
403
404     /* Same goes for RIP and RFLAGS */
405     assert(whpx_register_names[idx] == WHvX64RegisterRip);
406     env->eip = vcxt.values[idx++].Reg64;
407     assert(whpx_register_names[idx] == WHvX64RegisterRflags);
408     env->eflags = vcxt.values[idx++].Reg64;
409
410     /* Translate 6+4 segment registers. HV and QEMU order matches  */
411     assert(idx == WHvX64RegisterEs);
412     for (i = 0; i < 6; i += 1, idx += 1) {
413         env->segs[i] = whpx_seg_h2q(&vcxt.values[idx].Segment);
414     }
415
416     assert(idx == WHvX64RegisterLdtr);
417     env->ldt = whpx_seg_h2q(&vcxt.values[idx++].Segment);
418     assert(idx == WHvX64RegisterTr);
419     env->tr = whpx_seg_h2q(&vcxt.values[idx++].Segment);
420     assert(idx == WHvX64RegisterIdtr);
421     env->idt.base = vcxt.values[idx].Table.Base;
422     env->idt.limit = vcxt.values[idx].Table.Limit;
423     idx += 1;
424     assert(idx == WHvX64RegisterGdtr);
425     env->gdt.base = vcxt.values[idx].Table.Base;
426     env->gdt.limit = vcxt.values[idx].Table.Limit;
427     idx += 1;
428
429     /* CR0, 2, 3, 4, 8 */
430     assert(whpx_register_names[idx] == WHvX64RegisterCr0);
431     env->cr[0] = vcxt.values[idx++].Reg64;
432     assert(whpx_register_names[idx] == WHvX64RegisterCr2);
433     env->cr[2] = vcxt.values[idx++].Reg64;
434     assert(whpx_register_names[idx] == WHvX64RegisterCr3);
435     env->cr[3] = vcxt.values[idx++].Reg64;
436     assert(whpx_register_names[idx] == WHvX64RegisterCr4);
437     env->cr[4] = vcxt.values[idx++].Reg64;
438     assert(whpx_register_names[idx] == WHvX64RegisterCr8);
439     tpr = vcxt.values[idx++].Reg64;
440     if (tpr != vcpu->tpr) {
441         vcpu->tpr = tpr;
442         cpu_set_apic_tpr(x86_cpu->apic_state, tpr);
443     }
444
445     /* 8 Debug Registers - Skipped */
446
447     /* 16 XMM registers */
448     assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
449     for (i = 0; i < 16; i += 1, idx += 1) {
450         env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64;
451         env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64;
452     }
453
454     /* 8 FP registers */
455     assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
456     for (i = 0; i < 8; i += 1, idx += 1) {
457         env->fpregs[i].mmx.MMX_Q(0) = vcxt.values[idx].Fp.AsUINT128.Low64;
458         /* env->fpregs[i].mmx.MMX_Q(1) =
459                vcxt.values[idx].Fp.AsUINT128.High64;
460         */
461     }
462
463     /* FP control status register */
464     assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);
465     env->fpuc = vcxt.values[idx].FpControlStatus.FpControl;
466     env->fpstt = (vcxt.values[idx].FpControlStatus.FpStatus >> 11) & 0x7;
467     env->fpus = vcxt.values[idx].FpControlStatus.FpStatus & ~0x3800;
468     for (i = 0; i < 8; ++i) {
469         env->fptags[i] = !((vcxt.values[idx].FpControlStatus.FpTag >> i) & 1);
470     }
471     env->fpop = vcxt.values[idx].FpControlStatus.LastFpOp;
472     env->fpip = vcxt.values[idx].FpControlStatus.LastFpRip;
473     idx += 1;
474
475     /* XMM control status register */
476     assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);
477     env->mxcsr = vcxt.values[idx].XmmControlStatus.XmmStatusControl;
478     idx += 1;
479
480     /* MSRs */
481     assert(whpx_register_names[idx] == WHvX64RegisterTsc);
482     env->tsc = vcxt.values[idx++].Reg64;
483     assert(whpx_register_names[idx] == WHvX64RegisterEfer);
484     env->efer = vcxt.values[idx++].Reg64;
485 #ifdef TARGET_X86_64
486     assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase);
487     env->kernelgsbase = vcxt.values[idx++].Reg64;
488 #endif
489
490     assert(whpx_register_names[idx] == WHvX64RegisterApicBase);
491     apic_base = vcxt.values[idx++].Reg64;
492     if (apic_base != vcpu->apic_base) {
493         vcpu->apic_base = apic_base;
494         cpu_set_apic_base(x86_cpu->apic_state, vcpu->apic_base);
495     }
496
497     /* WHvX64RegisterPat - Skipped */
498
499     assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs);
500     env->sysenter_cs = vcxt.values[idx++].Reg64;;
501     assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip);
502     env->sysenter_eip = vcxt.values[idx++].Reg64;
503     assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp);
504     env->sysenter_esp = vcxt.values[idx++].Reg64;
505     assert(whpx_register_names[idx] == WHvX64RegisterStar);
506     env->star = vcxt.values[idx++].Reg64;
507 #ifdef TARGET_X86_64
508     assert(whpx_register_names[idx] == WHvX64RegisterLstar);
509     env->lstar = vcxt.values[idx++].Reg64;
510     assert(whpx_register_names[idx] == WHvX64RegisterCstar);
511     env->cstar = vcxt.values[idx++].Reg64;
512     assert(whpx_register_names[idx] == WHvX64RegisterSfmask);
513     env->fmask = vcxt.values[idx++].Reg64;
514 #endif
515
516     /* Interrupt / Event Registers - Skipped */
517
518     assert(idx == RTL_NUMBER_OF(whpx_register_names));
519
520     return;
521 }
522
523 static HRESULT CALLBACK whpx_emu_ioport_callback(
524     void *ctx,
525     WHV_EMULATOR_IO_ACCESS_INFO *IoAccess)
526 {
527     MemTxAttrs attrs = { 0 };
528     address_space_rw(&address_space_io, IoAccess->Port, attrs,
529                      (uint8_t *)&IoAccess->Data, IoAccess->AccessSize,
530                      IoAccess->Direction);
531     return S_OK;
532 }
533
534 static HRESULT CALLBACK whpx_emu_mmio_callback(
535     void *ctx,
536     WHV_EMULATOR_MEMORY_ACCESS_INFO *ma)
537 {
538     cpu_physical_memory_rw(ma->GpaAddress, ma->Data, ma->AccessSize,
539                            ma->Direction);
540     return S_OK;
541 }
542
543 static HRESULT CALLBACK whpx_emu_getreg_callback(
544     void *ctx,
545     const WHV_REGISTER_NAME *RegisterNames,
546     UINT32 RegisterCount,
547     WHV_REGISTER_VALUE *RegisterValues)
548 {
549     HRESULT hr;
550     struct whpx_state *whpx = &whpx_global;
551     CPUState *cpu = (CPUState *)ctx;
552
553     hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
554         whpx->partition, cpu->cpu_index,
555         RegisterNames, RegisterCount,
556         RegisterValues);
557     if (FAILED(hr)) {
558         error_report("WHPX: Failed to get virtual processor registers,"
559                      " hr=%08lx", hr);
560     }
561
562     return hr;
563 }
564
565 static HRESULT CALLBACK whpx_emu_setreg_callback(
566     void *ctx,
567     const WHV_REGISTER_NAME *RegisterNames,
568     UINT32 RegisterCount,
569     const WHV_REGISTER_VALUE *RegisterValues)
570 {
571     HRESULT hr;
572     struct whpx_state *whpx = &whpx_global;
573     CPUState *cpu = (CPUState *)ctx;
574
575     hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
576         whpx->partition, cpu->cpu_index,
577         RegisterNames, RegisterCount,
578         RegisterValues);
579     if (FAILED(hr)) {
580         error_report("WHPX: Failed to set virtual processor registers,"
581                      " hr=%08lx", hr);
582     }
583
584     /*
585      * The emulator just successfully wrote the register state. We clear the
586      * dirty state so we avoid the double write on resume of the VP.
587      */
588     cpu->vcpu_dirty = false;
589
590     return hr;
591 }
592
593 static HRESULT CALLBACK whpx_emu_translate_callback(
594     void *ctx,
595     WHV_GUEST_VIRTUAL_ADDRESS Gva,
596     WHV_TRANSLATE_GVA_FLAGS TranslateFlags,
597     WHV_TRANSLATE_GVA_RESULT_CODE *TranslationResult,
598     WHV_GUEST_PHYSICAL_ADDRESS *Gpa)
599 {
600     HRESULT hr;
601     struct whpx_state *whpx = &whpx_global;
602     CPUState *cpu = (CPUState *)ctx;
603     WHV_TRANSLATE_GVA_RESULT res;
604
605     hr = whp_dispatch.WHvTranslateGva(whpx->partition, cpu->cpu_index,
606                                       Gva, TranslateFlags, &res, Gpa);
607     if (FAILED(hr)) {
608         error_report("WHPX: Failed to translate GVA, hr=%08lx", hr);
609     } else {
610         *TranslationResult = res.ResultCode;
611     }
612
613     return hr;
614 }
615
616 static const WHV_EMULATOR_CALLBACKS whpx_emu_callbacks = {
617     .Size = sizeof(WHV_EMULATOR_CALLBACKS),
618     .WHvEmulatorIoPortCallback = whpx_emu_ioport_callback,
619     .WHvEmulatorMemoryCallback = whpx_emu_mmio_callback,
620     .WHvEmulatorGetVirtualProcessorRegisters = whpx_emu_getreg_callback,
621     .WHvEmulatorSetVirtualProcessorRegisters = whpx_emu_setreg_callback,
622     .WHvEmulatorTranslateGvaPage = whpx_emu_translate_callback,
623 };
624
625 static int whpx_handle_mmio(CPUState *cpu, WHV_MEMORY_ACCESS_CONTEXT *ctx)
626 {
627     HRESULT hr;
628     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
629     WHV_EMULATOR_STATUS emu_status;
630
631     hr = whp_dispatch.WHvEmulatorTryMmioEmulation(
632         vcpu->emulator, cpu,
633         &vcpu->exit_ctx.VpContext, ctx,
634         &emu_status);
635     if (FAILED(hr)) {
636         error_report("WHPX: Failed to parse MMIO access, hr=%08lx", hr);
637         return -1;
638     }
639
640     if (!emu_status.EmulationSuccessful) {
641         error_report("WHPX: Failed to emulate MMIO access with"
642                      " EmulatorReturnStatus: %u", emu_status.AsUINT32);
643         return -1;
644     }
645
646     return 0;
647 }
648
649 static int whpx_handle_portio(CPUState *cpu,
650                               WHV_X64_IO_PORT_ACCESS_CONTEXT *ctx)
651 {
652     HRESULT hr;
653     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
654     WHV_EMULATOR_STATUS emu_status;
655
656     hr = whp_dispatch.WHvEmulatorTryIoEmulation(
657         vcpu->emulator, cpu,
658         &vcpu->exit_ctx.VpContext, ctx,
659         &emu_status);
660     if (FAILED(hr)) {
661         error_report("WHPX: Failed to parse PortIO access, hr=%08lx", hr);
662         return -1;
663     }
664
665     if (!emu_status.EmulationSuccessful) {
666         error_report("WHPX: Failed to emulate PortIO access with"
667                      " EmulatorReturnStatus: %u", emu_status.AsUINT32);
668         return -1;
669     }
670
671     return 0;
672 }
673
674 static int whpx_handle_halt(CPUState *cpu)
675 {
676     struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
677     int ret = 0;
678
679     qemu_mutex_lock_iothread();
680     if (!((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
681           (env->eflags & IF_MASK)) &&
682         !(cpu->interrupt_request & CPU_INTERRUPT_NMI)) {
683         cpu->exception_index = EXCP_HLT;
684         cpu->halted = true;
685         ret = 1;
686     }
687     qemu_mutex_unlock_iothread();
688
689     return ret;
690 }
691
692 static void whpx_vcpu_pre_run(CPUState *cpu)
693 {
694     HRESULT hr;
695     struct whpx_state *whpx = &whpx_global;
696     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
697     struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
698     X86CPU *x86_cpu = X86_CPU(cpu);
699     int irq;
700     uint8_t tpr;
701     WHV_X64_PENDING_INTERRUPTION_REGISTER new_int = {0};
702     UINT32 reg_count = 0;
703     WHV_REGISTER_VALUE reg_values[3] = {0};
704     WHV_REGISTER_NAME reg_names[3];
705
706     qemu_mutex_lock_iothread();
707
708     /* Inject NMI */
709     if (!vcpu->interruption_pending &&
710         cpu->interrupt_request & (CPU_INTERRUPT_NMI | CPU_INTERRUPT_SMI)) {
711         if (cpu->interrupt_request & CPU_INTERRUPT_NMI) {
712             cpu->interrupt_request &= ~CPU_INTERRUPT_NMI;
713             vcpu->interruptable = false;
714             new_int.InterruptionType = WHvX64PendingNmi;
715             new_int.InterruptionPending = 1;
716             new_int.InterruptionVector = 2;
717         }
718         if (cpu->interrupt_request & CPU_INTERRUPT_SMI) {
719             cpu->interrupt_request &= ~CPU_INTERRUPT_SMI;
720         }
721     }
722
723     /*
724      * Force the VCPU out of its inner loop to process any INIT requests or
725      * commit pending TPR access.
726      */
727     if (cpu->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) {
728         if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) &&
729             !(env->hflags & HF_SMM_MASK)) {
730             cpu->exit_request = 1;
731         }
732         if (cpu->interrupt_request & CPU_INTERRUPT_TPR) {
733             cpu->exit_request = 1;
734         }
735     }
736
737     /* Get pending hard interruption or replay one that was overwritten */
738     if (!vcpu->interruption_pending &&
739         vcpu->interruptable && (env->eflags & IF_MASK)) {
740         assert(!new_int.InterruptionPending);
741         if (cpu->interrupt_request & CPU_INTERRUPT_HARD) {
742             cpu->interrupt_request &= ~CPU_INTERRUPT_HARD;
743             irq = cpu_get_pic_interrupt(env);
744             if (irq >= 0) {
745                 new_int.InterruptionType = WHvX64PendingInterrupt;
746                 new_int.InterruptionPending = 1;
747                 new_int.InterruptionVector = irq;
748             }
749         }
750     }
751
752     /* Setup interrupt state if new one was prepared */
753     if (new_int.InterruptionPending) {
754         reg_values[reg_count].PendingInterruption = new_int;
755         reg_names[reg_count] = WHvRegisterPendingInterruption;
756         reg_count += 1;
757     }
758
759     /* Sync the TPR to the CR8 if was modified during the intercept */
760     tpr = cpu_get_apic_tpr(x86_cpu->apic_state);
761     if (tpr != vcpu->tpr) {
762         vcpu->tpr = tpr;
763         reg_values[reg_count].Reg64 = tpr;
764         cpu->exit_request = 1;
765         reg_names[reg_count] = WHvX64RegisterCr8;
766         reg_count += 1;
767     }
768
769     /* Update the state of the interrupt delivery notification */
770     if (!vcpu->window_registered &&
771         cpu->interrupt_request & CPU_INTERRUPT_HARD) {
772         reg_values[reg_count].DeliverabilityNotifications.InterruptNotification
773             = 1;
774         vcpu->window_registered = 1;
775         reg_names[reg_count] = WHvX64RegisterDeliverabilityNotifications;
776         reg_count += 1;
777     }
778
779     qemu_mutex_unlock_iothread();
780
781     if (reg_count) {
782         hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
783             whpx->partition, cpu->cpu_index,
784             reg_names, reg_count, reg_values);
785         if (FAILED(hr)) {
786             error_report("WHPX: Failed to set interrupt state registers,"
787                          " hr=%08lx", hr);
788         }
789     }
790
791     return;
792 }
793
794 static void whpx_vcpu_post_run(CPUState *cpu)
795 {
796     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
797     struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
798     X86CPU *x86_cpu = X86_CPU(cpu);
799
800     env->eflags = vcpu->exit_ctx.VpContext.Rflags;
801
802     uint64_t tpr = vcpu->exit_ctx.VpContext.Cr8;
803     if (vcpu->tpr != tpr) {
804         vcpu->tpr = tpr;
805         qemu_mutex_lock_iothread();
806         cpu_set_apic_tpr(x86_cpu->apic_state, vcpu->tpr);
807         qemu_mutex_unlock_iothread();
808     }
809
810     vcpu->interruption_pending =
811         vcpu->exit_ctx.VpContext.ExecutionState.InterruptionPending;
812
813     vcpu->interruptable =
814         !vcpu->exit_ctx.VpContext.ExecutionState.InterruptShadow;
815
816     return;
817 }
818
819 static void whpx_vcpu_process_async_events(CPUState *cpu)
820 {
821     struct CPUX86State *env = (CPUArchState *)(cpu->env_ptr);
822     X86CPU *x86_cpu = X86_CPU(cpu);
823     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
824
825     if ((cpu->interrupt_request & CPU_INTERRUPT_INIT) &&
826         !(env->hflags & HF_SMM_MASK)) {
827
828         do_cpu_init(x86_cpu);
829         cpu->vcpu_dirty = true;
830         vcpu->interruptable = true;
831     }
832
833     if (cpu->interrupt_request & CPU_INTERRUPT_POLL) {
834         cpu->interrupt_request &= ~CPU_INTERRUPT_POLL;
835         apic_poll_irq(x86_cpu->apic_state);
836     }
837
838     if (((cpu->interrupt_request & CPU_INTERRUPT_HARD) &&
839          (env->eflags & IF_MASK)) ||
840         (cpu->interrupt_request & CPU_INTERRUPT_NMI)) {
841         cpu->halted = false;
842     }
843
844     if (cpu->interrupt_request & CPU_INTERRUPT_SIPI) {
845         if (!cpu->vcpu_dirty) {
846             whpx_get_registers(cpu);
847         }
848         do_cpu_sipi(x86_cpu);
849     }
850
851     if (cpu->interrupt_request & CPU_INTERRUPT_TPR) {
852         cpu->interrupt_request &= ~CPU_INTERRUPT_TPR;
853         if (!cpu->vcpu_dirty) {
854             whpx_get_registers(cpu);
855         }
856         apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip,
857                                       env->tpr_access_type);
858     }
859
860     return;
861 }
862
863 static int whpx_vcpu_run(CPUState *cpu)
864 {
865     HRESULT hr;
866     struct whpx_state *whpx = &whpx_global;
867     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
868     int ret;
869
870     whpx_vcpu_process_async_events(cpu);
871     if (cpu->halted) {
872         cpu->exception_index = EXCP_HLT;
873         atomic_set(&cpu->exit_request, false);
874         return 0;
875     }
876
877     qemu_mutex_unlock_iothread();
878     cpu_exec_start(cpu);
879
880     do {
881         if (cpu->vcpu_dirty) {
882             whpx_set_registers(cpu);
883             cpu->vcpu_dirty = false;
884         }
885
886         whpx_vcpu_pre_run(cpu);
887
888         if (atomic_read(&cpu->exit_request)) {
889             whpx_vcpu_kick(cpu);
890         }
891
892         hr = whp_dispatch.WHvRunVirtualProcessor(
893             whpx->partition, cpu->cpu_index,
894             &vcpu->exit_ctx, sizeof(vcpu->exit_ctx));
895
896         if (FAILED(hr)) {
897             error_report("WHPX: Failed to exec a virtual processor,"
898                          " hr=%08lx", hr);
899             ret = -1;
900             break;
901         }
902
903         whpx_vcpu_post_run(cpu);
904
905         switch (vcpu->exit_ctx.ExitReason) {
906         case WHvRunVpExitReasonMemoryAccess:
907             ret = whpx_handle_mmio(cpu, &vcpu->exit_ctx.MemoryAccess);
908             break;
909
910         case WHvRunVpExitReasonX64IoPortAccess:
911             ret = whpx_handle_portio(cpu, &vcpu->exit_ctx.IoPortAccess);
912             break;
913
914         case WHvRunVpExitReasonX64InterruptWindow:
915             vcpu->window_registered = 0;
916             break;
917
918         case WHvRunVpExitReasonX64Halt:
919             ret = whpx_handle_halt(cpu);
920             break;
921
922         case WHvRunVpExitReasonCanceled:
923             cpu->exception_index = EXCP_INTERRUPT;
924             ret = 1;
925             break;
926
927         case WHvRunVpExitReasonX64Cpuid: {
928             WHV_REGISTER_VALUE reg_values[5] = {0};
929             WHV_REGISTER_NAME reg_names[5];
930             UINT32 reg_count = 5;
931             UINT64 rip, rax, rcx, rdx, rbx;
932
933             rip = vcpu->exit_ctx.VpContext.Rip +
934                   vcpu->exit_ctx.VpContext.InstructionLength;
935             switch (vcpu->exit_ctx.CpuidAccess.Rax) {
936             case 1:
937                 rax = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
938                 /* Advertise that we are running on a hypervisor */
939                 rcx =
940                     vcpu->exit_ctx.CpuidAccess.DefaultResultRcx |
941                     CPUID_EXT_HYPERVISOR;
942
943                 rdx = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
944                 rbx = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
945                 break;
946             default:
947                 rax = vcpu->exit_ctx.CpuidAccess.DefaultResultRax;
948                 rcx = vcpu->exit_ctx.CpuidAccess.DefaultResultRcx;
949                 rdx = vcpu->exit_ctx.CpuidAccess.DefaultResultRdx;
950                 rbx = vcpu->exit_ctx.CpuidAccess.DefaultResultRbx;
951             }
952
953             reg_names[0] = WHvX64RegisterRip;
954             reg_names[1] = WHvX64RegisterRax;
955             reg_names[2] = WHvX64RegisterRcx;
956             reg_names[3] = WHvX64RegisterRdx;
957             reg_names[4] = WHvX64RegisterRbx;
958
959             reg_values[0].Reg64 = rip;
960             reg_values[1].Reg64 = rax;
961             reg_values[2].Reg64 = rcx;
962             reg_values[3].Reg64 = rdx;
963             reg_values[4].Reg64 = rbx;
964
965             hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
966                 whpx->partition, cpu->cpu_index,
967                 reg_names,
968                 reg_count,
969                 reg_values);
970
971             if (FAILED(hr)) {
972                 error_report("WHPX: Failed to set CpuidAccess state registers,"
973                              " hr=%08lx", hr);
974             }
975             ret = 0;
976             break;
977         }
978         case WHvRunVpExitReasonNone:
979         case WHvRunVpExitReasonUnrecoverableException:
980         case WHvRunVpExitReasonInvalidVpRegisterValue:
981         case WHvRunVpExitReasonUnsupportedFeature:
982         case WHvRunVpExitReasonX64MsrAccess:
983         case WHvRunVpExitReasonException:
984         default:
985             error_report("WHPX: Unexpected VP exit code %d",
986                          vcpu->exit_ctx.ExitReason);
987             whpx_get_registers(cpu);
988             qemu_mutex_lock_iothread();
989             qemu_system_guest_panicked(cpu_get_crash_info(cpu));
990             qemu_mutex_unlock_iothread();
991             break;
992         }
993
994     } while (!ret);
995
996     cpu_exec_end(cpu);
997     qemu_mutex_lock_iothread();
998     current_cpu = cpu;
999
1000     atomic_set(&cpu->exit_request, false);
1001
1002     return ret < 0;
1003 }
1004
1005 static void do_whpx_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
1006 {
1007     whpx_get_registers(cpu);
1008     cpu->vcpu_dirty = true;
1009 }
1010
1011 static void do_whpx_cpu_synchronize_post_reset(CPUState *cpu,
1012                                                run_on_cpu_data arg)
1013 {
1014     whpx_set_registers(cpu);
1015     cpu->vcpu_dirty = false;
1016 }
1017
1018 static void do_whpx_cpu_synchronize_post_init(CPUState *cpu,
1019                                               run_on_cpu_data arg)
1020 {
1021     whpx_set_registers(cpu);
1022     cpu->vcpu_dirty = false;
1023 }
1024
1025 static void do_whpx_cpu_synchronize_pre_loadvm(CPUState *cpu,
1026                                                run_on_cpu_data arg)
1027 {
1028     cpu->vcpu_dirty = true;
1029 }
1030
1031 /*
1032  * CPU support.
1033  */
1034
1035 void whpx_cpu_synchronize_state(CPUState *cpu)
1036 {
1037     if (!cpu->vcpu_dirty) {
1038         run_on_cpu(cpu, do_whpx_cpu_synchronize_state, RUN_ON_CPU_NULL);
1039     }
1040 }
1041
1042 void whpx_cpu_synchronize_post_reset(CPUState *cpu)
1043 {
1044     run_on_cpu(cpu, do_whpx_cpu_synchronize_post_reset, RUN_ON_CPU_NULL);
1045 }
1046
1047 void whpx_cpu_synchronize_post_init(CPUState *cpu)
1048 {
1049     run_on_cpu(cpu, do_whpx_cpu_synchronize_post_init, RUN_ON_CPU_NULL);
1050 }
1051
1052 void whpx_cpu_synchronize_pre_loadvm(CPUState *cpu)
1053 {
1054     run_on_cpu(cpu, do_whpx_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);
1055 }
1056
1057 /*
1058  * Vcpu support.
1059  */
1060
1061 static Error *whpx_migration_blocker;
1062
1063 int whpx_init_vcpu(CPUState *cpu)
1064 {
1065     HRESULT hr;
1066     struct whpx_state *whpx = &whpx_global;
1067     struct whpx_vcpu *vcpu;
1068     Error *local_error = NULL;
1069
1070     /* Add migration blockers for all unsupported features of the
1071      * Windows Hypervisor Platform
1072      */
1073     if (whpx_migration_blocker == NULL) {
1074         error_setg(&whpx_migration_blocker,
1075                "State blocked due to non-migratable CPUID feature support,"
1076                "dirty memory tracking support, and XSAVE/XRSTOR support");
1077
1078         (void)migrate_add_blocker(whpx_migration_blocker, &local_error);
1079         if (local_error) {
1080             error_report_err(local_error);
1081             migrate_del_blocker(whpx_migration_blocker);
1082             error_free(whpx_migration_blocker);
1083             return -EINVAL;
1084         }
1085     }
1086
1087     vcpu = g_malloc0(sizeof(struct whpx_vcpu));
1088
1089     if (!vcpu) {
1090         error_report("WHPX: Failed to allocte VCPU context.");
1091         return -ENOMEM;
1092     }
1093
1094     hr = whp_dispatch.WHvEmulatorCreateEmulator(
1095         &whpx_emu_callbacks,
1096         &vcpu->emulator);
1097     if (FAILED(hr)) {
1098         error_report("WHPX: Failed to setup instruction completion support,"
1099                      " hr=%08lx", hr);
1100         g_free(vcpu);
1101         return -EINVAL;
1102     }
1103
1104     hr = whp_dispatch.WHvCreateVirtualProcessor(
1105         whpx->partition, cpu->cpu_index, 0);
1106     if (FAILED(hr)) {
1107         error_report("WHPX: Failed to create a virtual processor,"
1108                      " hr=%08lx", hr);
1109         whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
1110         g_free(vcpu);
1111         return -EINVAL;
1112     }
1113
1114     vcpu->interruptable = true;
1115
1116     cpu->vcpu_dirty = true;
1117     cpu->hax_vcpu = (struct hax_vcpu_state *)vcpu;
1118
1119     return 0;
1120 }
1121
1122 int whpx_vcpu_exec(CPUState *cpu)
1123 {
1124     int ret;
1125     int fatal;
1126
1127     for (;;) {
1128         if (cpu->exception_index >= EXCP_INTERRUPT) {
1129             ret = cpu->exception_index;
1130             cpu->exception_index = -1;
1131             break;
1132         }
1133
1134         fatal = whpx_vcpu_run(cpu);
1135
1136         if (fatal) {
1137             error_report("WHPX: Failed to exec a virtual processor");
1138             abort();
1139         }
1140     }
1141
1142     return ret;
1143 }
1144
1145 void whpx_destroy_vcpu(CPUState *cpu)
1146 {
1147     struct whpx_state *whpx = &whpx_global;
1148     struct whpx_vcpu *vcpu = get_whpx_vcpu(cpu);
1149
1150     whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index);
1151     whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator);
1152     g_free(cpu->hax_vcpu);
1153     return;
1154 }
1155
1156 void whpx_vcpu_kick(CPUState *cpu)
1157 {
1158     struct whpx_state *whpx = &whpx_global;
1159     whp_dispatch.WHvCancelRunVirtualProcessor(
1160         whpx->partition, cpu->cpu_index, 0);
1161 }
1162
1163 /*
1164  * Memory support.
1165  */
1166
1167 static void whpx_update_mapping(hwaddr start_pa, ram_addr_t size,
1168                                 void *host_va, int add, int rom,
1169                                 const char *name)
1170 {
1171     struct whpx_state *whpx = &whpx_global;
1172     HRESULT hr;
1173
1174     /*
1175     if (add) {
1176         printf("WHPX: ADD PA:%p Size:%p, Host:%p, %s, '%s'\n",
1177                (void*)start_pa, (void*)size, host_va,
1178                (rom ? "ROM" : "RAM"), name);
1179     } else {
1180         printf("WHPX: DEL PA:%p Size:%p, Host:%p,      '%s'\n",
1181                (void*)start_pa, (void*)size, host_va, name);
1182     }
1183     */
1184
1185     if (add) {
1186         hr = whp_dispatch.WHvMapGpaRange(whpx->partition,
1187                                          host_va,
1188                                          start_pa,
1189                                          size,
1190                                          (WHvMapGpaRangeFlagRead |
1191                                           WHvMapGpaRangeFlagExecute |
1192                                           (rom ? 0 : WHvMapGpaRangeFlagWrite)));
1193     } else {
1194         hr = whp_dispatch.WHvUnmapGpaRange(whpx->partition,
1195                                            start_pa,
1196                                            size);
1197     }
1198
1199     if (FAILED(hr)) {
1200         error_report("WHPX: Failed to %s GPA range '%s' PA:%p, Size:%p bytes,"
1201                      " Host:%p, hr=%08lx",
1202                      (add ? "MAP" : "UNMAP"), name,
1203                      (void *)start_pa, (void *)size, host_va, hr);
1204     }
1205 }
1206
1207 static void whpx_process_section(MemoryRegionSection *section, int add)
1208 {
1209     MemoryRegion *mr = section->mr;
1210     hwaddr start_pa = section->offset_within_address_space;
1211     ram_addr_t size = int128_get64(section->size);
1212     unsigned int delta;
1213     uint64_t host_va;
1214
1215     if (!memory_region_is_ram(mr)) {
1216         return;
1217     }
1218
1219     delta = qemu_real_host_page_size - (start_pa & ~qemu_real_host_page_mask);
1220     delta &= ~qemu_real_host_page_mask;
1221     if (delta > size) {
1222         return;
1223     }
1224     start_pa += delta;
1225     size -= delta;
1226     size &= qemu_real_host_page_mask;
1227     if (!size || (start_pa & ~qemu_real_host_page_mask)) {
1228         return;
1229     }
1230
1231     host_va = (uintptr_t)memory_region_get_ram_ptr(mr)
1232             + section->offset_within_region + delta;
1233
1234     whpx_update_mapping(start_pa, size, (void *)host_va, add,
1235                        memory_region_is_rom(mr), mr->name);
1236 }
1237
1238 static void whpx_region_add(MemoryListener *listener,
1239                            MemoryRegionSection *section)
1240 {
1241     memory_region_ref(section->mr);
1242     whpx_process_section(section, 1);
1243 }
1244
1245 static void whpx_region_del(MemoryListener *listener,
1246                            MemoryRegionSection *section)
1247 {
1248     whpx_process_section(section, 0);
1249     memory_region_unref(section->mr);
1250 }
1251
1252 static void whpx_transaction_begin(MemoryListener *listener)
1253 {
1254 }
1255
1256 static void whpx_transaction_commit(MemoryListener *listener)
1257 {
1258 }
1259
1260 static void whpx_log_sync(MemoryListener *listener,
1261                          MemoryRegionSection *section)
1262 {
1263     MemoryRegion *mr = section->mr;
1264
1265     if (!memory_region_is_ram(mr)) {
1266         return;
1267     }
1268
1269     memory_region_set_dirty(mr, 0, int128_get64(section->size));
1270 }
1271
1272 static MemoryListener whpx_memory_listener = {
1273     .begin = whpx_transaction_begin,
1274     .commit = whpx_transaction_commit,
1275     .region_add = whpx_region_add,
1276     .region_del = whpx_region_del,
1277     .log_sync = whpx_log_sync,
1278     .priority = 10,
1279 };
1280
1281 static void whpx_memory_init(void)
1282 {
1283     memory_listener_register(&whpx_memory_listener, &address_space_memory);
1284 }
1285
1286 static void whpx_handle_interrupt(CPUState *cpu, int mask)
1287 {
1288     cpu->interrupt_request |= mask;
1289
1290     if (!qemu_cpu_is_self(cpu)) {
1291         qemu_cpu_kick(cpu);
1292     }
1293 }
1294
1295 /*
1296  * Partition support
1297  */
1298
1299 static int whpx_accel_init(MachineState *ms)
1300 {
1301     struct whpx_state *whpx;
1302     int ret;
1303     HRESULT hr;
1304     WHV_CAPABILITY whpx_cap;
1305     UINT32 whpx_cap_size;
1306     WHV_PARTITION_PROPERTY prop;
1307
1308     whpx = &whpx_global;
1309
1310     if (!init_whp_dispatch()) {
1311         ret = -ENOSYS;
1312         goto error;
1313     }
1314
1315     memset(whpx, 0, sizeof(struct whpx_state));
1316     whpx->mem_quota = ms->ram_size;
1317
1318     hr = whp_dispatch.WHvGetCapability(
1319         WHvCapabilityCodeHypervisorPresent, &whpx_cap,
1320         sizeof(whpx_cap), &whpx_cap_size);
1321     if (FAILED(hr) || !whpx_cap.HypervisorPresent) {
1322         error_report("WHPX: No accelerator found, hr=%08lx", hr);
1323         ret = -ENOSPC;
1324         goto error;
1325     }
1326
1327     hr = whp_dispatch.WHvCreatePartition(&whpx->partition);
1328     if (FAILED(hr)) {
1329         error_report("WHPX: Failed to create partition, hr=%08lx", hr);
1330         ret = -EINVAL;
1331         goto error;
1332     }
1333
1334     memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
1335     prop.ProcessorCount = smp_cpus;
1336     hr = whp_dispatch.WHvSetPartitionProperty(
1337         whpx->partition,
1338         WHvPartitionPropertyCodeProcessorCount,
1339         &prop,
1340         sizeof(WHV_PARTITION_PROPERTY));
1341
1342     if (FAILED(hr)) {
1343         error_report("WHPX: Failed to set partition core count to %d,"
1344                      " hr=%08lx", smp_cores, hr);
1345         ret = -EINVAL;
1346         goto error;
1347     }
1348
1349     memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
1350     prop.ExtendedVmExits.X64CpuidExit = 1;
1351     hr = whp_dispatch.WHvSetPartitionProperty(
1352         whpx->partition,
1353         WHvPartitionPropertyCodeExtendedVmExits,
1354         &prop,
1355         sizeof(WHV_PARTITION_PROPERTY));
1356
1357     if (FAILED(hr)) {
1358         error_report("WHPX: Failed to enable partition extended X64CpuidExit"
1359                      " hr=%08lx", hr);
1360         ret = -EINVAL;
1361         goto error;
1362     }
1363
1364     UINT32 cpuidExitList[] = {1};
1365     hr = whp_dispatch.WHvSetPartitionProperty(
1366         whpx->partition,
1367         WHvPartitionPropertyCodeCpuidExitList,
1368         cpuidExitList,
1369         RTL_NUMBER_OF(cpuidExitList) * sizeof(UINT32));
1370     if (FAILED(hr)) {
1371         error_report("WHPX: Failed to set partition CpuidExitList hr=%08lx",
1372                      hr);
1373         ret = -EINVAL;
1374         goto error;
1375     }
1376
1377     hr = whp_dispatch.WHvSetupPartition(whpx->partition);
1378     if (FAILED(hr)) {
1379         error_report("WHPX: Failed to setup partition, hr=%08lx", hr);
1380         ret = -EINVAL;
1381         goto error;
1382     }
1383
1384     whpx_memory_init();
1385
1386     cpu_interrupt_handler = whpx_handle_interrupt;
1387
1388     printf("Windows Hypervisor Platform accelerator is operational\n");
1389     return 0;
1390
1391   error:
1392
1393     if (NULL != whpx->partition) {
1394         whp_dispatch.WHvDeletePartition(whpx->partition);
1395         whpx->partition = NULL;
1396     }
1397
1398
1399     return ret;
1400 }
1401
1402 int whpx_enabled(void)
1403 {
1404     return whpx_allowed;
1405 }
1406
1407 static void whpx_accel_class_init(ObjectClass *oc, void *data)
1408 {
1409     AccelClass *ac = ACCEL_CLASS(oc);
1410     ac->name = "WHPX";
1411     ac->init_machine = whpx_accel_init;
1412     ac->allowed = &whpx_allowed;
1413 }
1414
1415 static const TypeInfo whpx_accel_type = {
1416     .name = ACCEL_CLASS_NAME("whpx"),
1417     .parent = TYPE_ACCEL,
1418     .class_init = whpx_accel_class_init,
1419 };
1420
1421 static void whpx_type_init(void)
1422 {
1423     type_register_static(&whpx_accel_type);
1424 }
1425
1426 bool init_whp_dispatch(void)
1427 {
1428     const char *lib_name;
1429     HMODULE hLib;
1430
1431     if (whp_dispatch_initialized) {
1432         return true;
1433     }
1434
1435     #define WHP_LOAD_FIELD(return_type, function_name, signature) \
1436         whp_dispatch.function_name = \
1437             (function_name ## _t)GetProcAddress(hLib, #function_name); \
1438         if (!whp_dispatch.function_name) { \
1439             error_report("Could not load function %s from library %s.", \
1440                          #function_name, lib_name); \
1441             goto error; \
1442         } \
1443
1444     lib_name = "WinHvPlatform.dll";
1445     hWinHvPlatform = LoadLibrary(lib_name);
1446     if (!hWinHvPlatform) {
1447         error_report("Could not load library %s.", lib_name);
1448         goto error;
1449     }
1450     hLib = hWinHvPlatform;
1451     LIST_WINHVPLATFORM_FUNCTIONS(WHP_LOAD_FIELD)
1452
1453     lib_name = "WinHvEmulation.dll";
1454     hWinHvEmulation = LoadLibrary(lib_name);
1455     if (!hWinHvEmulation) {
1456         error_report("Could not load library %s.", lib_name);
1457         goto error;
1458     }
1459     hLib = hWinHvEmulation;
1460     LIST_WINHVEMULATION_FUNCTIONS(WHP_LOAD_FIELD)
1461
1462     whp_dispatch_initialized = true;
1463     return true;
1464
1465     error:
1466
1467     if (hWinHvPlatform) {
1468         FreeLibrary(hWinHvPlatform);
1469     }
1470     if (hWinHvEmulation) {
1471         FreeLibrary(hWinHvEmulation);
1472     }
1473     return false;
1474 }
1475
1476 type_init(whpx_type_init);
This page took 0.111683 seconds and 4 git commands to generate.