* [PATCH v3 hci-8.0/hci-8.1 1/6] i386/pc: raise the limit of compat arrays per Virtuozzo machine type to four #VSTOR-152264
2026-10-29 12:25 [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264 Denis V. Lunev
@ 2026-10-29 12:25 ` Denis V. Lunev
2026-10-29 12:27 ` no-reply
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 2/6] i386: keep hle and rtm on Virtuozzo machine types up to vz9.2.0 #PSBM-149402 Denis V. Lunev
` (5 subsequent siblings)
6 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2026-10-29 12:25 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: svt-core, den
From: Denis V. Lunev <den@openvz.org>
A row of VZ_Q35_MT or VZ_PC_MT can name at most three compat arrays:
COUNT_ARGS counts up to three, VZ_COMPATS_EXPAND has variants for zero
to three, and __vz_compat_props has three slots per row. No row needs
more yet, which is why the limit never showed. The i440fx vz7.16.0 row
uses all three (hw_compat_vz_9_1, hw_compat_vz_7_16,
pc_vz_7_16_compat), and the next commit adds pc_vz_9_2_compat to it.
With a fourth argument COUNT_ARGS returns that argument instead of a
count, and the build fails on an undefined VZ_COMPATS_EXPAND_<name>.
Raise the limit to four.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
---
hw/i386/pc_piix.c | 2 +-
hw/i386/pc_q35.c | 2 +-
include/hw/i386/pc.h | 7 +++++--
3 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 9a73dcfad4b..1a50c2a645c 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -1087,7 +1087,7 @@ enum {
static struct {
GlobalProperty *prop;
const size_t *len;
-} __vz_compat_props[][3] = {
+} __vz_compat_props[][4] = {
{ VZ_COMPATS_EXPAND(hw_compat_vz, pc_vz_compat) },
VZ_PC_MT(AS_ARRAY)
};
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 9bb0c7e1649..2f4a14b4e01 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -1004,7 +1004,7 @@ enum {
static struct {
GlobalProperty *prop;
const size_t *len;
-} __vz_compat_props[][3] = {
+} __vz_compat_props[][4] = {
{ VZ_COMPATS_EXPAND(hw_compat_vz, pc_vz_compat) },
VZ_Q35_MT(AS_ARRAY)
};
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 5140c9c1f23..4d8a01528b8 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -428,8 +428,8 @@ extern const size_t pc_vz_7_4_compat_len;
/*
* Helper macros for defining VZ machine types, both pc and q35
*/
-#define _GET_NTH_ARG(_0, _1, _2, _3, N, ...) N
-#define COUNT_ARGS(...) _GET_NTH_ARG(__VA_ARGS__, 3, 2, 1, 0)
+#define _GET_NTH_ARG(_0, _1, _2, _3, _4, N, ...) N
+#define COUNT_ARGS(...) _GET_NTH_ARG(__VA_ARGS__, 4, 3, 2, 1, 0)
#define VZ_COMPATS_EXPAND_0()
#define VZ_COMPATS_EXPAND_1(prop1) {prop1, &prop1##_len}
@@ -437,6 +437,9 @@ extern const size_t pc_vz_7_4_compat_len;
{prop1, &prop1##_len}, {prop2, &prop2##_len}
#define VZ_COMPATS_EXPAND_3(prop1, prop2, prop3) \
{prop1, &prop1##_len}, {prop2, &prop2##_len}, {prop3, &prop3##_len}
+#define VZ_COMPATS_EXPAND_4(prop1, prop2, prop3, prop4) \
+ {prop1, &prop1##_len}, {prop2, &prop2##_len}, {prop3, &prop3##_len}, \
+ {prop4, &prop4##_len}
#define VZ_COMPATS_EXPAND_N(n, ...) VZ_COMPATS_EXPAND_##n(__VA_ARGS__)
#define VZ_COMPATS_EXPAND_(n, ...) VZ_COMPATS_EXPAND_N(n, __VA_ARGS__)
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v3 hci-8.0/hci-8.1 1/6] i386/pc: raise the limit of compat arrays per Virtuozzo machine type to four #VSTOR-152264
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 1/6] i386/pc: raise the limit of compat arrays per Virtuozzo machine type to four #VSTOR-152264 Denis V. Lunev
@ 2026-10-29 12:27 ` no-reply
0 siblings, 0 replies; 15+ messages in thread
From: no-reply @ 2026-10-29 12:27 UTC (permalink / raw)
To: andrey.zhadchenko, Denis V. Lunev; +Cc: svt-core, den
> From: Denis V. Lunev <den@openvz.org>
>
> A row of VZ_Q35_MT or VZ_PC_MT can name at most three compat arrays:
> COUNT_ARGS counts up to three, VZ_COMPATS_EXPAND has variants for zero
> to three, and __vz_compat_props has three slots per row. No row needs
> more yet, which is why the limit never showed. The i440fx vz7.16.0 row
> uses all three (hw_compat_vz_9_1, hw_compat_vz_7_16,
> pc_vz_7_16_compat), and the next commit adds pc_vz_9_2_compat to it.
> With a fourth argument COUNT_ARGS returns that argument instead of a
> count, and the build fails on an undefined VZ_COMPATS_EXPAND_<name>.
>
> Raise the limit to four.
>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261029122527.365104-1-den@openvz.org?part=1
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 hci-8.0/hci-8.1 2/6] i386: keep hle and rtm on Virtuozzo machine types up to vz9.2.0 #PSBM-149402
2026-10-29 12:25 [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264 Denis V. Lunev
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 1/6] i386/pc: raise the limit of compat arrays per Virtuozzo machine type to four #VSTOR-152264 Denis V. Lunev
@ 2026-10-29 12:25 ` Denis V. Lunev
2026-10-29 12:29 ` no-reply
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 3/6] i386: keep spec-ctrl for AMD guests on vz machine types up to vz9.2.0 #VSTOR-151770 Denis V. Lunev
` (4 subsequent siblings)
6 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2026-10-29 12:25 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: svt-core, den
From: Denis V. Lunev <den@openvz.org>
Intel microcode updates for TAA disable TSX, and a host may also boot
with tsx=off. KVM then stops offering hle and rtm, QEMU filters them,
and a guest started with TSX can no longer be migrated, restored or
reverted to a snapshot on that host: libvirt rejects the filtered
features (VSTOR-75689, VSTOR-105458). The guest read its CPUID at
boot, so the bits have to stay until it is restarted.
Add x-tsx-compat: hle and rtm requested by an Intel CPU model or on
the command line are then not filtered, and KVM gets them in the guest
CPUID, ignoring bits it does not support. This also covers Haswell
parts with the TSX erratum, where QEMU drops the bits itself. With TSX
disabled through TSX_CTRL or by force-abort microcode XBEGIN aborts
every transaction and HLE prefixes are ignored, so a guest that keeps
using TSX falls back to its lock path.
As a machine type property it also applies when such a guest is booted
afresh. Through libvirt this changes little: a custom CPU with the
default check='partial' is compared against the host before QEMU
starts and still fails, and host-model and host-passthrough request
only what the host has. A domain with check='full' or 'none', or QEMU
started directly, gets the bits on a cold boot, as on the older node.
Limiting the property to -incoming would miss an internal snapshot
revert, which loads the state into a QEMU started without it, and a
vCPU hot-added after migration. The kept bits are not reported as
filtered, so check and enforce stay silent for them.
pc_vz_9_2_compat turns it on for vz9.2.0 and every older vz machine
type. Release 7.x ships up to vz9.1.0, and vz9.2.0 is the last type
based on a RHEL 9 machine type, before the QEMU 10 based vz10.x types.
vz10.x types and -cpu host expansion stay strict.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
---
hw/i386/pc.c | 5 +++++
hw/i386/pc_piix.c | 3 ++-
hw/i386/pc_q35.c | 2 +-
include/hw/i386/pc.h | 3 +++
target/i386/cpu.c | 27 ++++++++++++++++++++++++++-
target/i386/cpu.h | 7 +++++++
6 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 76289b86c28..25b17866103 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -548,6 +548,11 @@ GlobalProperty pc_vz_compat[] = {
};
const size_t pc_vz_compat_len = G_N_ELEMENTS(pc_vz_compat);
+GlobalProperty pc_vz_9_2_compat[] = {
+ { TYPE_X86_CPU, "x-tsx-compat", "on" },
+};
+const size_t pc_vz_9_2_compat_len = G_N_ELEMENTS(pc_vz_9_2_compat);
+
GlobalProperty pc_vz_7_16_compat[] = {
{ TYPE_X86_CPU, "kvm-pv-ipi", "off" },
{ TYPE_X86_CPU, "kvm-pv-tlb-flush", "off" },
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 1a50c2a645c..b1b595078eb 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -1058,7 +1058,8 @@ DEFINE_I440FX_RHEL_MACHINE(7, 2, 0);
#define VZ_PC_MT(X) \
X(10, 1, 0, MT_VER_SYM(10, 0, 0), true) \
X(10, 0, 0, MT_VER_SYM(10, 0, 0), false) \
- X(7, 16, 0, MT_VER_SYM(7, 6, 0), false, hw_compat_vz_9_1, \
+ X(7, 16, 0, MT_VER_SYM(7, 6, 0), false, pc_vz_9_2_compat, \
+ hw_compat_vz_9_1, \
hw_compat_vz_7_16, \
pc_vz_7_16_compat) \
X(7, 12, 0, MT_VER_SYM(7, 6, 0), false, hw_compat_vz_7_12) \
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 2f4a14b4e01..019239bec6a 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -974,7 +974,7 @@ DEFINE_Q35_RHEL_MACHINE(7, 3, 0);
#define VZ_Q35_MT(X) \
X(10, 1, 0, MT_VER_SYM(10, 2, 0), true) \
X(10, 0, 0, MT_VER_SYM(10, 0, 0), false) \
- X(9, 2, 0, MT_VER_SYM(9, 6, 0), false) \
+ X(9, 2, 0, MT_VER_SYM(9, 6, 0), false, pc_vz_9_2_compat) \
X(9, 1, 0, MT_VER_SYM(9, 4, 0), false, hw_compat_vz_9_1) \
X(9, 0, 0, MT_VER_SYM(9, 2, 0), false) \
X(7, 16, 0, MT_VER_SYM(7, 6, 0), false, hw_compat_vz_7_16, \
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 4d8a01528b8..bd73426644e 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -364,6 +364,9 @@ extern const size_t pc_rhel_7_2_compat_len;
extern GlobalProperty pc_vz_compat[];
extern const size_t pc_vz_compat_len;
+extern GlobalProperty pc_vz_9_2_compat[];
+extern const size_t pc_vz_9_2_compat_len;
+
extern GlobalProperty pc_vz_7_16_compat[];
extern const size_t pc_vz_7_16_compat_len;
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 5310d68443b..5ff5644dee9 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -9100,6 +9100,29 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
}
}
+/* Requested features that a vz compat property keeps despite the host */
+static uint64_t x86_cpu_compat_kept_features(X86CPU *cpu, FeatureWord w)
+{
+ CPUX86State *env = &cpu->env;
+ uint64_t kept = 0;
+
+ if (!kvm_enabled()) {
+ return 0;
+ }
+
+ switch (w) {
+ case FEAT_7_0_EBX:
+ if (cpu->tsx_compat && IS_INTEL_CPU(env)) {
+ kept = CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return kept & env->features[w];
+}
+
/*
* Finishes initialization of CPUID data, filters CPU feature
* words based on host availability of each feature.
@@ -9126,7 +9149,8 @@ static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose)
uint64_t host_feat =
x86_cpu_get_supported_feature_word(NULL, w);
uint64_t requested_features = env->features[w];
- uint64_t unavailable_features = requested_features & ~host_feat;
+ uint64_t unavailable_features = requested_features & ~host_feat &
+ ~x86_cpu_compat_kept_features(cpu, w);
mark_unavailable_features(cpu, w, unavailable_features, prefix);
}
@@ -10056,6 +10080,7 @@ static const Property x86_cpu_properties[] = {
arch_cap_always_on, false),
DEFINE_PROP_BOOL("x-pdcm-on-even-without-pmu", X86CPU,
pdcm_on_even_without_pmu, false),
+ DEFINE_PROP_BOOL("x-tsx-compat", X86CPU, tsx_compat, false),
};
#ifndef CONFIG_USER_ONLY
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 07b7a9417b1..85efd0b9fbe 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2331,6 +2331,13 @@ struct ArchCPU {
*/
bool pdcm_on_even_without_pmu;
+ /*
+ * Virtuozzo machine types up to vz9.2.0: do not filter requested
+ * features the host no longer provides, so that a guest started on an
+ * older node keeps its CPUID.
+ */
+ bool tsx_compat;
+
/* Number of physical address bits supported */
uint32_t phys_bits;
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v3 hci-8.0/hci-8.1 2/6] i386: keep hle and rtm on Virtuozzo machine types up to vz9.2.0 #PSBM-149402
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 2/6] i386: keep hle and rtm on Virtuozzo machine types up to vz9.2.0 #PSBM-149402 Denis V. Lunev
@ 2026-10-29 12:29 ` no-reply
0 siblings, 0 replies; 15+ messages in thread
From: no-reply @ 2026-10-29 12:29 UTC (permalink / raw)
To: Denis V. Lunev, andrey.zhadchenko; +Cc: svt-core, den
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] i386: x-tsx-compat keeps HLE/RTM without checking host TSX support
--
commit 958d84e4025a51fe913636203f3656b7b19673c8
Author: Denis V. Lunev <den@openvz.org>
i386: keep hle and rtm on Virtuozzo machine types up to vz9.2.0 #PSBM-149402
This patch adds an x-tsx-compat CPU property. When it is set, HLE and RTM
requested by an Intel CPU model are not filtered out under KVM. The property
is turned on by pc_vz_9_2_compat for vz9.2.0 and all older vz machine types.
The goal is that a guest started with TSX can still be migrated, restored or
reverted on a host where microcode or tsx=off has disabled TSX.
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
[ ... ]
> +GlobalProperty pc_vz_9_2_compat[] = {
> + { TYPE_X86_CPU, "x-tsx-compat", "on" },
> +};
> +const size_t pc_vz_9_2_compat_len = G_N_ELEMENTS(pc_vz_9_2_compat);
[Severity: Medium]
Because this is a machine type property, it is also on for a cold boot of
every vz type up to vz9.2.0, not only for incoming migration.
Can a cold-booted guest end up with HLE and RTM in its CPUID on a host that
has no TSX silicon, for example an AMD host running an Intel-named CPU
model, or an Intel part that never had TSX?
> diff --git a/target/i386/cpu.c b/target/i386/cpu.c
> --- a/target/i386/cpu.c
> +++ b/target/i386/cpu.c
[ ... ]
> +/* Requested features that a vz compat property keeps despite the host */
> +static uint64_t x86_cpu_compat_kept_features(X86CPU *cpu, FeatureWord w)
> +{
> + CPUX86State *env = &cpu->env;
> + uint64_t kept = 0;
> +
> + if (!kvm_enabled()) {
> + return 0;
> + }
> +
> + switch (w) {
> + case FEAT_7_0_EBX:
> + if (cpu->tsx_compat && IS_INTEL_CPU(env)) {
> + kept = CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM;
> + }
> + break;
[Severity: Medium]
The guard in x86_cpu_compat_kept_features() checks only kvm_enabled(),
cpu->tsx_compat and IS_INTEL_CPU(env). IS_INTEL_CPU(env) tests the vendor of
the guest CPU model, not of the host.
Nothing here checks whether the host implements TSX, as opposed to having it
disabled by microcode through TSX_CTRL or RTM_ALWAYS_ABORT. The commit
message justifies the bypass only for the second case, where XBEGIN aborts.
On silicon without TSX, XBEGIN raises #UD instead of aborting. Could a guest
that trusts CPUID and uses RTM (glibc lock elision, libitm) then take an
invalid-opcode fault?
Would it make sense to restrict the kept bits to hosts where TSX exists but
is disabled?
This also bypasses the existing safeguard in kvm_arch_get_supported_cpuid():
target/i386/kvm/kvm.c:kvm_arch_get_supported_cpuid() {
...
if (host_tsx_broken()) {
ret &= ~(CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_HLE);
}
...
}
The commit message says this is intended for Haswell parts with the erratum.
Is it also intended for hosts with no TSX at all?
[ ... ]
> @@ -9126,7 +9149,8 @@ static bool x86_cpu_filter_features(X86CPU *cpu, bool verbose)
> uint64_t host_feat =
> x86_cpu_get_supported_feature_word(NULL, w);
> uint64_t requested_features = env->features[w];
> - uint64_t unavailable_features = requested_features & ~host_feat;
> + uint64_t unavailable_features = requested_features & ~host_feat &
> + ~x86_cpu_compat_kept_features(cpu, w);
> mark_unavailable_features(cpu, w, unavailable_features, prefix);
[Severity: Medium]
In x86_cpu_filter_features(), the kept bits are removed from
unavailable_features before mark_unavailable_features() is called.
The bits therefore stay in env->features and go into the guest CPUID. They
are also never added to cpu->filtered_features, so the check and enforce
warnings and errors stay silent for them.
Is it intended that enforce can no longer reject HLE or RTM on a host that
lacks TSX entirely?
I did not trace the KVM_SET_CPUID2 path in kvm_arch_init_vcpu(). The commit
message says KVM ignores unsupported bits, but the kernel does not validate
userspace-supplied guest CPUID against host capability.
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261029122527.365104-1-den@openvz.org?part=2
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 hci-8.0/hci-8.1 3/6] i386: keep spec-ctrl for AMD guests on vz machine types up to vz9.2.0 #VSTOR-151770
2026-10-29 12:25 [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264 Denis V. Lunev
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 1/6] i386/pc: raise the limit of compat arrays per Virtuozzo machine type to four #VSTOR-152264 Denis V. Lunev
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 2/6] i386: keep hle and rtm on Virtuozzo machine types up to vz9.2.0 #PSBM-149402 Denis V. Lunev
@ 2026-10-29 12:25 ` Denis V. Lunev
2026-10-29 12:29 ` no-reply
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 4/6] i386: keep bus-lock-detect for AMD guests on vz machine types up to vz9.2.0 #VSTOR-152291 Denis V. Lunev
` (3 subsequent siblings)
6 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2026-10-29 12:25 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: svt-core, den
From: Denis V. Lunev <den@openvz.org>
Since kernel commit de572491a975 ("KVM: x86: AMD's IBPB is not
equivalent to Intel's IBPB") KVM offers spec-ctrl on AMD hosts only
with IBPB_RET, which Zen 1-3 lack. A guest started under an older
kernel has spec-ctrl in its CPUID, and QEMU filters it on the new
host, so migration, restore and snapshot revert fail (VSTOR-151770).
Add x-spec-ctrl-compat and turn it on in pc_vz_9_2_compat: an AMD
guest keeps a requested spec-ctrl when the guest and the host both
have amd-ibpb and one of amd-ibrs, amd-stibp and amd-ssbd. Since
kernel commit e592ec657d84 KVM grants a guest only the CPUID bits it
supports itself, so the kept spec-ctrl gives the guest no MSR on such
a host. MSR_IA32_PRED_CMD stays available through amd-ibpb and
MSR_IA32_SPEC_CTRL through the other three (kernel commit
39485ed95d6b). Without them every access to MSR_IA32_SPEC_CTRL raises
#GP, so such a guest still fails to start or migrate, as it did with
the libvirt relaxation this replaces.
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
hw/i386/pc.c | 1 +
target/i386/cpu.c | 14 ++++++++++++++
target/i386/cpu.h | 1 +
3 files changed, 16 insertions(+)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 25b17866103..95ff2e7860e 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -550,6 +550,7 @@ const size_t pc_vz_compat_len = G_N_ELEMENTS(pc_vz_compat);
GlobalProperty pc_vz_9_2_compat[] = {
{ TYPE_X86_CPU, "x-tsx-compat", "on" },
+ { TYPE_X86_CPU, "x-spec-ctrl-compat", "on" },
};
const size_t pc_vz_9_2_compat_len = G_N_ELEMENTS(pc_vz_9_2_compat);
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 5ff5644dee9..27fefaeaf71 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -9116,6 +9116,19 @@ static uint64_t x86_cpu_compat_kept_features(X86CPU *cpu, FeatureWord w)
kept = CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM;
}
break;
+ case FEAT_7_0_EDX:
+ if (cpu->spec_ctrl_compat && IS_AMD_CPU(env)) {
+ uint64_t msrs = env->features[FEAT_8000_0008_EBX] &
+ kvm_arch_get_supported_cpuid(kvm_state, 0x80000008, 0, R_EBX);
+
+ if ((msrs & CPUID_8000_0008_EBX_IBPB) &&
+ (msrs & (CPUID_8000_0008_EBX_IBRS |
+ CPUID_8000_0008_EBX_STIBP |
+ CPUID_8000_0008_EBX_AMD_SSBD))) {
+ kept = CPUID_7_0_EDX_SPEC_CTRL;
+ }
+ }
+ break;
default:
break;
}
@@ -10081,6 +10094,7 @@ static const Property x86_cpu_properties[] = {
DEFINE_PROP_BOOL("x-pdcm-on-even-without-pmu", X86CPU,
pdcm_on_even_without_pmu, false),
DEFINE_PROP_BOOL("x-tsx-compat", X86CPU, tsx_compat, false),
+ DEFINE_PROP_BOOL("x-spec-ctrl-compat", X86CPU, spec_ctrl_compat, false),
};
#ifndef CONFIG_USER_ONLY
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 85efd0b9fbe..740fb3aedc5 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2337,6 +2337,7 @@ struct ArchCPU {
* older node keeps its CPUID.
*/
bool tsx_compat;
+ bool spec_ctrl_compat;
/* Number of physical address bits supported */
uint32_t phys_bits;
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v3 hci-8.0/hci-8.1 3/6] i386: keep spec-ctrl for AMD guests on vz machine types up to vz9.2.0 #VSTOR-151770
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 3/6] i386: keep spec-ctrl for AMD guests on vz machine types up to vz9.2.0 #VSTOR-151770 Denis V. Lunev
@ 2026-10-29 12:29 ` no-reply
0 siblings, 0 replies; 15+ messages in thread
From: no-reply @ 2026-10-29 12:29 UTC (permalink / raw)
To: andrey.zhadchenko, Denis V. Lunev; +Cc: svt-core, den
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] i386: shared tsx_compat comment does not describe conditional spec_ctrl_compat
--
commit f0225ca6e631cf113e6cd09a3b55911125b7a154
Author: Denis V. Lunev <den@openvz.org>
i386: keep spec-ctrl for AMD guests on vz machine types up to vz9.2.0 #VSTOR-151770
This patch adds an x-spec-ctrl-compat CPU property and enables it in
pc_vz_9_2_compat. On AMD guests, a requested spec-ctrl bit is kept when the
guest and host both report amd-ibpb and at least one of amd-ibrs, amd-stibp
or amd-ssbd.
> diff --git a/target/i386/cpu.h b/target/i386/cpu.h
> index 85efd0b9fbe5..740fb3aedc56 100644
> --- a/target/i386/cpu.h
> +++ b/target/i386/cpu.h
> @@ -2337,6 +2337,7 @@ struct ArchCPU {
> * older node keeps its CPUID.
> */
> bool tsx_compat;
> + bool spec_ctrl_compat;
>
[Severity: Low]
This isn't a bug, but the comment above tsx_compat now also appears to
cover spec_ctrl_compat:
/*
* Virtuozzo machine types up to vz9.2.0: do not filter requested
* features the host no longer provides, so that a guest started on an
* older node keeps its CPUID.
*/
bool tsx_compat;
bool spec_ctrl_compat;
Is that description accurate for the new flag? In
x86_cpu_compat_kept_features(), spec_ctrl_compat keeps SPEC_CTRL only when
the vendor is AMD, the guest and the host both have amd-ibpb, and at least
one of amd-ibrs, amd-stibp or amd-ssbd is present. It does not keep every
requested feature the host no longer provides.
Could spec_ctrl_compat get its own comment that describes these conditions?
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261029122527.365104-1-den@openvz.org?part=3
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3 hci-8.0/hci-8.1 4/6] i386: keep bus-lock-detect for AMD guests on vz machine types up to vz9.2.0 #VSTOR-152291
2026-10-29 12:25 [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264 Denis V. Lunev
` (2 preceding siblings ...)
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 3/6] i386: keep spec-ctrl for AMD guests on vz machine types up to vz9.2.0 #VSTOR-151770 Denis V. Lunev
@ 2026-10-29 12:25 ` Denis V. Lunev
2026-10-29 12:30 ` no-reply
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 5/6] i386: keep v-vmsave-vmload for nested AMD guests on vz types up to vz9.2.0 #VSTOR-152264 Denis V. Lunev
` (2 subsequent siblings)
6 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2026-10-29 12:25 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: svt-core, den
From: Denis V. Lunev <den@openvz.org>
Since kernel commit 54950bfe2b69 KVM on AMD no longer offers
bus-lock-detect. A Zen 5 guest started under an older kernel has it in
its CPUID, and QEMU filters it on the new host, so migration, restore
and snapshot revert fail (VSTOR-152291).
Add x-bus-lock-detect-compat and turn it on in pc_vz_9_2_compat: an
AMD guest keeps a requested bus-lock-detect. The guest loses nothing
it had: bus lock detection did not work under KVM on AMD before kernel
commit 62ad461079e7, DR6 bit 11 stays fixed, and a Linux 6.13 or newer
guest only logs one "unchecked MSR access" warning when it brings a
vCPU online.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
---
hw/i386/pc.c | 1 +
target/i386/cpu.c | 7 +++++++
target/i386/cpu.h | 1 +
3 files changed, 9 insertions(+)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 95ff2e7860e..91198e8996c 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -551,6 +551,7 @@ const size_t pc_vz_compat_len = G_N_ELEMENTS(pc_vz_compat);
GlobalProperty pc_vz_9_2_compat[] = {
{ TYPE_X86_CPU, "x-tsx-compat", "on" },
{ TYPE_X86_CPU, "x-spec-ctrl-compat", "on" },
+ { TYPE_X86_CPU, "x-bus-lock-detect-compat", "on" },
};
const size_t pc_vz_9_2_compat_len = G_N_ELEMENTS(pc_vz_9_2_compat);
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 27fefaeaf71..a3c5c9ce1a8 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -9116,6 +9116,11 @@ static uint64_t x86_cpu_compat_kept_features(X86CPU *cpu, FeatureWord w)
kept = CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_RTM;
}
break;
+ case FEAT_7_0_ECX:
+ if (cpu->bus_lock_detect_compat && IS_AMD_CPU(env)) {
+ kept = CPUID_7_0_ECX_BUS_LOCK_DETECT;
+ }
+ break;
case FEAT_7_0_EDX:
if (cpu->spec_ctrl_compat && IS_AMD_CPU(env)) {
uint64_t msrs = env->features[FEAT_8000_0008_EBX] &
@@ -10095,6 +10100,8 @@ static const Property x86_cpu_properties[] = {
pdcm_on_even_without_pmu, false),
DEFINE_PROP_BOOL("x-tsx-compat", X86CPU, tsx_compat, false),
DEFINE_PROP_BOOL("x-spec-ctrl-compat", X86CPU, spec_ctrl_compat, false),
+ DEFINE_PROP_BOOL("x-bus-lock-detect-compat", X86CPU,
+ bus_lock_detect_compat, false),
};
#ifndef CONFIG_USER_ONLY
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 740fb3aedc5..b5e2d88d5d5 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2338,6 +2338,7 @@ struct ArchCPU {
*/
bool tsx_compat;
bool spec_ctrl_compat;
+ bool bus_lock_detect_compat;
/* Number of physical address bits supported */
uint32_t phys_bits;
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v3 hci-8.0/hci-8.1 5/6] i386: keep v-vmsave-vmload for nested AMD guests on vz types up to vz9.2.0 #VSTOR-152264
2026-10-29 12:25 [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264 Denis V. Lunev
` (3 preceding siblings ...)
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 4/6] i386: keep bus-lock-detect for AMD guests on vz machine types up to vz9.2.0 #VSTOR-152291 Denis V. Lunev
@ 2026-10-29 12:25 ` Denis V. Lunev
2026-10-29 12:30 ` no-reply
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 6/6] i386: keep SVM leaf features without svm on vz types up to vz9.2.0 #PSBM-144630 Denis V. Lunev
2026-10-29 13:30 ` [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264 Andrey Drobyshev
6 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2026-10-29 12:25 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: svt-core, den
From: Denis V. Lunev <den@openvz.org>
On Zen 4 client parts (family 19h models 0x18-0x1f and 0x60-0x7f) the
6.12 kernel clears virtualized VMSAVE/VMLOAD in init_amd_zen4(): some
BIOS versions advertise it, and it can lead to random host reboots.
KVM then stops offering v-vmsave-vmload. A nested guest (svm=on)
started before has it in its CPUID, and QEMU filters it on such a host,
so migration, restore and snapshot revert fail.
Add x-v-vmsave-vmload-compat and turn it on in pc_vz_9_2_compat: an
AMD guest keeps a requested v-vmsave-vmload. This does not turn host
VLS back on: KVM keeps intercepting VMLOAD and VMSAVE of the nested
guest and emulates them (nested_vmcb_needs_vls_intercept()), which is
only slower.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
---
hw/i386/pc.c | 1 +
target/i386/cpu.c | 7 +++++++
target/i386/cpu.h | 1 +
3 files changed, 9 insertions(+)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 91198e8996c..5b2b2de4064 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -552,6 +552,7 @@ GlobalProperty pc_vz_9_2_compat[] = {
{ TYPE_X86_CPU, "x-tsx-compat", "on" },
{ TYPE_X86_CPU, "x-spec-ctrl-compat", "on" },
{ TYPE_X86_CPU, "x-bus-lock-detect-compat", "on" },
+ { TYPE_X86_CPU, "x-v-vmsave-vmload-compat", "on" },
};
const size_t pc_vz_9_2_compat_len = G_N_ELEMENTS(pc_vz_9_2_compat);
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index a3c5c9ce1a8..47027a2b828 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -9134,6 +9134,11 @@ static uint64_t x86_cpu_compat_kept_features(X86CPU *cpu, FeatureWord w)
}
}
break;
+ case FEAT_SVM:
+ if (cpu->v_vmsave_vmload_compat && IS_AMD_CPU(env)) {
+ kept = CPUID_SVM_V_VMSAVE_VMLOAD;
+ }
+ break;
default:
break;
}
@@ -10102,6 +10107,8 @@ static const Property x86_cpu_properties[] = {
DEFINE_PROP_BOOL("x-spec-ctrl-compat", X86CPU, spec_ctrl_compat, false),
DEFINE_PROP_BOOL("x-bus-lock-detect-compat", X86CPU,
bus_lock_detect_compat, false),
+ DEFINE_PROP_BOOL("x-v-vmsave-vmload-compat", X86CPU,
+ v_vmsave_vmload_compat, false),
};
#ifndef CONFIG_USER_ONLY
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index b5e2d88d5d5..4f8bcbe600a 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2339,6 +2339,7 @@ struct ArchCPU {
bool tsx_compat;
bool spec_ctrl_compat;
bool bus_lock_detect_compat;
+ bool v_vmsave_vmload_compat;
/* Number of physical address bits supported */
uint32_t phys_bits;
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* [PATCH v3 hci-8.0/hci-8.1 6/6] i386: keep SVM leaf features without svm on vz types up to vz9.2.0 #PSBM-144630
2026-10-29 12:25 [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264 Denis V. Lunev
` (4 preceding siblings ...)
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 5/6] i386: keep v-vmsave-vmload for nested AMD guests on vz types up to vz9.2.0 #VSTOR-152264 Denis V. Lunev
@ 2026-10-29 12:25 ` Denis V. Lunev
2026-10-29 12:33 ` no-reply
2026-10-29 13:30 ` [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264 Andrey Drobyshev
6 siblings, 1 reply; 15+ messages in thread
From: Denis V. Lunev @ 2026-10-29 12:25 UTC (permalink / raw)
To: andrey.zhadchenko; +Cc: svt-core, den
From: Denis V. Lunev <den@openvz.org>
Since commit 730319aef0f ("i386: Mask SVM features if nested SVM is
disabled", QEMU 5.1) the features of CPUID leaf 0x8000000a are dropped
when svm is off. QEMU 2.12 on Vz7 kept them, and a Vz7 host-model
guest runs with svm=off,npt=on,nrip-save=on. Moving it to a newer QEMU
fails in libvirt (PSBM-144630):
guest CPU doesn't match specification: missing features: npt,nrip-save
Add x-svm-features-compat and turn it on in pc_vz_9_2_compat: under KVM
requested SVM leaf features stay when svm is off, both against the
dependency on svm and against the host. The guest sees the CPUID it
saw on QEMU 2.12: cpu_x86_cpuid() reports leaf 0x8000000a only with
svm, and the kept features raise the automatic xlevel to 0x8000000a
as they did there. With svm off every FEAT_SVM bit is kept, including
the ones -cpu host takes from the host, which the guest cannot see
either. TCG keeps dropping the features, since it cannot provide them.
Signed-off-by: Denis V. Lunev <den@openvz.org>
Acked-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
---
hw/i386/pc.c | 1 +
target/i386/cpu.c | 13 +++++++++++++
target/i386/cpu.h | 1 +
3 files changed, 15 insertions(+)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 5b2b2de4064..9b6b51bd5f7 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -553,6 +553,7 @@ GlobalProperty pc_vz_9_2_compat[] = {
{ TYPE_X86_CPU, "x-spec-ctrl-compat", "on" },
{ TYPE_X86_CPU, "x-bus-lock-detect-compat", "on" },
{ TYPE_X86_CPU, "x-v-vmsave-vmload-compat", "on" },
+ { TYPE_X86_CPU, "x-svm-features-compat", "on" },
};
const size_t pc_vz_9_2_compat_len = G_N_ELEMENTS(pc_vz_9_2_compat);
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 47027a2b828..29e7b4b7e15 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -8996,6 +8996,13 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
for (i = 0; i < ARRAY_SIZE(feature_dependencies); i++) {
FeatureDep *d = &feature_dependencies[i];
+
+ /* CPUID leaf 0x8000000a stays empty without svm anyway */
+ if (cpu->svm_features_compat && kvm_enabled() &&
+ d->to.index == FEAT_SVM) {
+ continue;
+ }
+
if (!(env->features[d->from.index] & d->from.mask)) {
uint64_t unavailable_features = env->features[d->to.index] & d->to.mask;
@@ -9138,6 +9145,10 @@ static uint64_t x86_cpu_compat_kept_features(X86CPU *cpu, FeatureWord w)
if (cpu->v_vmsave_vmload_compat && IS_AMD_CPU(env)) {
kept = CPUID_SVM_V_VMSAVE_VMLOAD;
}
+ if (cpu->svm_features_compat &&
+ !(env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM)) {
+ kept = ~0ULL;
+ }
break;
default:
break;
@@ -10109,6 +10120,8 @@ static const Property x86_cpu_properties[] = {
bus_lock_detect_compat, false),
DEFINE_PROP_BOOL("x-v-vmsave-vmload-compat", X86CPU,
v_vmsave_vmload_compat, false),
+ DEFINE_PROP_BOOL("x-svm-features-compat", X86CPU,
+ svm_features_compat, false),
};
#ifndef CONFIG_USER_ONLY
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 4f8bcbe600a..97e38013e46 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2340,6 +2340,7 @@ struct ArchCPU {
bool spec_ctrl_compat;
bool bus_lock_detect_compat;
bool v_vmsave_vmload_compat;
+ bool svm_features_compat;
/* Number of physical address bits supported */
uint32_t phys_bits;
--
2.53.0
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v3 hci-8.0/hci-8.1 6/6] i386: keep SVM leaf features without svm on vz types up to vz9.2.0 #PSBM-144630
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 6/6] i386: keep SVM leaf features without svm on vz types up to vz9.2.0 #PSBM-144630 Denis V. Lunev
@ 2026-10-29 12:33 ` no-reply
0 siblings, 0 replies; 15+ messages in thread
From: no-reply @ 2026-10-29 12:33 UTC (permalink / raw)
To: andrey.zhadchenko, Denis V. Lunev; +Cc: den, svt-core
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] i386: x86_cpu_compat_kept_features() keeps SVM leaf bits after svm is host-filtered
--
commit cc8f40cd79cdf926fae1c7d33e11aa26bbf6654b
Author: Denis V. Lunev <den@openvz.org>
i386: keep SVM leaf features without svm on vz types up to vz9.2.0 #PSBM-144630
This adds an x-svm-features-compat CPU property and enables it in
pc_vz_9_2_compat. Under KVM, requested SVM leaf features are kept when svm
is off, both against the feature dependency on svm and against the host
feature filter.
> diff --git a/target/i386/cpu.c b/target/i386/cpu.c
> --- a/target/i386/cpu.c
> +++ b/target/i386/cpu.c
[ ... ]
> @@ -9138,6 +9145,10 @@ static uint64_t x86_cpu_compat_kept_features(X86CPU *cpu, FeatureWord w)
> if (cpu->v_vmsave_vmload_compat && IS_AMD_CPU(env)) {
> kept = CPUID_SVM_V_VMSAVE_VMLOAD;
> }
> + if (cpu->svm_features_compat &&
> + !(env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM)) {
> + kept = ~0ULL;
> + }
> break;
> default:
> break;
[Severity: Low]
Can this condition tell "svm=off was requested" apart from "svm=on was
requested but the host filtered it"?
x86_cpu_compat_kept_features() reads env->features[FEAT_8000_0001_ECX] when
it is called from x86_cpu_filter_features():
uint64_t unavailable_features = requested_features & ~host_feat &
~x86_cpu_compat_kept_features(cpu, w);
mark_unavailable_features(cpu, w, unavailable_features, prefix);
In the FeatureWord enum, FEAT_8000_0001_ECX comes before FEAT_SVM, so the
loop filters FEAT_8000_0001_ECX first. If the user requested svm=on, for
example through a host-model CPU, and the host lacks nested SVM, for
example kvm_amd nested=0, mark_unavailable_features() clears
CPUID_EXT3_SVM first.
When the loop then reaches FEAT_SVM, the check above sees the svm bit
already cleared and sets kept = ~0ULL. Every requested FEAT_SVM bit that
the host doesn't support is then neither cleared nor reported. This goes
beyond the stated "svm off" scope in the commit message.
The guest-visible CPUID looks unchanged, because cpu_x86_cpuid() returns
zeros for leaf 0x8000000a without svm. The svm bit is still reported as
unavailable, so enforce still fails. The xlevel adjustment happens in
x86_cpu_expand_features() before filtering. What does change is that npt,
nrip-save and the other SVM leaf features are no longer listed as filtered,
and env->features[FEAT_SVM] keeps unsupported bits.
Would it be better to record whether svm was requested off before
x86_cpu_filter_features() runs, or to check env->user_features, instead of
reading the already-filtered env->features value?
--
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261029122527.365104-1-den@openvz.org?part=6
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264
2026-10-29 12:25 [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264 Denis V. Lunev
` (5 preceding siblings ...)
2026-10-29 12:25 ` [PATCH v3 hci-8.0/hci-8.1 6/6] i386: keep SVM leaf features without svm on vz types up to vz9.2.0 #PSBM-144630 Denis V. Lunev
@ 2026-10-29 13:30 ` Andrey Drobyshev
2026-10-29 13:47 ` Andrey Drobyshev
6 siblings, 1 reply; 15+ messages in thread
From: Andrey Drobyshev @ 2026-10-29 13:30 UTC (permalink / raw)
To: Denis V. Lunev; +Cc: andrey.zhadchenko, svt-core
> A guest started on an older node can have a CPU feature that the
> destination host no longer offers: TSX disabled by microcode, a newer
> kernel that stops offering spec-ctrl or bus-lock-detect on AMD, or SVM
> leaf features that QEMU 2.12 on Vz7 kept with svm off. QEMU filters the
> feature on the destination, and libvirt refuses the live migration,
> restore or snapshot revert:
>
> guest CPU doesn't match specification: missing features: hle,rtm
>
> The guest read its CPUID at boot, so the bit has to stay until the guest
> restarts.
>
> Until now libvirt relaxed the check, in three places that behave
> differently. One of them crashes libvirtd on the destination of any
> migration of a host-passthrough VM with a vz7 machine type
> (VSTOR-152247). This series keeps the bits in QEMU instead: one
> x-...-compat X86CPU property per feature, all turned on by a new
> pc_vz_9_2_compat on vz9.2.0 and every older vz machine type. Release
> 7.x ships up to vz9.1.0, and vz9.2.0 is the last type based on a RHEL 9
> machine type. vz10.x types and -cpu host expansion stay strict. A
> property keeps a bit only when the CPU model or the command line asks
> for it and the condition in the commit message holds; KVM ignores
> CPUID bits it does not support.
>
> Patch 1 lets a row of the vz machine type tables name a fourth compat
> array, which the i440fx vz7.16.0 row needs. Patches 2 to 6 add one
> property each:
>
> 2 hle, rtm PSBM-149402 (field: VSTOR-75689,
> VSTOR-105458)
> 3 spec-ctrl, AMD VSTOR-151770
> 4 bus-lock-detect, AMD VSTOR-152291
> 5 v-vmsave-vmload, AMD code review, nested guests on Zen 4
> client parts, no field report
> 6 SVM leaf features, svm off PSBM-144630
>
> The same patches apply to hci-8.0 and hci-8.1 without changes; the
> base given below is hci-dev. On 8.0 they also fix the migration on
> their own: hci-8.0 libvirt keeps its relaxations, and they no longer
> see a filtered bit. That covers bus-lock-detect (VSTOR-152291), which
> hci-8.0 libvirt does not relax. The vz7 CPU fixup there still runs on
> migration (with the NULL check from VSTOR-152247) and forces npt and
> nrip-save off, which the guest does not see, because leaf 0x8000000a
> is hidden without svm. Only the destination needs the new qemu-kvm:
> the compat acts when the incoming QEMU process starts.
>
> On hci-dev the libvirt side drops its relaxations and the qemu.d hooks
> in libvirt.ovz pr/den-VSTOR-152247-drop-vz-cpu-relaxations. It needs
> this series in qemu-kvm first.
>
> Testing:
> - dev-cl04, EPYC 7443P: a saved guest whose migration cookie CPU was
> rewritten to the shape of a Vz7 host-model guest
> (svm=off,npt=on,nrip-save=on, plus spec-ctrl) fails to restore
> without the series with "missing features: npt,nrip-save" and
> "missing features: spec-ctrl". With it the guest restores, the
> features stay on and filtered-features is empty. Stock 8.1 libvirt,
> which carries the same relaxations as hci-8.0, restores it with no
> warning as well.
> - sqvm2-1015, Broadwell without TSX: the VSTOR-75689 guest CPU fails
> with "missing features: hle,rtm" without the series and keeps hle
> and rtm with it.
> - sqvm2-1013 <-> sqvm2-1015, with the libvirt PR: live migration in
> both directions of a pc-i440fx-vz7.12.0 host-passthrough guest and
> of the VSTOR-75689 Broadwell-IBRS guest. No crash, no warning,
> hle/rtm kept, the CPU stays match='exact'. Stock libvirt crashes on
> the first of them.
> - hci-8.0 and hci-8.1 builds: -cpu EPYC-Milan,svm=off,npt=on,
> nrip-save=on,enforce and -cpu EPYC-Milan,spec-ctrl=on,enforce start
> on vz7.12.0, vz9.0.0 and vz9.2.0 and are refused on vz10.x. A fresh
> Broadwell-IBRS start with check='full' is refused on vz10.1.0.
> - both builds, TCG: -cpu EPYC-Milan,svm=off warns about the same
> features on vz9.2.0 as on vz10.0.0, none from leaf 0x8000000a.
> - both builds, qtest-x86_64: ivshmem-test, test-hmp and qom-test fail
> as on the base (qemu_ram_free assertion, isapc aborting at start).
> - both builds, spec-ctrl on vz9.2.0 and vz7.16.0: EPYC-Milan with
> spec-ctrl=on,enforce starts, also with only one of ibrs, amd-stibp
> and amd-ssbd left; EPYC-IBPB, or EPYC-Milan without ibpb or without
> all three, is refused. Everything is refused on vz10.1.0.
> - bus-lock-detect and v-vmsave-vmload are build-tested only: no Zen 5
> or Zen 4 client host was available.
>
> Changes v2 -> v3:
> - 3/6: keep spec-ctrl only when the guest also has the amd-* bits that
> give it the MSRs, not only the host (Andrey)
> - 2/6: pc_vz_9_2_compat first in the vz7.16.0 row (Andrey); TSX_CTRL
> makes XBEGIN abort, not #UD, and libvirt check='partial' still
> refuses a fresh start
> - 5/6, 6/6: commit messages clarified
> - R-b on 1/6, A-b on 2/6, 4/6, 5/6 and 6/6
>
> Changes v1 -> v2:
> - 6/6: keep SVM leaf features past the svm dependency under KVM only,
> TCG warned about them
> - 2/6, 6/6, cover: commit messages clarified after the Sashiko review
>
> v2: http://lore.virtuozzo.com/qemu/20261029113436.93521-1-den@openvz.org/
> v1: http://lore.virtuozzo.com/kernel/20261029095645.4173762-1-den@openvz.org/
>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
>
> Denis V. Lunev (6):
> i386/pc: raise the limit of compat arrays per Virtuozzo machine type
> to four #VSTOR-152264
> i386: keep hle and rtm on Virtuozzo machine types up to vz9.2.0
> #PSBM-149402
> i386: keep spec-ctrl for AMD guests on vz machine types up to vz9.2.0
> #VSTOR-151770
> i386: keep bus-lock-detect for AMD guests on vz machine types up to
> vz9.2.0 #VSTOR-152291
> i386: keep v-vmsave-vmload for nested AMD guests on vz types up to
> vz9.2.0 #VSTOR-152264
> i386: keep SVM leaf features without svm on vz types up to vz9.2.0
> #PSBM-144630
>
> hw/i386/pc.c | 9 ++++++
> hw/i386/pc_piix.c | 5 ++--
> hw/i386/pc_q35.c | 4 +--
> include/hw/i386/pc.h | 10 +++++--
> target/i386/cpu.c | 68 +++++++++++++++++++++++++++++++++++++++++++-
> target/i386/cpu.h | 11 +++++++
> 6 files changed, 100 insertions(+), 7 deletions(-)
Major: vz10.x AMD guests from 55.x-kernel nodes are left out (patch 3 / cover letter)
- The SPEC_CTRL gate change (AMD_IBPB_RET required) entered vzkernel with the RHEL 10.1 import, commit 9f055df113432, first tag rh10-6.12.0-211.16.1..vz10.
All earlier vz10 kernels (rh10-6.12.0-55..vz10) still advertise spec-ctrl on every AMD host with IBPB+IBRS, i.e. on Zen 1-3.
- Release-kernel tags rk-6.12.0-55.52.1.5.28.vz10-v10.2 and rk-6.12.0-55.52.1.5.22.vz10-v10.3 show shipped 8.0 nodes ran 55.x. Host-model guests started
there carry vz10.0.0/vz10.1.0 and spec-ctrl as require.
- After such a node moves to a 211.x kernel those guests fail migration, restore and revert exactly as in VSTOR-151770, but pc_vz_9_2_compat does not apply
to vz10.x. The libvirt kludge being reverted in PR 392 (d7e2f96f877f) covered every machine type, so the pair of series regresses this population relative to the kludge.
- Fix: enable x-spec-ctrl-compat for vz10.0.0 and vz10.1.0 as well, with only the next new type strict, or keep the libvirt spec-ctrl kludge until then. The other four properties are fine at vz9.2.0: BLD and VMSAVE/VMLOAD changes are in every vz10 kernel, TSX is host-config, not kernel-version.
Medium: tsx_compat has no host guard (patch 2)
- kept = HLE|RTM whenever the vendor is Intel. The message says it "also covers Haswell parts with the TSX erratum" and that XBEGIN aborts. On
HSW136-microcode parts and on silicon without TSX, XBEGIN raises #UD, so a guest that selected RTM paths at startup gets SIGILL.
- Not a regression against the libvirt skip, which had the same hole, but the message overclaims. Guard suggestion: keep only when the host still has TSX
silicon, i.e. ARCH_CAPABILITIES.TSX_CTRL, CPUID.7.EDX rtm-always-abort or tsx-force-abort, and never when host_tsx_broken().
Low: Hygon hosts excluded (patches 3, 4)
- IS_AMD_CPU matches AuthenticAMD only. Dhyana (Zen 1) hosts lose spec-ctrl on 211.x the same way and get nothing from the series. Add the HygonGenuine
vendor check if Hygon is in the fleet.
Low: bus-lock-detect kept bit on 211.x (patch 4)
- svm_set_msr rejects any DEBUGCTL bit but LBR (DEBUGCTL_RESERVED_BITS = ~DEBUGCTLMSR_LBR), so a rebooted guest enabling BLD gets #GP and one "unchecked MSR access error" splat. A migrated guest loses BLD silently since QEMU does not migrate DEBUGCTL. Cosmetic, worth a sentence in the message.
--
Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264
2026-10-29 13:30 ` [PATCH v3 hci-8.0/hci-8.1 0/6] i386: keep CPU features of guests from older nodes on vz machine types #VSTOR-152264 Andrey Drobyshev
@ 2026-10-29 13:47 ` Andrey Drobyshev
0 siblings, 0 replies; 15+ messages in thread
From: Andrey Drobyshev @ 2026-10-29 13:47 UTC (permalink / raw)
To: Denis V. Lunev; +Cc: andrey.zhadchenko, svt-core
On 10/29/26 3:30 PM, Andrey Drobyshev wrote:
>> A guest started on an older node can have a CPU feature that the
>> destination host no longer offers: TSX disabled by microcode, a newer
>> kernel that stops offering spec-ctrl or bus-lock-detect on AMD, or SVM
>> leaf features that QEMU 2.12 on Vz7 kept with svm off. QEMU filters the
>> feature on the destination, and libvirt refuses the live migration,
>> restore or snapshot revert:
>>
>> guest CPU doesn't match specification: missing features: hle,rtm
>>
>> The guest read its CPUID at boot, so the bit has to stay until the guest
>> restarts.
>>
>> Until now libvirt relaxed the check, in three places that behave
>> differently. One of them crashes libvirtd on the destination of any
>> migration of a host-passthrough VM with a vz7 machine type
>> (VSTOR-152247). This series keeps the bits in QEMU instead: one
>> x-...-compat X86CPU property per feature, all turned on by a new
>> pc_vz_9_2_compat on vz9.2.0 and every older vz machine type. Release
>> 7.x ships up to vz9.1.0, and vz9.2.0 is the last type based on a RHEL 9
>> machine type. vz10.x types and -cpu host expansion stay strict. A
>> property keeps a bit only when the CPU model or the command line asks
>> for it and the condition in the commit message holds; KVM ignores
>> CPUID bits it does not support.
>>
>> Patch 1 lets a row of the vz machine type tables name a fourth compat
>> array, which the i440fx vz7.16.0 row needs. Patches 2 to 6 add one
>> property each:
>>
>> 2 hle, rtm PSBM-149402 (field: VSTOR-75689,
>> VSTOR-105458)
>> 3 spec-ctrl, AMD VSTOR-151770
>> 4 bus-lock-detect, AMD VSTOR-152291
>> 5 v-vmsave-vmload, AMD code review, nested guests on Zen 4
>> client parts, no field report
>> 6 SVM leaf features, svm off PSBM-144630
>>
>> The same patches apply to hci-8.0 and hci-8.1 without changes; the
>> base given below is hci-dev. On 8.0 they also fix the migration on
>> their own: hci-8.0 libvirt keeps its relaxations, and they no longer
>> see a filtered bit. That covers bus-lock-detect (VSTOR-152291), which
>> hci-8.0 libvirt does not relax. The vz7 CPU fixup there still runs on
>> migration (with the NULL check from VSTOR-152247) and forces npt and
>> nrip-save off, which the guest does not see, because leaf 0x8000000a
>> is hidden without svm. Only the destination needs the new qemu-kvm:
>> the compat acts when the incoming QEMU process starts.
>>
>> On hci-dev the libvirt side drops its relaxations and the qemu.d hooks
>> in libvirt.ovz pr/den-VSTOR-152247-drop-vz-cpu-relaxations. It needs
>> this series in qemu-kvm first.
>>
>> Testing:
>> - dev-cl04, EPYC 7443P: a saved guest whose migration cookie CPU was
>> rewritten to the shape of a Vz7 host-model guest
>> (svm=off,npt=on,nrip-save=on, plus spec-ctrl) fails to restore
>> without the series with "missing features: npt,nrip-save" and
>> "missing features: spec-ctrl". With it the guest restores, the
>> features stay on and filtered-features is empty. Stock 8.1 libvirt,
>> which carries the same relaxations as hci-8.0, restores it with no
>> warning as well.
>> - sqvm2-1015, Broadwell without TSX: the VSTOR-75689 guest CPU fails
>> with "missing features: hle,rtm" without the series and keeps hle
>> and rtm with it.
>> - sqvm2-1013 <-> sqvm2-1015, with the libvirt PR: live migration in
>> both directions of a pc-i440fx-vz7.12.0 host-passthrough guest and
>> of the VSTOR-75689 Broadwell-IBRS guest. No crash, no warning,
>> hle/rtm kept, the CPU stays match='exact'. Stock libvirt crashes on
>> the first of them.
>> - hci-8.0 and hci-8.1 builds: -cpu EPYC-Milan,svm=off,npt=on,
>> nrip-save=on,enforce and -cpu EPYC-Milan,spec-ctrl=on,enforce start
>> on vz7.12.0, vz9.0.0 and vz9.2.0 and are refused on vz10.x. A fresh
>> Broadwell-IBRS start with check='full' is refused on vz10.1.0.
>> - both builds, TCG: -cpu EPYC-Milan,svm=off warns about the same
>> features on vz9.2.0 as on vz10.0.0, none from leaf 0x8000000a.
>> - both builds, qtest-x86_64: ivshmem-test, test-hmp and qom-test fail
>> as on the base (qemu_ram_free assertion, isapc aborting at start).
>> - both builds, spec-ctrl on vz9.2.0 and vz7.16.0: EPYC-Milan with
>> spec-ctrl=on,enforce starts, also with only one of ibrs, amd-stibp
>> and amd-ssbd left; EPYC-IBPB, or EPYC-Milan without ibpb or without
>> all three, is refused. Everything is refused on vz10.1.0.
>> - bus-lock-detect and v-vmsave-vmload are build-tested only: no Zen 5
>> or Zen 4 client host was available.
>>
>> Changes v2 -> v3:
>> - 3/6: keep spec-ctrl only when the guest also has the amd-* bits that
>> give it the MSRs, not only the host (Andrey)
>> - 2/6: pc_vz_9_2_compat first in the vz7.16.0 row (Andrey); TSX_CTRL
>> makes XBEGIN abort, not #UD, and libvirt check='partial' still
>> refuses a fresh start
>> - 5/6, 6/6: commit messages clarified
>> - R-b on 1/6, A-b on 2/6, 4/6, 5/6 and 6/6
>>
>> Changes v1 -> v2:
>> - 6/6: keep SVM leaf features past the svm dependency under KVM only,
>> TCG warned about them
>> - 2/6, 6/6, cover: commit messages clarified after the Sashiko review
>>
>> v2: http://lore.virtuozzo.com/qemu/20261029113436.93521-1-den@openvz.org/
>> v1: http://lore.virtuozzo.com/kernel/20261029095645.4173762-1-den@openvz.org/
>>
>> Signed-off-by: Denis V. Lunev <den@openvz.org>
>>
>> Denis V. Lunev (6):
>> i386/pc: raise the limit of compat arrays per Virtuozzo machine type
>> to four #VSTOR-152264
>> i386: keep hle and rtm on Virtuozzo machine types up to vz9.2.0
>> #PSBM-149402
>> i386: keep spec-ctrl for AMD guests on vz machine types up to vz9.2.0
>> #VSTOR-151770
>> i386: keep bus-lock-detect for AMD guests on vz machine types up to
>> vz9.2.0 #VSTOR-152291
>> i386: keep v-vmsave-vmload for nested AMD guests on vz types up to
>> vz9.2.0 #VSTOR-152264
>> i386: keep SVM leaf features without svm on vz types up to vz9.2.0
>> #PSBM-144630
>>
>> hw/i386/pc.c | 9 ++++++
>> hw/i386/pc_piix.c | 5 ++--
>> hw/i386/pc_q35.c | 4 +--
>> include/hw/i386/pc.h | 10 +++++--
>> target/i386/cpu.c | 68 +++++++++++++++++++++++++++++++++++++++++++-
>> target/i386/cpu.h | 11 +++++++
>> 6 files changed, 100 insertions(+), 7 deletions(-)
>
> Major: vz10.x AMD guests from 55.x-kernel nodes are left out (patch 3 / cover letter)
> - The SPEC_CTRL gate change (AMD_IBPB_RET required) entered vzkernel with the RHEL 10.1 import, commit 9f055df113432, first tag rh10-6.12.0-211.16.1..vz10.
> All earlier vz10 kernels (rh10-6.12.0-55..vz10) still advertise spec-ctrl on every AMD host with IBPB+IBRS, i.e. on Zen 1-3.
> - Release-kernel tags rk-6.12.0-55.52.1.5.28.vz10-v10.2 and rk-6.12.0-55.52.1.5.22.vz10-v10.3 show shipped 8.0 nodes ran 55.x. Host-model guests started
> there carry vz10.0.0/vz10.1.0 and spec-ctrl as require.
> - After such a node moves to a 211.x kernel those guests fail migration, restore and revert exactly as in VSTOR-151770, but pc_vz_9_2_compat does not apply
> to vz10.x. The libvirt kludge being reverted in PR 392 (d7e2f96f877f) covered every machine type, so the pair of series regresses this population relative to the kludge.
> - Fix: enable x-spec-ctrl-compat for vz10.0.0 and vz10.1.0 as well, with only the next new type strict, or keep the libvirt spec-ctrl kludge until then. The other four properties are fine at vz9.2.0: BLD and VMSAVE/VMLOAD changes are in every vz10 kernel, TSX is host-config, not kernel-version.
>
> Medium: tsx_compat has no host guard (patch 2)
> - kept = HLE|RTM whenever the vendor is Intel. The message says it "also covers Haswell parts with the TSX erratum" and that XBEGIN aborts. On
> HSW136-microcode parts and on silicon without TSX, XBEGIN raises #UD, so a guest that selected RTM paths at startup gets SIGILL.
> - Not a regression against the libvirt skip, which had the same hole, but the message overclaims. Guard suggestion: keep only when the host still has TSX
> silicon, i.e. ARCH_CAPABILITIES.TSX_CTRL, CPUID.7.EDX rtm-always-abort or tsx-force-abort, and never when host_tsx_broken().
>
> Low: Hygon hosts excluded (patches 3, 4)
> - IS_AMD_CPU matches AuthenticAMD only. Dhyana (Zen 1) hosts lose spec-ctrl on 211.x the same way and get nothing from the series. Add the HygonGenuine
> vendor check if Hygon is in the fleet.
>
> Low: bus-lock-detect kept bit on 211.x (patch 4)
> - svm_set_msr rejects any DEBUGCTL bit but LBR (DEBUGCTL_RESERVED_BITS = ~DEBUGCTLMSR_LBR), so a rebooted guest enabling BLD gets #GP and one "unchecked MSR access error" splat. A migrated guest loses BLD silently since QEMU does not migrate DEBUGCTL. Cosmetic, worth a sentence in the message.
>
Disregard this. .211 is the first VZ10 kernel in our production.
Ack for the series
Applied onto hci-dev
^ permalink raw reply [flat|nested] 15+ messages in thread