From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id E96561FF13A for ; Wed, 01 Apr 2026 10:00:55 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 0F59411CFA; Wed, 1 Apr 2026 10:00:41 +0200 (CEST) From: Arthur Bied-Charreton To: pve-devel@lists.proxmox.com Subject: [PATCH qemu-server v2 03/17] cpu flags: Create CPUFlags module Date: Wed, 1 Apr 2026 10:00:14 +0200 Message-ID: <20260401080028.62513-4-a.bied-charreton@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260401080028.62513-1-a.bied-charreton@proxmox.com> References: <20260401080028.62513-1-a.bied-charreton@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.119 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Message-ID-Hash: XI3YQBSNYNQT73XFJ3JV4U7FD4VHLCF4 X-Message-ID-Hash: XI3YQBSNYNQT73XFJ3JV4U7FD4VHLCF4 X-MailFrom: abied-charreton@jett.proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Introduce PVE::QemuServer::CPUFlags module as the new home for cpu flags-related helpers, and move various utilities from QemuServer and CPUConfig into it. `query_supported_cpu_flags` is not yet moved to the new module, as it is trickier to migrate without creating circular dependencies. Signed-off-by: Arthur Bied-Charreton --- src/PVE/QemuServer.pm | 24 +----- src/PVE/QemuServer/CPUConfig.pm | 89 ++-------------------- src/PVE/QemuServer/CPUFlags.pm | 126 ++++++++++++++++++++++++++++++++ src/PVE/QemuServer/Makefile | 1 + 4 files changed, 136 insertions(+), 104 deletions(-) create mode 100644 src/PVE/QemuServer/CPUFlags.pm diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 856dc737..9cea859f 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -2917,9 +2917,10 @@ sub vga_conf_has_spice { return $1 || 1; } -# To use query_supported_cpu_flags and query_understood_cpu_flags to get flags -# to use in a QEMU command line (-cpu element), first array_intersect the result -# of query_supported_ with query_understood_. This is necessary because: +# To use query_supported_cpu_flags and query_understood_cpu_flags (moved to the +# PVE::QemuServer::CPUFlags module) to get flags to use in a QEMU command line +# (-cpu element), first array_intersect the result of query_supported_ with +# query_understood_. This is necessary because: # # a) query_understood_ returns flags the host cannot use and # b) query_supported_ (rather the QMP call) doesn't actually return CPU @@ -3026,23 +3027,6 @@ sub query_supported_cpu_flags { return $flags; } -# Understood CPU flags are written to a file at 'pve-qemu' compile time -my $understood_cpu_flag_dir = "/usr/share/kvm"; - -sub query_understood_cpu_flags { - my $arch = get_host_arch(); - my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch"; - - die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n" - if !-e $filepath; - - my $raw = file_get_contents($filepath); - $raw =~ s/^\s+|\s+$//g; - my @flags = split(/\s+/, $raw); - - return \@flags; -} - # Since commit 277d33454f77ec1d1e0bc04e37621e4dd2424b67 in pve-qemu, smm is not off by default # anymore. But smm=off seems to be required when using SeaBIOS and serial display. my sub should_disable_smm { diff --git a/src/PVE/QemuServer/CPUConfig.pm b/src/PVE/QemuServer/CPUConfig.pm index 7adfdf45..0ee9b991 100644 --- a/src/PVE/QemuServer/CPUConfig.pm +++ b/src/PVE/QemuServer/CPUConfig.pm @@ -12,6 +12,7 @@ use PVE::RESTEnvironment qw(log_warn); use PVE::Tools qw(run_command); use PVE::QemuServer::Helpers qw(min_version get_host_arch); +use PVE::QemuServer::CPUFlags qw(cpu_flag_supported_re cpu_flag_any_re supported_cpu_flags_names); use base qw(PVE::SectionConfig Exporter); @@ -261,89 +262,9 @@ sub get_all_cpu_models { return $all_cpu_models; } -my $supported_cpu_flags_by_arch = { - x86_64 => [ - { - name => 'nested-virt', - description => - "Controls nested virtualization, namely 'svm' for AMD CPUs and 'vmx' for" - . " Intel CPUs. Live migration still only works if it's the same flag on both sides." - . " Use a CPU model similar to the host, with the same vendor, not x86-64-vX!", - }, - { - name => 'md-clear', - description => "Required to let the guest OS know if MDS is mitigated correctly.", - }, - { - name => 'pcid', - description => - "Meltdown fix cost reduction on Westmere, Sandy-, and IvyBridge Intel CPUs.", - }, - { - name => 'spec-ctrl', - description => "Allows improved Spectre mitigation with Intel CPUs.", - }, - { - name => 'ssbd', - description => "Protection for 'Speculative Store Bypass' for Intel models.", - }, - { - name => 'ibpb', - description => "Allows improved Spectre mitigation with AMD CPUs.", - }, - { - name => 'virt-ssbd', - description => "Basis for 'Speculative Store Bypass' protection for AMD models.", - }, - { - name => 'amd-ssbd', - description => - "Improves Spectre mitigation performance with AMD CPUs, best used with" - . " 'virt-ssbd'.", - }, - { - name => 'amd-no-ssb', - description => - "Notifies guest OS that host is not vulnerable for Spectre on AMD CPUs.", - }, - { - name => 'pdpe1gb', - description => "Allow guest OS to use 1GB size pages, if host HW supports it.", - }, - { - name => 'hv-tlbflush', - description => - "Improve performance in overcommitted Windows guests. May lead to guest" - . " bluescreens on old CPUs.", - }, - { - name => 'hv-evmcs', - description => - "Improve performance for nested virtualization. Only supported on Intel" . " CPUs.", - }, - { - name => 'aes', - description => "Activate AES instruction set for HW acceleration.", - }, - ], - aarch64 => [], -}; - -sub get_supported_cpu_flags { - my ($arch) = @_; - $arch = get_host_arch() if !defined($arch); - return $supported_cpu_flags_by_arch->{$arch}; -} - -my $all_supported_cpu_flags = {}; -for my $arch ($supported_cpu_flags_by_arch->%*) { - for my $flag ($supported_cpu_flags_by_arch->{$arch}->@*) { - $all_supported_cpu_flags->{ $flag->{name} } = 1; - } -} -my @supported_cpu_flags_names = sort keys $all_supported_cpu_flags->%*; -my $cpu_flag_supported_re = qr/([+-])(@{[join('|', @supported_cpu_flags_names)]})/; -my $cpu_flag_any_re = qr/([+-])([a-zA-Z0-9\-_\.]+)/; +my $cpu_flag_supported_re = cpu_flag_supported_re(); +my $cpu_flag_any_re = cpu_flag_any_re(); +my @supported_cpu_flags_names = (supported_cpu_flags_names()); our $qemu_cmdline_cpu_re = qr/^((?>[+-]?[\w\-\._=]+,?)+)$/; @@ -388,7 +309,7 @@ my $cpu_fmt = { . " controls nested virtualization for the current CPU ('svm' for AMD and 'vmx' for" . " Intel). Custom CPU models can specify any flag supported by QEMU/KVM, VM-specific" . " flags must be from the following set for security reasons: " - . join(', ', @supported_cpu_flags_names), + . join(', ', PVE::QemuServer::CPUFlags::supported_cpu_flags_names()), format_description => '+FLAG[;-FLAG...]', type => 'string', pattern => qr/$cpu_flag_any_re(;$cpu_flag_any_re)*/, diff --git a/src/PVE/QemuServer/CPUFlags.pm b/src/PVE/QemuServer/CPUFlags.pm new file mode 100644 index 00000000..51d7753e --- /dev/null +++ b/src/PVE/QemuServer/CPUFlags.pm @@ -0,0 +1,126 @@ +package PVE::QemuServer::CPUFlags; + +use v5.36; + +use Exporter qw(import); + +use PVE::Cluster; +use PVE::Tools; +use PVE::QemuServer::Helpers qw(get_host_arch); + +our @EXPORT_OK = qw( + cpu_flag_supported_re + cpu_flag_any_re + supported_cpu_flags_names + get_supported_cpu_flags + query_understood_cpu_flags +); + +my $supported_vm_specific_cpu_flags_by_arch = { + x86_64 => [ + { + name => 'nested-virt', + description => + "Controls nested virtualization, namely 'svm' for AMD CPUs and 'vmx' for" + . " Intel CPUs. Live migration still only works if it's the same flag on both sides." + . " Use a CPU model similar to the host, with the same vendor, not x86-64-vX!", + }, + { + name => 'md-clear', + description => "Required to let the guest OS know if MDS is mitigated correctly.", + }, + { + name => 'pcid', + description => + "Meltdown fix cost reduction on Westmere, Sandy-, and IvyBridge Intel CPUs.", + }, + { + name => 'spec-ctrl', + description => "Allows improved Spectre mitigation with Intel CPUs.", + }, + { + name => 'ssbd', + description => "Protection for 'Speculative Store Bypass' for Intel models.", + }, + { + name => 'ibpb', + description => "Allows improved Spectre mitigation with AMD CPUs.", + }, + { + name => 'virt-ssbd', + description => "Basis for 'Speculative Store Bypass' protection for AMD models.", + }, + { + name => 'amd-ssbd', + description => + "Improves Spectre mitigation performance with AMD CPUs, best used with" + . " 'virt-ssbd'.", + }, + { + name => 'amd-no-ssb', + description => + "Notifies guest OS that host is not vulnerable for Spectre on AMD CPUs.", + }, + { + name => 'pdpe1gb', + description => "Allow guest OS to use 1GB size pages, if host HW supports it.", + }, + { + name => 'hv-tlbflush', + description => + "Improve performance in overcommitted Windows guests. May lead to guest" + . " bluescreens on old CPUs.", + }, + { + name => 'hv-evmcs', + description => + "Improve performance for nested virtualization. Only supported on Intel" . " CPUs.", + }, + { + name => 'aes', + description => "Activate AES instruction set for HW acceleration.", + }, + ], + aarch64 => [], +}; + +my $all_supported_vm_specific_cpu_flags = {}; +for my $arch ($supported_vm_specific_cpu_flags_by_arch->%*) { + for my $flag ($supported_vm_specific_cpu_flags_by_arch->{$arch}->@*) { + $all_supported_vm_specific_cpu_flags->{ $flag->{name} } = 1; + } +} + +# Understood CPU flags are written to a file at 'pve-qemu' compile time +my $understood_cpu_flag_dir = "/usr/share/kvm"; + +sub supported_cpu_flags_names() { + return sort keys $all_supported_vm_specific_cpu_flags->%*; +} + +sub cpu_flag_supported_re() { + return qr/([+-])(@{[join('|', supported_cpu_flags_names())]})/; +} + +sub cpu_flag_any_re() { + return qr/([+-])([a-zA-Z0-9\-_\.]+)/; +} + +# Return supported VM-specific CPU flags. +sub get_supported_cpu_flags($arch) { + return $supported_vm_specific_cpu_flags_by_arch->{$arch}; +} + +sub query_understood_cpu_flags($arch) { + my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch"; + + die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n" + if !-e $filepath; + + my $raw = PVE::Tools::file_get_contents($filepath); + $raw =~ s/^\s+|\s+$//g; + my @flags = split(/\s+/, $raw); + + return \@flags; +} +1; diff --git a/src/PVE/QemuServer/Makefile b/src/PVE/QemuServer/Makefile index 7e48c388..c26bdec4 100644 --- a/src/PVE/QemuServer/Makefile +++ b/src/PVE/QemuServer/Makefile @@ -9,6 +9,7 @@ SOURCES=Agent.pm \ CGroup.pm \ Cloudinit.pm \ CPUConfig.pm \ + CPUFlags.pm \ DBusVMState.pm \ Drive.pm \ DriveDevice.pm \ -- 2.47.3