* [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes
@ 2026-03-23 22:34 Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 01/13] whpx: i386: workaround for Windows 10 support Mohamed Mediouni
` (12 more replies)
0 siblings, 13 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
On Windows 10, the paravirtualisation enlightenments aren't available.
And neither is performance monitoring. Using the former as a gate to
operate in a reduced-functionality mode on Windows 10.
And on the performance side, some state is really expensive to fetch
or write with Hyper-V so switch some less-essential state to on demand.
The effect of this is magnified on Windows 10 because Hyper-V enlightenments
are not available there.
v1 -> v2:
- fix x86 HVF compatibility
- small nits
- added workaround for an issue that showed up during 32-bit Linux boot
on AMD
Issue number: https://gitlab.com/qemu-project/qemu/-/work_items/3349
Mohamed Mediouni (13):
whpx: i386: workaround for Windows 10 support
whpx: i386: enable exceptions VM exit only when needed
whpx: i386: skip TSC read for MMIO exits
whpx: i386: skip XCRs read for MMIO exits
whpx: i386: don't restore segment registers after MMIO handling
target/i386: emulate: add new callbacks
whpx: i386: add implementation of new x86_emul_ops
target/i386: emulate: indirect access to CRs
whpx: i386: indirect access to CRs
target/i386: emulate: segmentation rework
whpx: i386: fetch segments on-demand
whpx: i386: workaround for segment granularity reading as 0
whpx: i386: fast runtime state reads
target/i386/emulate/x86_emu.h | 6 +
target/i386/emulate/x86_helpers.c | 83 +++++----
target/i386/emulate/x86_mmu.c | 11 +-
target/i386/hvf/x86.c | 11 ++
target/i386/whpx/whpx-all.c | 283 +++++++++++++++++++++++++-----
5 files changed, 305 insertions(+), 89 deletions(-)
--
2.50.1 (Apple Git-155)
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 01/13] whpx: i386: workaround for Windows 10 support
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 02/13] whpx: i386: enable exceptions VM exit only when needed Mohamed Mediouni
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
Windows Server 2022 and later support
WHvCapabilityCodeProcessorPerfmonFeatures and
WHvPartitionPropertyCodeSyntheticProcessorFeaturesBanks.
Windows 10 supports neither of those.
As the QEMU executable doesn't have a manifest, OS version
queries do not return the actual Windows version but 6.2.9200
which corresponds to Windows 8. Windows Server 2022 and Windows
11 still use the 10.0 number, with distinction being the build
number.
As such, use the absence of perf monitoring feature query as
a cutoff to detect if a legacy OS is present.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 43 ++++++++++++++++++++++++-------------
1 file changed, 28 insertions(+), 15 deletions(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 4d5d3dbd24..015c0f1dc9 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -1948,6 +1948,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
WHV_CAPABILITY_FEATURES features = {0};
WHV_PROCESSOR_FEATURES_BANKS processor_features;
WHV_PROCESSOR_PERFMON_FEATURES perfmon_features;
+ bool is_legacy_os = false;
whpx = &whpx_global;
@@ -2096,21 +2097,29 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
hr = whp_dispatch.WHvGetCapability(
WHvCapabilityCodeProcessorPerfmonFeatures, &perfmon_features,
sizeof(WHV_PROCESSOR_PERFMON_FEATURES), &whpx_cap_size);
+ /*
+ * Relying on this is a crutch to maintain Windows 10 support.
+ *
+ * WHvCapabilityCodeProcessorPerfmonFeatures and
+ * WHvPartitionPropertyCodeSyntheticProcessorFeaturesBanks
+ * are implemented starting from Windows Server 2022 (build 20348).
+ */
if (FAILED(hr)) {
- error_report("WHPX: Failed to get performance monitoring features, hr=%08lx", hr);
- ret = -ENOSPC;
- goto error;
- }
-
- hr = whp_dispatch.WHvSetPartitionProperty(
- whpx->partition,
- WHvPartitionPropertyCodeProcessorPerfmonFeatures,
- &perfmon_features,
- sizeof(WHV_PROCESSOR_PERFMON_FEATURES));
- if (FAILED(hr)) {
- error_report("WHPX: Failed to set performance monitoring features, hr=%08lx", hr);
- ret = -EINVAL;
- goto error;
+ warn_report("WHPX: Failed to get performance "
+ "monitoring features, hr=%08lx", hr);
+ is_legacy_os = true;
+ } else {
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeProcessorPerfmonFeatures,
+ &perfmon_features,
+ sizeof(WHV_PROCESSOR_PERFMON_FEATURES));
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to set performance "
+ "monitoring features, hr=%08lx", hr);
+ ret = -EINVAL;
+ goto error;
+ }
}
/* Enable synthetic processor features */
@@ -2138,7 +2147,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
synthetic_features.Bank0.DirectSyntheticTimers = 1;
}
- if (whpx->hyperv_enlightenments_allowed) {
+ if (!is_legacy_os && whpx->hyperv_enlightenments_allowed) {
hr = whp_dispatch.WHvSetPartitionProperty(
whpx->partition,
WHvPartitionPropertyCodeSyntheticProcessorFeaturesBanks,
@@ -2149,6 +2158,10 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
ret = -EINVAL;
goto error;
}
+ } else if (is_legacy_os && whpx->hyperv_enlightenments_required) {
+ error_report("Hyper-V enlightenments not available on legacy Windows");
+ ret = -EINVAL;
+ goto error;
}
/* Register for MSR and CPUID exits */
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 02/13] whpx: i386: enable exceptions VM exit only when needed
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 01/13] whpx: i386: workaround for Windows 10 support Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 03/13] whpx: i386: skip TSC read for MMIO exits Mohamed Mediouni
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
The exceptions VM exit was enabled with an empty bitmask
even when not used.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 015c0f1dc9..8f1835ee95 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -903,13 +903,31 @@ static void whpx_init_emu(void)
HRESULT whpx_set_exception_exit_bitmap(UINT64 exceptions)
{
struct whpx_state *whpx = &whpx_global;
- WHV_PARTITION_PROPERTY prop = { 0, };
+ WHV_PARTITION_PROPERTY prop;
HRESULT hr;
if (exceptions == whpx->exception_exit_bitmap) {
return S_OK;
}
+ /* Register for MSR and CPUID exits */
+ memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
+ prop.ExtendedVmExits.X64MsrExit = 1;
+ if (exceptions != 0) {
+ prop.ExtendedVmExits.ExceptionExit = 1;
+ }
+
+ hr = whp_dispatch.WHvSetPartitionProperty(
+ whpx->partition,
+ WHvPartitionPropertyCodeExtendedVmExits,
+ &prop,
+ sizeof(WHV_PARTITION_PROPERTY));
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to enable extended VM exits, hr=%08lx", hr);
+ return hr;
+ }
+
+ memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
prop.ExceptionExitBitmap = exceptions;
hr = whp_dispatch.WHvSetPartitionProperty(
@@ -2167,7 +2185,6 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
/* Register for MSR and CPUID exits */
memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
prop.ExtendedVmExits.X64MsrExit = 1;
- prop.ExtendedVmExits.ExceptionExit = 1;
hr = whp_dispatch.WHvSetPartitionProperty(
whpx->partition,
@@ -2175,7 +2192,7 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
&prop,
sizeof(WHV_PARTITION_PROPERTY));
if (FAILED(hr)) {
- error_report("WHPX: Failed to enable MSR & CPUIDexit, hr=%08lx", hr);
+ error_report("WHPX: Failed to enable extended VM exits, hr=%08lx", hr);
ret = -EINVAL;
goto error;
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 03/13] whpx: i386: skip TSC read for MMIO exits
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 01/13] whpx: i386: workaround for Windows 10 support Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 02/13] whpx: i386: enable exceptions VM exit only when needed Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 04/13] whpx: i386: skip XCRs " Mohamed Mediouni
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
The TSC value isn't needed for vmexit processing.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 8f1835ee95..ac03445d9d 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -606,7 +606,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
- if (!env->tsc_valid) {
+ if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && !env->tsc_valid) {
whpx_get_tsc(cpu);
env->tsc_valid = !runstate_is_running();
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 04/13] whpx: i386: skip XCRs read for MMIO exits
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
` (2 preceding siblings ...)
2026-03-23 22:34 ` [PATCH v2 03/13] whpx: i386: skip TSC read for MMIO exits Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 05/13] whpx: i386: don't restore segment registers after MMIO handling Mohamed Mediouni
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
The XCR0 value isn't currently needed for vmexit processing.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index ac03445d9d..c0c7ba9177 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -689,7 +689,9 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
* Extended control registers needs to be handled separately depending
* on whether xsave is supported/enabled or not.
*/
- whpx_get_xcrs(cpu);
+ if (level > WHPX_LEVEL_FAST_RUNTIME_STATE) {
+ whpx_get_xcrs(cpu);
+ }
/* 16 XMM registers */
assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 05/13] whpx: i386: don't restore segment registers after MMIO handling
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
` (3 preceding siblings ...)
2026-03-23 22:34 ` [PATCH v2 04/13] whpx: i386: skip XCRs " Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 06/13] target/i386: emulate: add new callbacks Mohamed Mediouni
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index c0c7ba9177..69d141e7cc 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -416,19 +416,21 @@ void whpx_set_registers(CPUState *cpu, WHPXStateLevel level)
assert(whpx_register_names[idx] == WHvX64RegisterRflags);
lflags_to_rflags(env);
vcxt.values[idx++].Reg64 = env->eflags;
-
- /* Translate 6+4 segment registers. HV and QEMU order matches */
assert(idx == WHvX64RegisterEs);
- for (i = 0; i < 6; i += 1, idx += 1) {
- vcxt.values[idx].Segment = whpx_seg_q2h(&env->segs[i], v86, r86);
- }
- assert(idx == WHvX64RegisterLdtr);
- /*
- * Skip those registers for synchronisation after MMIO accesses
- * as they're not going to be modified in that case.
- */
if (level > WHPX_LEVEL_FAST_RUNTIME_STATE) {
+
+ /* Translate 6+4 segment registers. HV and QEMU order matches */
+ for (i = 0; i < 6; i += 1, idx += 1) {
+ vcxt.values[idx].Segment = whpx_seg_q2h(&env->segs[i], v86, r86);
+ }
+
+ assert(idx == WHvX64RegisterLdtr);
+ /*
+ * Skip those registers for synchronisation after MMIO accesses
+ * as they're not going to be modified in that case.
+ */
+
vcxt.values[idx++].Segment = whpx_seg_q2h(&env->ldt, 0, 0);
assert(idx == WHvX64RegisterTr);
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 06/13] target/i386: emulate: add new callbacks
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
` (4 preceding siblings ...)
2026-03-23 22:34 ` [PATCH v2 05/13] whpx: i386: don't restore segment registers after MMIO handling Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 07/13] whpx: i386: add implementation of new x86_emul_ops Mohamed Mediouni
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
On Hyper-V fetching some guest registers is really expensive, so
add a way to query some state from information provided by Hyper-V
to save time on vmexits.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/emulate/x86_emu.h | 3 +++
target/i386/emulate/x86_helpers.c | 6 ++++++
target/i386/emulate/x86_mmu.c | 3 +++
3 files changed, 12 insertions(+)
diff --git a/target/i386/emulate/x86_emu.h b/target/i386/emulate/x86_emu.h
index 0f284b0c3d..4ed970bd53 100644
--- a/target/i386/emulate/x86_emu.h
+++ b/target/i386/emulate/x86_emu.h
@@ -32,6 +32,9 @@ struct x86_emul_ops {
int size, int count);
void (*simulate_rdmsr)(CPUState *cs);
void (*simulate_wrmsr)(CPUState *cs);
+ bool (*is_protected_mode)(CPUState *cpu);
+ bool (*is_long_mode)(CPUState *cpu);
+ bool (*is_user_mode)(CPUState *cpu);
};
extern const struct x86_emul_ops *emul_ops;
diff --git a/target/i386/emulate/x86_helpers.c b/target/i386/emulate/x86_helpers.c
index 024f9a2afc..ebbf40f2b0 100644
--- a/target/i386/emulate/x86_helpers.c
+++ b/target/i386/emulate/x86_helpers.c
@@ -211,6 +211,9 @@ bool x86_is_protected(CPUState *cpu)
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
uint64_t cr0 = env->cr[0];
+ if (emul_ops->is_protected_mode) {
+ return emul_ops->is_protected_mode(cpu);
+ }
return cr0 & CR0_PE_MASK;
}
@@ -234,6 +237,9 @@ bool x86_is_long_mode(CPUState *cpu)
uint64_t efer = env->efer;
uint64_t lme_lma = (MSR_EFER_LME | MSR_EFER_LMA);
+ if (emul_ops->is_long_mode) {
+ return emul_ops->is_long_mode(cpu);
+ }
return ((efer & lme_lma) == lme_lma);
}
diff --git a/target/i386/emulate/x86_mmu.c b/target/i386/emulate/x86_mmu.c
index 4e39bae025..670939acdb 100644
--- a/target/i386/emulate/x86_mmu.c
+++ b/target/i386/emulate/x86_mmu.c
@@ -49,6 +49,9 @@
static bool is_user(CPUState *cpu)
{
+ if (emul_ops->is_user_mode) {
+ return emul_ops->is_user_mode(cpu);
+ }
return false;
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 07/13] whpx: i386: add implementation of new x86_emul_ops
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
` (5 preceding siblings ...)
2026-03-23 22:34 ` [PATCH v2 06/13] target/i386: emulate: add new callbacks Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 08/13] target/i386: emulate: indirect access to CRs Mohamed Mediouni
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
target/i386/emulate now has new ops for fetching whether the guest is in
protected mode, long mode or user mode without fetching control
registers.
Use those for faster vmexits.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 69d141e7cc..b97dc9fd51 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -885,10 +885,32 @@ static void read_segment_descriptor(CPUState *cpu,
}
}
+static bool is_protected_mode(CPUState *cpu)
+{
+ AccelCPUState *vcpu = cpu->accel;
+
+ return vcpu->exit_ctx.VpContext.ExecutionState.Cr0Pe == 1;
+}
+
+static bool is_long_mode(CPUState *cpu)
+{
+ AccelCPUState *vcpu = cpu->accel;
+
+ return vcpu->exit_ctx.VpContext.ExecutionState.EferLma == 1;
+}
+
+static bool is_user_mode(CPUState *cpu)
+{
+ AccelCPUState *vcpu = cpu->accel;
+ return vcpu->exit_ctx.VpContext.ExecutionState.Cpl == 3;
+}
static const struct x86_emul_ops whpx_x86_emul_ops = {
.read_segment_descriptor = read_segment_descriptor,
- .handle_io = handle_io
+ .handle_io = handle_io,
+ .is_protected_mode = is_protected_mode,
+ .is_long_mode = is_long_mode,
+ .is_user_mode = is_user_mode
};
static void whpx_init_emu(void)
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 08/13] target/i386: emulate: indirect access to CRs
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
` (6 preceding siblings ...)
2026-03-23 22:34 ` [PATCH v2 07/13] whpx: i386: add implementation of new x86_emul_ops Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 09/13] whpx: i386: " Mohamed Mediouni
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
Prepare to have on-demand fetch of registers from the backend during
faults.
For x86_64 macOS, copy the function there too.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/emulate/x86_emu.h | 3 +++
target/i386/emulate/x86_helpers.c | 27 ++++++++++++++++-----------
target/i386/emulate/x86_mmu.c | 8 ++------
target/i386/hvf/x86.c | 11 +++++++++++
4 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/target/i386/emulate/x86_emu.h b/target/i386/emulate/x86_emu.h
index 4ed970bd53..a8d4c93098 100644
--- a/target/i386/emulate/x86_emu.h
+++ b/target/i386/emulate/x86_emu.h
@@ -28,6 +28,7 @@ struct x86_emul_ops {
MMUTranslateResult (*mmu_gva_to_gpa) (CPUState *cpu, target_ulong gva, uint64_t *gpa, MMUTranslateFlags flags);
void (*read_segment_descriptor)(CPUState *cpu, struct x86_segment_descriptor *desc,
enum X86Seg seg);
+ target_ulong (*read_cr) (CPUState *cpu, int cr);
void (*handle_io)(CPUState *cpu, uint16_t port, void *data, int direction,
int size, int count);
void (*simulate_rdmsr)(CPUState *cs);
@@ -45,6 +46,8 @@ void x86_emul_raise_exception(CPUX86State *env, int exception_index, int error_c
target_ulong read_reg(CPUX86State *env, int reg, int size);
void write_reg(CPUX86State *env, int reg, target_ulong val, int size);
+target_ulong x86_read_cr(CPUState *cpu, int cr);
+
target_ulong read_val_from_reg(void *reg_ptr, int size);
void write_val_to_reg(void *reg_ptr, target_ulong val, int size);
bool write_val_ext(CPUX86State *env, struct x86_decode_op *decode, target_ulong val, int size);
diff --git a/target/i386/emulate/x86_helpers.c b/target/i386/emulate/x86_helpers.c
index ebbf40f2b0..c817015ef9 100644
--- a/target/i386/emulate/x86_helpers.c
+++ b/target/i386/emulate/x86_helpers.c
@@ -206,15 +206,26 @@ bool x86_read_call_gate(CPUState *cpu, struct x86_call_gate *idt_desc,
return true;
}
-bool x86_is_protected(CPUState *cpu)
+target_ulong x86_read_cr(CPUState *cpu, int cr)
{
X86CPU *x86_cpu = X86_CPU(cpu);
CPUX86State *env = &x86_cpu->env;
- uint64_t cr0 = env->cr[0];
+
+ if (emul_ops->read_cr) {
+ return emul_ops->read_cr(cpu, cr);
+ }
+ return env->cr[cr];
+}
+
+bool x86_is_protected(CPUState *cpu)
+{
+ uint64_t cr0;
+
if (emul_ops->is_protected_mode) {
return emul_ops->is_protected_mode(cpu);
}
+ cr0 = x86_read_cr(cpu, 0);
return cr0 & CR0_PE_MASK;
}
@@ -245,9 +256,7 @@ bool x86_is_long_mode(CPUState *cpu)
bool x86_is_la57(CPUState *cpu)
{
- X86CPU *x86_cpu = X86_CPU(cpu);
- CPUX86State *env = &x86_cpu->env;
- uint64_t is_la57 = env->cr[4] & CR4_LA57_MASK;
+ uint64_t is_la57 = x86_read_cr(cpu, 4) & CR4_LA57_MASK;
return is_la57;
}
@@ -259,18 +268,14 @@ bool x86_is_long64_mode(CPUState *cpu)
bool x86_is_paging_mode(CPUState *cpu)
{
- X86CPU *x86_cpu = X86_CPU(cpu);
- CPUX86State *env = &x86_cpu->env;
- uint64_t cr0 = env->cr[0];
+ uint64_t cr0 = x86_read_cr(cpu, 0);
return cr0 & CR0_PG_MASK;
}
bool x86_is_pae_enabled(CPUState *cpu)
{
- X86CPU *x86_cpu = X86_CPU(cpu);
- CPUX86State *env = &x86_cpu->env;
- uint64_t cr4 = env->cr[4];
+ uint64_t cr4 = x86_read_cr(cpu, 4);
return cr4 & CR4_PAE_MASK;
}
diff --git a/target/i386/emulate/x86_mmu.c b/target/i386/emulate/x86_mmu.c
index 670939acdb..ba0ebe4268 100644
--- a/target/i386/emulate/x86_mmu.c
+++ b/target/i386/emulate/x86_mmu.c
@@ -114,8 +114,6 @@ static bool get_pt_entry(CPUState *cpu, struct gpt_translation *pt,
static MMUTranslateResult test_pt_entry(CPUState *cpu, struct gpt_translation *pt,
int level, int *largeness, bool pae, MMUTranslateFlags flags)
{
- X86CPU *x86_cpu = X86_CPU(cpu);
- CPUX86State *env = &x86_cpu->env;
uint64_t pte = pt->pte[level];
if (!pte_present(pte)) {
@@ -130,7 +128,7 @@ static MMUTranslateResult test_pt_entry(CPUState *cpu, struct gpt_translation *p
*largeness = level;
}
- uint32_t cr0 = env->cr[0];
+ uint32_t cr0 = x86_read_cr(cpu, 0);
/* check protection */
if (cr0 & CR0_WP_MASK) {
if (mmu_validate_write(flags) && !pte_write_access(pte)) {
@@ -184,11 +182,9 @@ static inline uint64_t large_page_gpa(struct gpt_translation *pt, bool pae,
static MMUTranslateResult walk_gpt(CPUState *cpu, target_ulong addr, MMUTranslateFlags flags,
struct gpt_translation *pt, bool pae)
{
- X86CPU *x86_cpu = X86_CPU(cpu);
- CPUX86State *env = &x86_cpu->env;
int top_level, level;
int largeness = 0;
- target_ulong cr3 = env->cr[3];
+ target_ulong cr3 = x86_read_cr(cpu, 3);
uint64_t page_mask = pae ? PAE_PTE_PAGE_MASK : LEGACY_PTE_PAGE_MASK;
MMUTranslateResult res;
diff --git a/target/i386/hvf/x86.c b/target/i386/hvf/x86.c
index 7fe710aca3..bae2f30fa2 100644
--- a/target/i386/hvf/x86.c
+++ b/target/i386/hvf/x86.c
@@ -143,6 +143,17 @@ bool x86_is_la57(CPUState *cpu)
return false;
}
+target_ulong x86_read_cr(CPUState *cpu, int cr)
+{
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+
+ if (emul_ops->read_cr) {
+ return emul_ops->read_cr(cpu, cr);
+ }
+ return env->cr[cr];
+}
+
bool x86_is_long64_mode(CPUState *cpu)
{
struct vmx_segment desc;
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 09/13] whpx: i386: indirect access to CRs
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
` (7 preceding siblings ...)
2026-03-23 22:34 ` [PATCH v2 08/13] target/i386: emulate: indirect access to CRs Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 10/13] target/i386: emulate: segmentation rework Mohamed Mediouni
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 32 +++++++++++++++++++++++++++++++-
1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index b97dc9fd51..71b33a632a 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -905,12 +905,42 @@ static bool is_user_mode(CPUState *cpu)
return vcpu->exit_ctx.VpContext.ExecutionState.Cpl == 3;
}
+static target_ulong read_cr(CPUState *cpu, int cr)
+{
+ WHV_REGISTER_NAME whv_cr;
+ WHV_REGISTER_VALUE val;
+
+ switch (cr) {
+ case 0:
+ whv_cr = WHvX64RegisterCr0;
+ break;
+ case 2:
+ whv_cr = WHvX64RegisterCr2;
+ break;
+ case 3:
+ whv_cr = WHvX64RegisterCr3;
+ break;
+ case 4:
+ whv_cr = WHvX64RegisterCr4;
+ break;
+ case 8:
+ whv_cr = WHvX64RegisterCr8;
+ break;
+ default:
+ abort();
+ }
+ whpx_get_reg(cpu, whv_cr, &val);
+
+ return val.Reg64;
+}
+
static const struct x86_emul_ops whpx_x86_emul_ops = {
.read_segment_descriptor = read_segment_descriptor,
.handle_io = handle_io,
.is_protected_mode = is_protected_mode,
.is_long_mode = is_long_mode,
- .is_user_mode = is_user_mode
+ .is_user_mode = is_user_mode,
+ .read_cr = read_cr
};
static void whpx_init_emu(void)
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 10/13] target/i386: emulate: segmentation rework
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
` (8 preceding siblings ...)
2026-03-23 22:34 ` [PATCH v2 09/13] whpx: i386: " Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 11/13] whpx: i386: fetch segments on-demand Mohamed Mediouni
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
Make accesses to segments all go through read_segment_descriptor
to be able to fetch segment state on-demand.
Switch away from SegmentCache to the x86_segment_descriptor
that is already used by read_segment_descriptor.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/emulate/x86_helpers.c | 50 ++++++++++++-------------------
1 file changed, 19 insertions(+), 31 deletions(-)
diff --git a/target/i386/emulate/x86_helpers.c b/target/i386/emulate/x86_helpers.c
index c817015ef9..63bae3582f 100644
--- a/target/i386/emulate/x86_helpers.c
+++ b/target/i386/emulate/x86_helpers.c
@@ -43,49 +43,37 @@ static CpuMode cpu_mode(CPUState *cpu)
return m;
}
-static bool segment_type_ro(const SegmentCache *seg)
+static bool segment_type_ro(const x86_segment_descriptor desc)
{
- uint32_t type_ = (seg->flags >> DESC_TYPE_SHIFT) & 15;
+ uint32_t type_ = desc.type;
return (type_ & (~RWRX_SEGMENT_TYPE)) == 0;
}
-static bool segment_type_code(const SegmentCache *seg)
+static bool segment_type_code(const x86_segment_descriptor desc)
{
- uint32_t type_ = (seg->flags >> DESC_TYPE_SHIFT) & 15;
+ uint32_t type_ = desc.type;
return (type_ & CODE_SEGMENT_TYPE) != 0;
}
-static bool segment_expands_down(const SegmentCache *seg)
+static bool segment_expands_down(const x86_segment_descriptor desc)
{
- uint32_t type_ = (seg->flags >> DESC_TYPE_SHIFT) & 15;
+ uint32_t type_ = desc.type;
- if (segment_type_code(seg)) {
+ if (segment_type_code(desc)) {
return false;
}
return (type_ & EXPAND_DOWN_SEGMENT_TYPE) != 0;
}
-static uint32_t segment_limit(const SegmentCache *seg)
+static uint8_t segment_db(const x86_segment_descriptor desc)
{
- uint32_t limit = seg->limit;
- uint32_t granularity = (seg->flags & DESC_G_MASK) != 0;
-
- if (granularity != 0) {
- limit = (limit << 12) | 0xFFF;
- }
-
- return limit;
+ return desc.db;
}
-static uint8_t segment_db(const SegmentCache *seg)
+static uint32_t segment_max_limit(const x86_segment_descriptor desc)
{
- return (seg->flags >> DESC_B_SHIFT) & 1;
-}
-
-static uint32_t segment_max_limit(const SegmentCache *seg)
-{
- if (segment_db(seg) != 0) {
+ if (segment_db(desc) != 0) {
return 0xFFFFFFFF;
}
return 0xFFFF;
@@ -96,15 +84,15 @@ static int linearize(CPUState *cpu,
X86Seg seg_idx)
{
enum CpuMode mode;
- X86CPU *x86_cpu = X86_CPU(cpu);
- CPUX86State *env = &x86_cpu->env;
- SegmentCache *seg = &env->segs[seg_idx];
- target_ulong base = seg->base;
+ struct x86_segment_descriptor desc;
+ target_ulong base;
target_ulong logical_addr_32b;
uint32_t limit;
/* TODO: the emulator will not pass us "write" indicator yet */
bool write = false;
+ emul_ops->read_segment_descriptor(cpu, &desc, seg_idx);
+ base = x86_segment_base(&desc);
mode = cpu_mode(cpu);
switch (mode) {
@@ -116,21 +104,21 @@ static int linearize(CPUState *cpu,
break;
case PROTECTED_MODE:
case REAL_MODE:
- if (segment_type_ro(seg) && write) {
+ if (segment_type_ro(desc) && write) {
error_report("Cannot write to read-only segment");
return -1;
}
logical_addr_32b = logical_addr & 0xFFFFFFFF;
- limit = segment_limit(seg);
+ limit = x86_segment_limit(&desc);
- if (segment_expands_down(seg)) {
+ if (segment_expands_down(desc)) {
if (logical_addr_32b >= limit) {
error_report("Address exceeds limit (expands down)");
return -1;
}
- limit = segment_max_limit(seg);
+ limit = segment_max_limit(desc);
}
if (logical_addr_32b > limit) {
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 11/13] whpx: i386: fetch segments on-demand
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
` (9 preceding siblings ...)
2026-03-23 22:34 ` [PATCH v2 10/13] target/i386: emulate: segmentation rework Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 12/13] whpx: i386: workaround for segment granularity reading as 0 Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 13/13] whpx: i386: fast runtime state reads Mohamed Mediouni
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
Instead of save/restore, fetch segments dynamically.
Rely on the fetched state instead of loading from memory.
Or, if available, on the VM exit context.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 55 +++++++++++++++++++++++++++++--------
1 file changed, 44 insertions(+), 11 deletions(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index 71b33a632a..f278a52451 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -868,21 +868,54 @@ static int whpx_handle_portio(CPUState *cpu,
return 0;
}
+static void whpx_segment_to_x86_descriptor(CPUState *cpu, WHV_X64_SEGMENT_REGISTER* reg,
+ struct x86_segment_descriptor *desc)
+{
+ x86_set_segment_limit(desc, reg->Limit);
+ x86_set_segment_base(desc, reg->Base);
+
+ desc->type = reg->SegmentType;
+ desc->s = reg->NonSystemSegment;
+ desc->dpl = reg->DescriptorPrivilegeLevel;
+ desc->p = reg->Present;
+ desc->avl = reg->Available;
+ desc->l = reg->Long;
+ desc->db = reg->Default;
+ desc->g = reg->Granularity;
+}
+
+static void whpx_read_segment_descriptor(CPUState *cpu, WHV_X64_SEGMENT_REGISTER* reg,
+ X86Seg seg)
+{
+ AccelCPUState *vcpu = cpu->accel;
+ WHV_REGISTER_NAME reg_name = WHvX64RegisterEs + seg;
+ WHV_REGISTER_VALUE val;
+
+ if (seg == R_CS) {
+ *reg = vcpu->exit_ctx.VpContext.Cs;
+ return;
+ }
+ if (vcpu->exit_ctx.ExitReason == WHvRunVpExitReasonX64IoPortAccess) {
+ if (seg == R_DS) {
+ *reg = vcpu->exit_ctx.IoPortAccess.Ds;
+ return;
+ } else if (seg == R_ES) {
+ *reg = vcpu->exit_ctx.IoPortAccess.Es;
+ return;
+ }
+ }
+
+ whpx_get_reg(cpu, reg_name, &val);
+ *reg = val.Segment;
+}
+
static void read_segment_descriptor(CPUState *cpu,
struct x86_segment_descriptor *desc,
enum X86Seg seg_idx)
{
- bool ret;
- X86CPU *x86_cpu = X86_CPU(cpu);
- CPUX86State *env = &x86_cpu->env;
- SegmentCache *seg = &env->segs[seg_idx];
- x86_segment_selector sel = { .sel = seg->selector & 0xFFFF };
-
- ret = x86_read_segment_descriptor(cpu, desc, sel);
- if (ret == false) {
- error_report("failed to read segment descriptor");
- abort();
- }
+ WHV_X64_SEGMENT_REGISTER reg;
+ whpx_read_segment_descriptor(cpu, ®, seg_idx);
+ whpx_segment_to_x86_descriptor(cpu, ®, desc);
}
static bool is_protected_mode(CPUState *cpu)
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 12/13] whpx: i386: workaround for segment granularity reading as 0
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
` (10 preceding siblings ...)
2026-03-23 22:34 ` [PATCH v2 11/13] whpx: i386: fetch segments on-demand Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 13/13] whpx: i386: fast runtime state reads Mohamed Mediouni
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
OS boot triggers a Cs segment limit assertion, while
Hyper-V reports that Granularity = 0 despite the
limit being 0xffffffff.
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr>
---
target/i386/whpx/whpx-all.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index f278a52451..d87afceb08 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -916,6 +916,25 @@ static void read_segment_descriptor(CPUState *cpu,
WHV_X64_SEGMENT_REGISTER reg;
whpx_read_segment_descriptor(cpu, ®, seg_idx);
whpx_segment_to_x86_descriptor(cpu, ®, desc);
+
+ /*
+ * Workaround: vcpu->exit_ctx.VpContext.Cs.Granularity is 0...
+ *
+ * OS boot triggers a Cs segment limit assertion, while
+ * Hyper-V reports that Granularity = 0 despite the
+ * limit being 0xffffffff.
+ *
+ * This particular issue is much easier to trigger with
+ * the instruction_stream logic disabled. With that enabled,
+ * plenty of guests boot just fine as they don't trigger the
+ * immediate in CS read from a trapped instruction case.
+ *
+ * However, 32-bit Linux on AMD triggers specifically in
+ * https://lore.kernel.org/20250422234830.2840784-6-superm1@kernel.org
+ */
+ if (seg_idx == R_CS) {
+ desc->g = 1;
+ }
}
static bool is_protected_mode(CPUState *cpu)
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v2 13/13] whpx: i386: fast runtime state reads
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
` (11 preceding siblings ...)
2026-03-23 22:34 ` [PATCH v2 12/13] whpx: i386: workaround for segment granularity reading as 0 Mohamed Mediouni
@ 2026-03-23 22:34 ` Mohamed Mediouni
12 siblings, 0 replies; 14+ messages in thread
From: Mohamed Mediouni @ 2026-03-23 22:34 UTC (permalink / raw)
To: qemu-devel
Cc: Roman Bolshakov, Wei Liu, Pedro Barbuda, Mohamed Mediouni,
Phil Dennis-Jordan
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>
---
target/i386/whpx/whpx-all.c | 77 +++++++++++++++++++++++++++++++++----
1 file changed, 70 insertions(+), 7 deletions(-)
diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c
index d87afceb08..ff842bf359 100644
--- a/target/i386/whpx/whpx-all.c
+++ b/target/i386/whpx/whpx-all.c
@@ -156,6 +156,26 @@ static const WHV_REGISTER_NAME whpx_register_names[] = {
*/
};
+static const WHV_REGISTER_NAME whpx_register_names_for_vmexit[] = {
+ /* X64 General purpose registers */
+ WHvX64RegisterRax,
+ WHvX64RegisterRcx,
+ WHvX64RegisterRdx,
+ WHvX64RegisterRbx,
+ WHvX64RegisterRsp,
+ WHvX64RegisterRbp,
+ WHvX64RegisterRsi,
+ WHvX64RegisterRdi,
+ WHvX64RegisterR8,
+ WHvX64RegisterR9,
+ WHvX64RegisterR10,
+ WHvX64RegisterR11,
+ WHvX64RegisterR12,
+ WHvX64RegisterR13,
+ WHvX64RegisterR14,
+ WHvX64RegisterR15,
+};
+
struct whpx_register_set {
WHV_REGISTER_VALUE values[RTL_NUMBER_OF(whpx_register_names)];
};
@@ -593,6 +613,47 @@ static void whpx_get_xcrs(CPUState *cpu)
cpu_env(cpu)->xcr0 = xcr0.Reg64;
}
+static void whpx_get_registers_for_vmexit(CPUState *cpu, WHPXStateLevel level)
+{
+ struct whpx_state *whpx = &whpx_global;
+ AccelCPUState *vcpu = cpu->accel;
+ X86CPU *x86_cpu = X86_CPU(cpu);
+ CPUX86State *env = &x86_cpu->env;
+ struct whpx_register_set vcxt;
+ HRESULT hr;
+ int idx;
+ int idx_next;
+
+ assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
+
+ hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
+ whpx->partition, cpu->cpu_index,
+ whpx_register_names_for_vmexit,
+ RTL_NUMBER_OF(whpx_register_names_for_vmexit),
+ &vcxt.values[0]);
+ if (FAILED(hr)) {
+ error_report("WHPX: Failed to get virtual processor context, hr=%08lx",
+ hr);
+ }
+
+ idx = 0;
+
+ /* Indexes for first 16 registers match between HV and QEMU definitions */
+ idx_next = 16;
+ for (idx = 0; idx < CPU_NB_REGS; idx += 1) {
+ env->regs[idx] = vcxt.values[idx].Reg64;
+ }
+ idx = idx_next;
+
+ env->eip = vcpu->exit_ctx.VpContext.Rip;
+ env->eflags = vcpu->exit_ctx.VpContext.Rflags;
+ rflags_to_lflags(env);
+
+ assert(idx == RTL_NUMBER_OF(whpx_register_names_for_vmexit));
+
+ x86_update_hflags(env);
+}
+
void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
{
struct whpx_state *whpx = &whpx_global;
@@ -608,7 +669,11 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
- if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && !env->tsc_valid) {
+ if (level == WHPX_LEVEL_FAST_RUNTIME_STATE) {
+ return whpx_get_registers_for_vmexit(cpu, level);
+ }
+
+ if (!env->tsc_valid) {
whpx_get_tsc(cpu);
env->tsc_valid = !runstate_is_running();
}
@@ -623,7 +688,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
hr);
}
- if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && whpx_irqchip_in_kernel()) {
+ if (whpx_irqchip_in_kernel()) {
/*
* Fetch the TPR value from the emulated APIC. It may get overwritten
* below with the value from CR8 returned by
@@ -680,7 +745,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
env->cr[4] = vcxt.values[idx++].Reg64;
assert(whpx_register_names[idx] == WHvX64RegisterCr8);
tpr = vcxt.values[idx++].Reg64;
- if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && tpr != vcpu->tpr) {
+ if (tpr != vcpu->tpr) {
vcpu->tpr = tpr;
cpu_set_apic_tpr(x86_cpu->apic_state, whpx_cr8_to_apic_tpr(tpr));
}
@@ -691,9 +756,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
* Extended control registers needs to be handled separately depending
* on whether xsave is supported/enabled or not.
*/
- if (level > WHPX_LEVEL_FAST_RUNTIME_STATE) {
- whpx_get_xcrs(cpu);
- }
+ whpx_get_xcrs(cpu);
/* 16 XMM registers */
assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
@@ -768,7 +831,7 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
assert(idx == RTL_NUMBER_OF(whpx_register_names));
- if (level > WHPX_LEVEL_FAST_RUNTIME_STATE && whpx_irqchip_in_kernel()) {
+ if (whpx_irqchip_in_kernel()) {
whpx_apic_get(x86_cpu->apic_state);
}
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-03-23 22:37 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-23 22:34 [PATCH v2 00/13] whpx: i386: Windows 10 and performance fixes Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 01/13] whpx: i386: workaround for Windows 10 support Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 02/13] whpx: i386: enable exceptions VM exit only when needed Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 03/13] whpx: i386: skip TSC read for MMIO exits Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 04/13] whpx: i386: skip XCRs " Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 05/13] whpx: i386: don't restore segment registers after MMIO handling Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 06/13] target/i386: emulate: add new callbacks Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 07/13] whpx: i386: add implementation of new x86_emul_ops Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 08/13] target/i386: emulate: indirect access to CRs Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 09/13] whpx: i386: " Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 10/13] target/i386: emulate: segmentation rework Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 11/13] whpx: i386: fetch segments on-demand Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 12/13] whpx: i386: workaround for segment granularity reading as 0 Mohamed Mediouni
2026-03-23 22:34 ` [PATCH v2 13/13] whpx: i386: fast runtime state reads Mohamed Mediouni
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox