From: Fiona Ebner <f.ebner@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH qemu-server] cpu config: expose CPU 'level' property required for certain host/guest configurations
Date: Mon, 18 May 2026 14:40:09 +0200 [thread overview]
Message-ID: <20260518124018.148829-1-f.ebner@proxmox.com> (raw)
As reported in the community forum in 2024 [0] already, with somewhat
recent Intel CPUs, Windows guests with Hyper-V enabled will fail to
boot with certain CPU types like 'host' or 'max'. A workaround is
using 'level=30' in the '-cpu' QEMU commandline. The 'level' property
is currently not exposed, so users were forced to use custom 'args',
which means they lose other CPU configuration made by Proxmox VE.
Expose the 'level' setting, so it can be done without custom args.
While the problem is not new, it will become more common, since
virtualization-based security is being adapted more broadly.
[0]: https://forum.proxmox.com/threads/131950/post-642093
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
---
src/PVE/QemuServer/CPUConfig.pm | 18 ++++++++++++++++++
src/test/cfg2cmd/cpu-level.conf | 6 ++++++
src/test/cfg2cmd/cpu-level.conf.cmd | 26 ++++++++++++++++++++++++++
3 files changed, 50 insertions(+)
create mode 100644 src/test/cfg2cmd/cpu-level.conf
create mode 100644 src/test/cfg2cmd/cpu-level.conf.cmd
diff --git a/src/PVE/QemuServer/CPUConfig.pm b/src/PVE/QemuServer/CPUConfig.pm
index 2c30a5db..39d1767f 100644
--- a/src/PVE/QemuServer/CPUConfig.pm
+++ b/src/PVE/QemuServer/CPUConfig.pm
@@ -355,6 +355,16 @@ my $cpu_fmt = {
. " note that doing so will break live migration to CPUs with other values.",
optional => 1,
},
+ 'level' => {
+ type => 'integer',
+ minimum => 0,
+ maximum => 4294967295, # It's a uint32_t in QEMU
+ description =>
+ "The CPUID topology level. Limits the topology presented by the virtual CPU, in "
+ . " particular, limits the set of CPUID leaves. Only applies when the vCPU architecture"
+ . " is x86_64.",
+ optional => 1,
+ },
};
PVE::JSONSchema::register_standard_option('pve-qm-custom-cpu-model', $cpu_fmt);
@@ -910,6 +920,14 @@ sub get_cpu_options(
my $cpu_str = $cputype;
+ if (defined(my $level = $cpu->{level} // $custom_cpu->{level})) {
+ if ($arch eq 'x86_64') {
+ $cpu_str .= ",level=${level}";
+ } else {
+ warn "CPU 'level' property is ignored for architecture '$arch'\n";
+ }
+ }
+
# will be resolved in parameter order
my $resolved_flags = resolve_cpu_flags(
$pve_flags,
diff --git a/src/test/cfg2cmd/cpu-level.conf b/src/test/cfg2cmd/cpu-level.conf
new file mode 100644
index 00000000..1ce1e6a9
--- /dev/null
+++ b/src/test/cfg2cmd/cpu-level.conf
@@ -0,0 +1,6 @@
+# TEST: Test for a configuration where the 'level' option and some flags are set for a CPU
+cpu: host,level=30,flags=+md-clear;+pdpe1gb;-hv-tlbflush
+memory: 768
+numa: 0
+ostype: win11
+sockets: 1
diff --git a/src/test/cfg2cmd/cpu-level.conf.cmd b/src/test/cfg2cmd/cpu-level.conf.cmd
new file mode 100644
index 00000000..d276a6de
--- /dev/null
+++ b/src/test/cfg2cmd/cpu-level.conf.cmd
@@ -0,0 +1,26 @@
+/usr/bin/kvm \
+ -id 8006 \
+ -name vm8006 \
+ -no-shutdown \
+ -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \
+ -mon 'chardev=qmp,mode=control' \
+ -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect-ms=5000' \
+ -mon 'chardev=qmp-event,mode=control' \
+ -pidfile /var/run/qemu-server/8006.pid \
+ -daemonize \
+ -smp '1,sockets=1,cores=1,maxcpus=1' \
+ -nodefaults \
+ -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \
+ -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \
+ -global 'kvm-pit.lost_tick_policy=discard' \
+ -cpu 'host,level=30,-cet-ibt,-cet-ss,-hv-tlbflush,hv_ipi,hv_relaxed,hv_reset,hv_runtime,hv_spinlocks=0x1fff,hv_stimer,hv_synic,hv_time,hv_vapic,hv_vpindex,+kvm_pv_eoi,+kvm_pv_unhalt,+md-clear,+pdpe1gb' \
+ -m 768 \
+ -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \
+ -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \
+ -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \
+ -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \
+ -device 'VGA,id=vga,bus=pci.0,addr=0x2,edid=off' \
+ -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3' \
+ -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \
+ -rtc 'driftfix=slew,base=localtime' \
+ -machine 'hpet=off,type=pc-i440fx-5.1+pve0'
--
2.47.3
next reply other threads:[~2026-05-18 12:41 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-18 12:40 Fiona Ebner [this message]
2026-05-18 14:00 ` [PATCH qemu-server] cpu config: expose CPU 'level' property required for certain host/guest configurations David Riley
2026-05-18 15:59 ` applied: " Thomas Lamprecht
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=20260518124018.148829-1-f.ebner@proxmox.com \
--to=f.ebner@proxmox.com \
--cc=pve-devel@lists.proxmox.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