@samitouri / QOSamiQemu / commits / 378b1fdb1a

whpx: i386: fast runtime state reads

Now that there's an on-demand interface for fetching CRs and segments, only query GPRs and query everything else on-demand for vmexits. Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Link: https://lore.kernel.org/r/20260324151323.74473-13-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Mohamed Mediouni committed Mar 24, 2026 at 16:13 UTC 378b1fdb1a423b61e1f8fc6d80dd1832d2fd4f3f
1 file changed +70 -7
target/i386/whpx/whpx-all.c
+70 -7
@@ -156,6 +156,26 @@ static const WHV_REGISTER_NAME whpx_register_names[] = {
156 */
157 };
158
159 +static const WHV_REGISTER_NAME whpx_register_names_for_vmexit[] = {
160 + /* X64 General purpose registers */
161 + WHvX64RegisterRax,
162 + WHvX64RegisterRcx,
163 + WHvX64RegisterRdx,
164 + WHvX64RegisterRbx,
165 + WHvX64RegisterRsp,
166 + WHvX64RegisterRbp,
167 + WHvX64RegisterRsi,
168 + WHvX64RegisterRdi,
169 + WHvX64RegisterR8,
170 + WHvX64RegisterR9,
171 + WHvX64RegisterR10,
172 + WHvX64RegisterR11,
173 + WHvX64RegisterR12,
174 + WHvX64RegisterR13,
175 + WHvX64RegisterR14,
176 + WHvX64RegisterR15,
177 +};
178 +
179 struct whpx_register_set {
180 WHV_REGISTER_VALUE values[RTL_NUMBER_OF(whpx_register_names)];
181 };
@@ -593,6 +613,47 @@ static void whpx_get_xcrs(CPUState *cpu)
613 cpu_env(cpu)->xcr0 = xcr0.Reg64;
614 }
615
616 +static void whpx_get_registers_for_vmexit(CPUState *cpu, WHPXStateLevel level)
617 +{
618 + struct whpx_state *whpx = &whpx_global;
619 + AccelCPUState *vcpu = cpu->accel;
620 + X86CPU *x86_cpu = X86_CPU(cpu);
621 + CPUX86State *env = &x86_cpu->env;
622 + struct whpx_register_set vcxt;
623 + HRESULT hr;
624 + int idx;
625 + int idx_next;
626 +
627 + assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
628 +
629 + hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
630 + whpx->partition, cpu->cpu_index,
631 + whpx_register_names_for_vmexit,
632 + RTL_NUMBER_OF(whpx_register_names_for_vmexit),
633 + &vcxt.values[0]);
634 + if (FAILED(hr)) {
635 + error_report("WHPX: Failed to get virtual processor context, hr=%08lx",
636 + hr);
637 + }
638 +
639 + idx = 0;
640 +
641 + /* Indexes for first 16 registers match between HV and QEMU definitions */
642 + idx_next = 16;
643 + for (idx = 0; idx < CPU_NB_REGS; idx += 1) {
644 + env->regs[idx] = vcxt.values[idx].Reg64;
645 + }
646 + idx = idx_next;
647 +
648 + env->eip = vcpu->exit_ctx.VpContext.Rip;
649 + env->eflags = vcpu->exit_ctx.VpContext.Rflags;
650 + rflags_to_lflags(env);
651 +
652 + assert(idx == RTL_NUMBER_OF(whpx_register_names_for_vmexit));
653 +
654 + x86_update_hflags(env);
655 +}
656 +
657 void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
658 {
659 struct whpx_state *whpx = &whpx_global;
@@ -608,7 +669,11 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
669
670 assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
671
611 - if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && !env->tsc_valid) {
672 + if (level == WHPX_LEVEL_FAST_RUNTIME_STATE) {
673 + return whpx_get_registers_for_vmexit(cpu, level);
674 + }
675 +
676 + if (!env->tsc_valid) {
677 whpx_get_tsc(cpu);
678 env->tsc_valid = !runstate_is_running();
679 }
@@ -623,7 +688,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
688 hr);
689 }
690
626 - if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && whpx_irqchip_in_kernel()) {
691 + if (whpx_irqchip_in_kernel()) {
692 /*
693 * Fetch the TPR value from the emulated APIC. It may get overwritten
694 * below with the value from CR8 returned by
@@ -680,7 +745,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
745 env->cr[4] = vcxt.values[idx++].Reg64;
746 assert(whpx_register_names[idx] == WHvX64RegisterCr8);
747 tpr = vcxt.values[idx++].Reg64;
683 - if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && tpr != vcpu->tpr) {
748 + if (tpr != vcpu->tpr) {
749 vcpu->tpr = tpr;
750 cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(tpr));
751 }
@@ -691,9 +756,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
756 * Extended control registers needs to be handled separately depending
757 * on whether xsave is supported/enabled or not.
758 */
694 - if (level > WHPX_LEVEL_FAST_RUNTIME_STATE) {
695 - whpx_get_xcrs(cpu);
696 - }
759 + whpx_get_xcrs(cpu);
760
761 /* 16 XMM registers */
762 assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
@@ -768,7 +831,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
831
832 assert(idx == RTL_NUMBER_OF(whpx_register_names));
833
771 - if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && whpx_irqchip_in_kernel()) {
834 + if (whpx_irqchip_in_kernel()) {
835 whpx_apic_get(x86_cpu->apic_state);
836 }
837