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