@samitouri / QOSamiQemu / commits / 2a9c0d0ac9

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