whpx: i386: saving/restoring less state for WHPX_LEVEL_FAST_RUNTIME_STATE
Optimise vmexits by save/restoring less state in those cases instead of the full state. Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Reviewed-by: Bernhard Beschow <shentey@gmail.com> Link: https://lore.kernel.org/r/20260223233950.96076-17-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Mohamed Mediouni committed
Feb 24, 2026 at 00:39 UTC
2a9c0d0ac964e8763d9f64d84cee9872a832f283
1 file changed
+104
-98
target/i386/whpx/whpx-all.c
+104
-98
@@ -422,118 +422,124 @@ void whpx_set_registers(CPUState *cpu, WHPXStateLevel level)
422
}
423
424
assert(idx == WHvX64RegisterLdtr);
425
- vcxt.values[idx++].Segment = whpx_seg_q2h(&env->ldt, 0, 0);
426
-
427
- assert(idx == WHvX64RegisterTr);
428
- vcxt.values[idx++].Segment = whpx_seg_q2h(&env->tr, 0, 0);
429
-
430
- assert(idx == WHvX64RegisterIdtr);
431
- vcxt.values[idx].Table.Base = env->idt.base;
432
- vcxt.values[idx].Table.Limit = env->idt.limit;
433
- idx += 1;
434
-
435
- assert(idx == WHvX64RegisterGdtr);
436
- vcxt.values[idx].Table.Base = env->gdt.base;
437
- vcxt.values[idx].Table.Limit = env->gdt.limit;
438
- idx += 1;
439
-
440
- /* CR0, 2, 3, 4, 8 */
441
- assert(whpx_register_names[idx] == WHvX64RegisterCr0);
442
- vcxt.values[idx++].Reg64 = env->cr[0];
443
- assert(whpx_register_names[idx] == WHvX64RegisterCr2);
444
- vcxt.values[idx++].Reg64 = env->cr[2];
445
- assert(whpx_register_names[idx] == WHvX64RegisterCr3);
446
- vcxt.values[idx++].Reg64 = env->cr[3];
447
- assert(whpx_register_names[idx] == WHvX64RegisterCr4);
448
- vcxt.values[idx++].Reg64 = env->cr[4];
449
- assert(whpx_register_names[idx] == WHvX64RegisterCr8);
450
- vcxt.values[idx++].Reg64 = vcpu->tpr;
451
-
452
- /* 8 Debug Registers - Skipped */
453
-
425
/*
455
- * Extended control registers needs to be handled separately depending
456
- * on whether xsave is supported/enabled or not.
426
+ * Skip those registers for synchronisation after MMIO accesses
427
+ * as they're not going to be modified in that case.
428
*/
458
- whpx_set_xcrs(cpu);
459
-
460
- /* 16 XMM registers */
461
- assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
462
- idx_next = idx + 16;
463
- for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
464
- vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);
465
- vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);
466
- }
467
- idx = idx_next;
468
-
469
- /* 8 FP registers */
470
- assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
471
- for (i = 0; i < 8; i += 1, idx += 1) {
472
- vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0);
473
- /* vcxt.values[idx].Fp.AsUINT128.High64 =
474
- env->fpregs[i].mmx.MMX_Q(1);
475
- */
476
- }
429
+ if (level > WHPX_LEVEL_FAST_RUNTIME_STATE) {
430
+ vcxt.values[idx++].Segment = whpx_seg_q2h(&env->ldt, 0, 0);
431
+
432
+ assert(idx == WHvX64RegisterTr);
433
+ vcxt.values[idx++].Segment = whpx_seg_q2h(&env->tr, 0, 0);
434
+
435
+ assert(idx == WHvX64RegisterIdtr);
436
+ vcxt.values[idx].Table.Base = env->idt.base;
437
+ vcxt.values[idx].Table.Limit = env->idt.limit;
438
+ idx += 1;
439
+
440
+ assert(idx == WHvX64RegisterGdtr);
441
+ vcxt.values[idx].Table.Base = env->gdt.base;
442
+ vcxt.values[idx].Table.Limit = env->gdt.limit;
443
+ idx += 1;
444
+
445
+ /* CR0, 2, 3, 4, 8 */
446
+ assert(whpx_register_names[idx] == WHvX64RegisterCr0);
447
+ vcxt.values[idx++].Reg64 = env->cr[0];
448
+ assert(whpx_register_names[idx] == WHvX64RegisterCr2);
449
+ vcxt.values[idx++].Reg64 = env->cr[2];
450
+ assert(whpx_register_names[idx] == WHvX64RegisterCr3);
451
+ vcxt.values[idx++].Reg64 = env->cr[3];
452
+ assert(whpx_register_names[idx] == WHvX64RegisterCr4);
453
+ vcxt.values[idx++].Reg64 = env->cr[4];
454
+ assert(whpx_register_names[idx] == WHvX64RegisterCr8);
455
+ vcxt.values[idx++].Reg64 = vcpu->tpr;
456
+
457
+ /* 8 Debug Registers - Skipped */
458
478
- /* FP control status register */
479
- assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);
480
- vcxt.values[idx].FpControlStatus.FpControl = env->fpuc;
481
- vcxt.values[idx].FpControlStatus.FpStatus =
482
- (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
483
- vcxt.values[idx].FpControlStatus.FpTag = 0;
484
- for (i = 0; i < 8; ++i) {
485
- vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i;
486
- }
487
- vcxt.values[idx].FpControlStatus.Reserved = 0;
488
- vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop;
489
- vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip;
490
- idx += 1;
491
-
492
- /* XMM control status register */
493
- assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);
494
- vcxt.values[idx].XmmControlStatus.LastFpRdp = 0;
495
- vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr;
496
- vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff;
497
- idx += 1;
459
+ /*
460
+ * Extended control registers needs to be handled separately depending
461
+ * on whether xsave is supported/enabled or not.
462
+ */
463
+ whpx_set_xcrs(cpu);
464
+
465
+ /* 16 XMM registers */
466
+ assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
467
+ idx_next = idx + 16;
468
+ for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
469
+ vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);
470
+ vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);
471
+ }
472
+ idx = idx_next;
473
+
474
+ /* 8 FP registers */
475
+ assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
476
+ for (i = 0; i < 8; i += 1, idx += 1) {
477
+ vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0);
478
+ /* vcxt.values[idx].Fp.AsUINT128.High64 =
479
+ env->fpregs[i].mmx.MMX_Q(1);
480
+ */
481
+ }
482
499
- /* MSRs */
500
- assert(whpx_register_names[idx] == WHvX64RegisterEfer);
501
- vcxt.values[idx++].Reg64 = env->efer;
483
+ /* FP control status register */
484
+ assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);
485
+ vcxt.values[idx].FpControlStatus.FpControl = env->fpuc;
486
+ vcxt.values[idx].FpControlStatus.FpStatus =
487
+ (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
488
+ vcxt.values[idx].FpControlStatus.FpTag = 0;
489
+ for (i = 0; i < 8; ++i) {
490
+ vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i;
491
+ }
492
+ vcxt.values[idx].FpControlStatus.Reserved = 0;
493
+ vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop;
494
+ vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip;
495
+ idx += 1;
496
+
497
+ /* XMM control status register */
498
+ assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);
499
+ vcxt.values[idx].XmmControlStatus.LastFpRdp = 0;
500
+ vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr;
501
+ vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff;
502
+ idx += 1;
503
+
504
+ /* MSRs */
505
+ assert(whpx_register_names[idx] == WHvX64RegisterEfer);
506
+ vcxt.values[idx++].Reg64 = env->efer;
507
#ifdef TARGET_X86_64
503
- assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase);
504
- vcxt.values[idx++].Reg64 = env->kernelgsbase;
508
+ assert(whpx_register_names[idx] == WHvX64RegisterKernelGsBase);
509
+ vcxt.values[idx++].Reg64 = env->kernelgsbase;
510
#endif
511
507
- assert(whpx_register_names[idx] == WHvX64RegisterApicBase);
508
- vcxt.values[idx++].Reg64 = vcpu->apic_base;
512
+ assert(whpx_register_names[idx] == WHvX64RegisterApicBase);
513
+ vcxt.values[idx++].Reg64 = vcpu->apic_base;
514
510
- /* WHvX64RegisterPat - Skipped */
515
+ /* WHvX64RegisterPat - Skipped */
516
512
- assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs);
513
- vcxt.values[idx++].Reg64 = env->sysenter_cs;
514
- assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip);
515
- vcxt.values[idx++].Reg64 = env->sysenter_eip;
516
- assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp);
517
- vcxt.values[idx++].Reg64 = env->sysenter_esp;
518
- assert(whpx_register_names[idx] == WHvX64RegisterStar);
519
- vcxt.values[idx++].Reg64 = env->star;
517
+ assert(whpx_register_names[idx] == WHvX64RegisterSysenterCs);
518
+ vcxt.values[idx++].Reg64 = env->sysenter_cs;
519
+ assert(whpx_register_names[idx] == WHvX64RegisterSysenterEip);
520
+ vcxt.values[idx++].Reg64 = env->sysenter_eip;
521
+ assert(whpx_register_names[idx] == WHvX64RegisterSysenterEsp);
522
+ vcxt.values[idx++].Reg64 = env->sysenter_esp;
523
+ assert(whpx_register_names[idx] == WHvX64RegisterStar);
524
+ vcxt.values[idx++].Reg64 = env->star;
525
#ifdef TARGET_X86_64
521
- assert(whpx_register_names[idx] == WHvX64RegisterLstar);
522
- vcxt.values[idx++].Reg64 = env->lstar;
523
- assert(whpx_register_names[idx] == WHvX64RegisterCstar);
524
- vcxt.values[idx++].Reg64 = env->cstar;
525
- assert(whpx_register_names[idx] == WHvX64RegisterSfmask);
526
- vcxt.values[idx++].Reg64 = env->fmask;
526
+ assert(whpx_register_names[idx] == WHvX64RegisterLstar);
527
+ vcxt.values[idx++].Reg64 = env->lstar;
528
+ assert(whpx_register_names[idx] == WHvX64RegisterCstar);
529
+ vcxt.values[idx++].Reg64 = env->cstar;
530
+ assert(whpx_register_names[idx] == WHvX64RegisterSfmask);
531
+ vcxt.values[idx++].Reg64 = env->fmask;
532
#endif
533
529
- /* Interrupt / Event Registers - Skipped */
534
+ /* Interrupt / Event Registers - Skipped */
535
531
- assert(idx == RTL_NUMBER_OF(whpx_register_names));
536
+ assert(idx == RTL_NUMBER_OF(whpx_register_names));
537
+ }
538
539
hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
540
whpx->partition, cpu->cpu_index,
541
whpx_register_names,
536
- RTL_NUMBER_OF(whpx_register_names),
542
+ idx,
543
&vcxt.values[0]);
544
545
if (FAILED(hr)) {
@@ -613,7 +619,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
619
hr);
620
}
621
616
- if (whpx_irqchip_in_kernel()) {
622
+ if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && whpx_irqchip_in_kernel()) {
623
/*
624
* Fetch the TPR value from the emulated APIC. It may get overwritten
625
* below with the value from CR8 returned by
@@ -670,7 +676,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
676
env->cr[4] = vcxt.values[idx++].Reg64;
677
assert(whpx_register_names[idx] == WHvX64RegisterCr8);
678
tpr = vcxt.values[idx++].Reg64;
673
- if (tpr != vcpu->tpr) {
679
+ if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && tpr != vcpu->tpr) {
680
vcpu->tpr = tpr;
681
cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(tpr));
682
}
@@ -756,7 +762,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
762
763
assert(idx == RTL_NUMBER_OF(whpx_register_names));
764
759
- if (whpx_irqchip_in_kernel()) {
765
+ if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && whpx_irqchip_in_kernel()) {
766
whpx_apic_get(x86_cpu->apic_state);
767
}
768