all lists on lists.proxmox.com
 help / color / mirror / Atom feed
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


  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.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal