From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 3316E1FF139 for ; Tue, 27 Jan 2026 14:47:06 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 04FF123DE2; Tue, 27 Jan 2026 14:47:05 +0100 (CET) From: Fiona Ebner To: pve-devel@lists.proxmox.com Date: Tue, 27 Jan 2026 14:46:13 +0100 Message-ID: <20260127134626.127432-6-f.ebner@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260127134626.127432-1-f.ebner@proxmox.com> References: <20260127134626.127432-1-f.ebner@proxmox.com> MIME-Version: 1.0 X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1769521525329 X-SPAM-LEVEL: Spam detection results: 0 AWL -0.015 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 SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pve-devel] [PATCH qemu-server 5/6] cpu config: support aarch64 CPU models X-BeenThere: pve-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox VE development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Proxmox VE development discussion Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pve-devel-bounces@lists.proxmox.com Sender: "pve-devel" Previously, only the default 'cortex-a57' CPU model would be used implicitly. Group models and built-in models by architecture, since that is what (most) use sites are interested in. Note that the 'host' model only exists if the host arch matches the emulator/vCPU arch. Some use sites do require a list of all possible ones, e.g. custom types, because they are not namespaced by arch. Signed-off-by: Fiona Ebner --- src/PVE/QemuServer/CPUConfig.pm | 289 ++++++++++++++++++-------------- 1 file changed, 167 insertions(+), 122 deletions(-) diff --git a/src/PVE/QemuServer/CPUConfig.pm b/src/PVE/QemuServer/CPUConfig.pm index 2825da46..00d56b22 100644 --- a/src/PVE/QemuServer/CPUConfig.pm +++ b/src/PVE/QemuServer/CPUConfig.pm @@ -52,27 +52,37 @@ sub load_custom_model_conf { } #builtin models : reported-model is mandatory -my $builtin_models = { - 'x86-64-v2' => { - 'reported-model' => 'qemu64', - flags => "+popcnt;+pni;+sse4.1;+sse4.2;+ssse3", - }, - 'x86-64-v2-AES' => { - 'reported-model' => 'qemu64', - flags => "+aes;+popcnt;+pni;+sse4.1;+sse4.2;+ssse3", - }, - 'x86-64-v3' => { - 'reported-model' => 'qemu64', - flags => - "+aes;+popcnt;+pni;+sse4.1;+sse4.2;+ssse3;+avx;+avx2;+bmi1;+bmi2;+f16c;+fma;+abm;+movbe;+xsave", - }, - 'x86-64-v4' => { - 'reported-model' => 'qemu64', - flags => - "+aes;+popcnt;+pni;+sse4.1;+sse4.2;+ssse3;+avx;+avx2;+bmi1;+bmi2;+f16c;+fma;+abm;+movbe;+xsave;+avx512f;+avx512bw;+avx512cd;+avx512dq;+avx512vl", +my $builtin_models_by_arch = { + x86_64 => { + 'x86-64-v2' => { + 'reported-model' => 'qemu64', + flags => "+popcnt;+pni;+sse4.1;+sse4.2;+ssse3", + }, + 'x86-64-v2-AES' => { + 'reported-model' => 'qemu64', + flags => "+aes;+popcnt;+pni;+sse4.1;+sse4.2;+ssse3", + }, + 'x86-64-v3' => { + 'reported-model' => 'qemu64', + flags => + "+aes;+popcnt;+pni;+sse4.1;+sse4.2;+ssse3;+avx;+avx2;+bmi1;+bmi2;+f16c;+fma;+abm;+movbe;+xsave", + }, + 'x86-64-v4' => { + 'reported-model' => 'qemu64', + flags => + "+aes;+popcnt;+pni;+sse4.1;+sse4.2;+ssse3;+avx;+avx2;+bmi1;+bmi2;+f16c;+fma;+abm;+movbe;+xsave;+avx512f;+avx512bw;+avx512cd;+avx512dq;+avx512vl", + }, }, + aarch64 => {}, }; +my $all_builtin_models; +for my $arch (keys $builtin_models_by_arch->%*) { + for my $model (keys $builtin_models_by_arch->{$arch}->%*) { + $all_builtin_models->{$model} = $builtin_models_by_arch->{$arch}->{$model}; + } +} + my $depreacated_cpu_map = { # there never was such a client CPU, so map it to the server one for backward compat 'Icelake-Client' => 'Icelake-Server', @@ -90,104 +100,130 @@ my $cputypes_32bit = { 'qemu32' => 1, }; -my $cpu_vendor_list = { - # Intel CPUs - 486 => 'GenuineIntel', - pentium => 'GenuineIntel', - pentium2 => 'GenuineIntel', - pentium3 => 'GenuineIntel', - coreduo => 'GenuineIntel', - core2duo => 'GenuineIntel', - Conroe => 'GenuineIntel', - Penryn => 'GenuineIntel', - Nehalem => 'GenuineIntel', - 'Nehalem-IBRS' => 'GenuineIntel', - Westmere => 'GenuineIntel', - 'Westmere-IBRS' => 'GenuineIntel', - SandyBridge => 'GenuineIntel', - 'SandyBridge-IBRS' => 'GenuineIntel', - IvyBridge => 'GenuineIntel', - 'IvyBridge-IBRS' => 'GenuineIntel', - Haswell => 'GenuineIntel', - 'Haswell-IBRS' => 'GenuineIntel', - 'Haswell-noTSX' => 'GenuineIntel', - 'Haswell-noTSX-IBRS' => 'GenuineIntel', - Broadwell => 'GenuineIntel', - 'Broadwell-IBRS' => 'GenuineIntel', - 'Broadwell-noTSX' => 'GenuineIntel', - 'Broadwell-noTSX-IBRS' => 'GenuineIntel', - 'Skylake-Client' => 'GenuineIntel', - 'Skylake-Client-IBRS' => 'GenuineIntel', - 'Skylake-Client-noTSX-IBRS' => 'GenuineIntel', - 'Skylake-Client-v4' => 'GenuineIntel', - 'Skylake-Server' => 'GenuineIntel', - 'Skylake-Server-IBRS' => 'GenuineIntel', - 'Skylake-Server-noTSX-IBRS' => 'GenuineIntel', - 'Skylake-Server-v4' => 'GenuineIntel', - 'Skylake-Server-v5' => 'GenuineIntel', - 'Cascadelake-Server' => 'GenuineIntel', - 'Cascadelake-Server-v2' => 'GenuineIntel', - 'Cascadelake-Server-noTSX' => 'GenuineIntel', - 'Cascadelake-Server-v4' => 'GenuineIntel', - 'Cascadelake-Server-v5' => 'GenuineIntel', - 'Cooperlake' => 'GenuineIntel', - 'Cooperlake-v2' => 'GenuineIntel', - KnightsMill => 'GenuineIntel', - 'Icelake-Client' => 'GenuineIntel', # depreacated, removed with QEMU 7.1 - 'Icelake-Client-noTSX' => 'GenuineIntel', # depreacated, removed with QEMU 7.1 - 'Icelake-Server' => 'GenuineIntel', - 'Icelake-Server-noTSX' => 'GenuineIntel', - 'Icelake-Server-v3' => 'GenuineIntel', - 'Icelake-Server-v4' => 'GenuineIntel', - 'Icelake-Server-v5' => 'GenuineIntel', - 'Icelake-Server-v6' => 'GenuineIntel', - 'Icelake-Server-v7' => 'GenuineIntel', - 'SapphireRapids' => 'GenuineIntel', - 'SapphireRapids-v2' => 'GenuineIntel', - 'SapphireRapids-v3' => 'GenuineIntel', - 'SapphireRapids-v4' => 'GenuineIntel', - 'GraniteRapids' => 'GenuineIntel', - 'GraniteRapids-v2' => 'GenuineIntel', - 'GraniteRapids-v3' => 'GenuineIntel', - 'SierraForest' => 'GenuineIntel', - 'SierraForest-v2' => 'GenuineIntel', - 'SierraForest-v3' => 'GenuineIntel', - 'ClearwaterForest' => 'GenuineIntel', +my $cpu_models_by_arch = { + x86_64 => { + # Intel CPUs + 486 => 'GenuineIntel', + pentium => 'GenuineIntel', + pentium2 => 'GenuineIntel', + pentium3 => 'GenuineIntel', + coreduo => 'GenuineIntel', + core2duo => 'GenuineIntel', + Conroe => 'GenuineIntel', + Penryn => 'GenuineIntel', + Nehalem => 'GenuineIntel', + 'Nehalem-IBRS' => 'GenuineIntel', + Westmere => 'GenuineIntel', + 'Westmere-IBRS' => 'GenuineIntel', + SandyBridge => 'GenuineIntel', + 'SandyBridge-IBRS' => 'GenuineIntel', + IvyBridge => 'GenuineIntel', + 'IvyBridge-IBRS' => 'GenuineIntel', + Haswell => 'GenuineIntel', + 'Haswell-IBRS' => 'GenuineIntel', + 'Haswell-noTSX' => 'GenuineIntel', + 'Haswell-noTSX-IBRS' => 'GenuineIntel', + Broadwell => 'GenuineIntel', + 'Broadwell-IBRS' => 'GenuineIntel', + 'Broadwell-noTSX' => 'GenuineIntel', + 'Broadwell-noTSX-IBRS' => 'GenuineIntel', + 'Skylake-Client' => 'GenuineIntel', + 'Skylake-Client-IBRS' => 'GenuineIntel', + 'Skylake-Client-noTSX-IBRS' => 'GenuineIntel', + 'Skylake-Client-v4' => 'GenuineIntel', + 'Skylake-Server' => 'GenuineIntel', + 'Skylake-Server-IBRS' => 'GenuineIntel', + 'Skylake-Server-noTSX-IBRS' => 'GenuineIntel', + 'Skylake-Server-v4' => 'GenuineIntel', + 'Skylake-Server-v5' => 'GenuineIntel', + 'Cascadelake-Server' => 'GenuineIntel', + 'Cascadelake-Server-v2' => 'GenuineIntel', + 'Cascadelake-Server-noTSX' => 'GenuineIntel', + 'Cascadelake-Server-v4' => 'GenuineIntel', + 'Cascadelake-Server-v5' => 'GenuineIntel', + 'Cooperlake' => 'GenuineIntel', + 'Cooperlake-v2' => 'GenuineIntel', + KnightsMill => 'GenuineIntel', + 'Icelake-Client' => 'GenuineIntel', # depreacated, removed with QEMU 7.1 + 'Icelake-Client-noTSX' => 'GenuineIntel', # depreacated, removed with QEMU 7.1 + 'Icelake-Server' => 'GenuineIntel', + 'Icelake-Server-noTSX' => 'GenuineIntel', + 'Icelake-Server-v3' => 'GenuineIntel', + 'Icelake-Server-v4' => 'GenuineIntel', + 'Icelake-Server-v5' => 'GenuineIntel', + 'Icelake-Server-v6' => 'GenuineIntel', + 'Icelake-Server-v7' => 'GenuineIntel', + 'SapphireRapids' => 'GenuineIntel', + 'SapphireRapids-v2' => 'GenuineIntel', + 'SapphireRapids-v3' => 'GenuineIntel', + 'SapphireRapids-v4' => 'GenuineIntel', + 'GraniteRapids' => 'GenuineIntel', + 'GraniteRapids-v2' => 'GenuineIntel', + 'GraniteRapids-v3' => 'GenuineIntel', + 'SierraForest' => 'GenuineIntel', + 'SierraForest-v2' => 'GenuineIntel', + 'SierraForest-v3' => 'GenuineIntel', + 'ClearwaterForest' => 'GenuineIntel', - # AMD CPUs - athlon => 'AuthenticAMD', - phenom => 'AuthenticAMD', - Opteron_G1 => 'AuthenticAMD', - Opteron_G2 => 'AuthenticAMD', - Opteron_G3 => 'AuthenticAMD', - Opteron_G4 => 'AuthenticAMD', - Opteron_G5 => 'AuthenticAMD', - EPYC => 'AuthenticAMD', - 'EPYC-IBPB' => 'AuthenticAMD', - 'EPYC-v3' => 'AuthenticAMD', - 'EPYC-v4' => 'AuthenticAMD', - 'EPYC-v5' => 'AuthenticAMD', - 'EPYC-Rome' => 'AuthenticAMD', - 'EPYC-Rome-v2' => 'AuthenticAMD', - 'EPYC-Rome-v3' => 'AuthenticAMD', - 'EPYC-Rome-v4' => 'AuthenticAMD', - 'EPYC-Rome-v5' => 'AuthenticAMD', - 'EPYC-Milan' => 'AuthenticAMD', - 'EPYC-Milan-v2' => 'AuthenticAMD', - 'EPYC-Milan-v3' => 'AuthenticAMD', - 'EPYC-Genoa' => 'AuthenticAMD', - 'EPYC-Genoa-v2' => 'AuthenticAMD', - 'EPYC-Turin' => 'AuthenticAMD', + # AMD CPUs + athlon => 'AuthenticAMD', + phenom => 'AuthenticAMD', + Opteron_G1 => 'AuthenticAMD', + Opteron_G2 => 'AuthenticAMD', + Opteron_G3 => 'AuthenticAMD', + Opteron_G4 => 'AuthenticAMD', + Opteron_G5 => 'AuthenticAMD', + EPYC => 'AuthenticAMD', + 'EPYC-IBPB' => 'AuthenticAMD', + 'EPYC-v3' => 'AuthenticAMD', + 'EPYC-v4' => 'AuthenticAMD', + 'EPYC-v5' => 'AuthenticAMD', + 'EPYC-Rome' => 'AuthenticAMD', + 'EPYC-Rome-v2' => 'AuthenticAMD', + 'EPYC-Rome-v3' => 'AuthenticAMD', + 'EPYC-Rome-v4' => 'AuthenticAMD', + 'EPYC-Rome-v5' => 'AuthenticAMD', + 'EPYC-Milan' => 'AuthenticAMD', + 'EPYC-Milan-v2' => 'AuthenticAMD', + 'EPYC-Milan-v3' => 'AuthenticAMD', + 'EPYC-Genoa' => 'AuthenticAMD', + 'EPYC-Genoa-v2' => 'AuthenticAMD', + 'EPYC-Turin' => 'AuthenticAMD', - # generic types, use vendor from host node - host => 'default', - kvm32 => 'default', - kvm64 => 'default', - qemu32 => 'default', - qemu64 => 'default', - max => 'default', + # generic types, use vendor from host node + kvm32 => 'default', + kvm64 => 'default', + qemu32 => 'default', + qemu64 => 'default', + max => 'default', + }, + aarch64 => { + 'a64fx' => 'ARM', + 'cortex-a35' => 'ARM', + 'cortex-a53' => 'ARM', + 'cortex-a55' => 'ARM', + 'cortex-a57' => 'ARM', + 'cortex-a710' => 'ARM', + 'cortex-a72' => 'ARM', + 'cortex-a76' => 'ARM', + 'neoverse-n1' => 'ARM', + 'neoverse-n2' => 'ARM', + 'neoverse-v1' => 'ARM', + # 32 bit and deprecated models were not added + max => 'default', + }, }; +# The host CPU model only exists if the arch matches +$cpu_models_by_arch->{$host_arch}->{host} = 'default'; + +my $all_cpu_models; +for my $arch (keys $cpu_models_by_arch->%*) { + for my $model (keys $cpu_models_by_arch->{$arch}->%*) { + $all_cpu_models->{$model} = $cpu_models_by_arch->{$arch}->{$model}; + } +} + my $supported_cpu_flags = [ { name => 'nested-virt', @@ -274,7 +310,7 @@ my $cpu_fmt = { "CPU model and vendor to report to the guest. Must be a QEMU/KVM supported model." . " Only valid for custom CPU model definitions, default models will always report themselves to the guest OS.", type => 'string', - enum => [sort { lc("$a") cmp lc("$b") } keys %$cpu_vendor_list], + enum => [sort { lc("$a") cmp lc("$b") } keys $all_cpu_models->%*], default => 'kvm64', optional => 1, }, @@ -439,7 +475,7 @@ sub validate_vm_cpu_conf { if (is_custom_model($cputype)) { # dies on unknown model get_custom_model($cputype); - } elsif (!defined($cpu_vendor_list->{$cputype}) && !defined($builtin_models->{$cputype})) { + } elsif (!defined($all_cpu_models->{$cputype}) && !defined($all_builtin_models->{$cputype})) { die "Built-in cputype '$cputype' is not defined (missing 'custom-' prefix?)\n"; } @@ -529,7 +565,10 @@ sub add_cpu_json_properties { } sub get_cpu_models { - my ($include_custom) = @_; + my ($include_custom, $arch) = @_; + + $arch = $host_arch if !defined($arch); + my $cpu_vendor_list = $cpu_models_by_arch->{$arch}; my $models = []; @@ -542,6 +581,7 @@ sub get_cpu_models { }; } + my $builtin_models = $builtin_models_by_arch->{$arch}; for my $model (keys %{$builtin_models}) { my $reported_model = $builtin_models->{$model}->{'reported-model'}; my $vendor = $cpu_vendor_list->{$reported_model}; @@ -559,7 +599,7 @@ sub get_cpu_models { for my $custom_model (keys %{ $conf->{ids} }) { my $reported_model = $conf->{ids}->{$custom_model}->{'reported-model'}; $reported_model //= $cpu_fmt->{'reported-model'}->{default}; - my $vendor = $cpu_vendor_list->{$reported_model}; + my $vendor = $all_cpu_models->{$reported_model}; push @$models, { name => "custom-$custom_model", @@ -614,6 +654,7 @@ sub print_cpu_device { or die "Cannot parse cpu description: $cputype\n"; $cpu = $cpuconf->{cputype}; + my $builtin_models = $builtin_models_by_arch->{$arch}; if (my $model = $builtin_models->{$cpu}) { $cpu = $model->{'reported-model'}; } elsif (is_custom_model($cputype)) { @@ -792,6 +833,7 @@ sub get_cpu_options { or die "Cannot parse cpu description: $cpu_prop_str\n"; $cputype = $cpu->{cputype}; + my $builtin_models = $builtin_models_by_arch->{$arch}; if (my $model = $builtin_models->{$cputype}) { $cputype = $model->{'reported-model'}; $builtin_cpu->{flags} = $model->{'flags'}; @@ -812,6 +854,9 @@ sub get_cpu_options { $hv_vendor_id = $cpu->{'hv-vendor-id'} if defined($cpu->{'hv-vendor-id'}); } + die "CPU model '$cputype' does not exist for configured vCPU architecture '$arch'\n" + if !defined($cpu_models_by_arch->{$arch}->{$cputype}); + my $pve_flags = get_pve_cpu_flags($conf, $kvm, $cputype, $arch, $machine_version); my $hv_flags; @@ -846,13 +891,12 @@ sub get_cpu_options { }; } - # $cputype is the "reported-model" for custom types, so we can just look up - # the vendor in the default list - my $cpu_vendor = $cpu_vendor_list->{$cputype}; - if ($cpu_vendor) { + # For aarch64, QEMU does not have a vendor property for the -cpu commandline. + if ($arch eq 'x86_64') { + # $cputype is the "reported-model" for custom types, so we can just look up + # the vendor in the default list + my $cpu_vendor = $cpu_models_by_arch->{$arch}->{$cputype} or die "internal error"; $pve_forced_flags->{'vendor'} = { value => $cpu_vendor } if $cpu_vendor ne 'default'; - } elsif ($arch ne 'aarch64') { - die "internal error"; # should not happen } my $cpu_str = $cputype; @@ -1034,6 +1078,7 @@ sub get_cpu_bitness { $cputype = $cpu->{cputype}; + my $builtin_models = $builtin_models_by_arch->{$arch}; if (my $model = $builtin_models->{$cputype}) { $cputype = $model->{'reported-model'}; } elsif (is_custom_model($cputype)) { -- 2.47.3 _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel