From: Fiona Ebner <f.ebner@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH qemu-server 5/6] cpu config: support aarch64 CPU models
Date: Tue, 27 Jan 2026 14:46:13 +0100 [thread overview]
Message-ID: <20260127134626.127432-6-f.ebner@proxmox.com> (raw)
In-Reply-To: <20260127134626.127432-1-f.ebner@proxmox.com>
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 <f.ebner@proxmox.com>
---
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
next prev parent reply other threads:[~2026-01-27 13:47 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-27 13:46 [pve-devel] [PATCH-SERIES qemu-server 0/6] " Fiona Ebner
2026-01-27 13:46 ` [pve-devel] [PATCH qemu-server 1/6] cpu config: introduce pve-qm-cpu-arch standard option for virtual CPU architecture Fiona Ebner
2026-01-27 13:46 ` [pve-devel] [PATCH qemu-server 2/6] cpu config: guard adding hyperv enlightenments by arch Fiona Ebner
2026-01-27 13:46 ` [pve-devel] [PATCH qemu-server 3/6] cpu config: 'hidden' option only applies to vCPUs with x86_64 arch Fiona Ebner
2026-01-27 13:46 ` [pve-devel] [PATCH qemu-server 4/6] cpu config: introduce module-wide $host_arch variable Fiona Ebner
2026-01-27 13:46 ` Fiona Ebner [this message]
2026-01-27 13:46 ` [pve-devel] [PATCH qemu-server 6/6] api: cpu: allow querying CPU models for a given architecture Fiona Ebner
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=20260127134626.127432-6-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.