From: "Denis V. Lunev" <den@openvz.org>
To: andrey.zhadchenko@virtuozzo.com
Cc: svt-core@virtuozzo.com, den@openvz.org
Subject: [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
Date: Thu, 29 Oct 2026 13:25:23 +0100 [thread overview]
Message-ID: <20261029122527.365104-3-den@openvz.org> (raw)
In-Reply-To: <20261029122527.365104-1-den@openvz.org>
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
next prev parent reply other threads:[~2026-10-29 12:25 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
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:27 ` no-reply
2026-10-29 12:25 ` Denis V. Lunev [this message]
2026-10-29 12:29 ` [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 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
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
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
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 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
2026-10-29 13:47 ` Andrey Drobyshev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261029122527.365104-3-den@openvz.org \
--to=den@openvz.org \
--cc=andrey.zhadchenko@virtuozzo.com \
--cc=svt-core@virtuozzo.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox