]> git.proxmox.com Git - qemu-server.git/commitdiff
Add CPUConfig file and migrate some helpers
authorStefan Reiter <s.reiter@proxmox.com>
Thu, 16 Jan 2020 15:40:48 +0000 (16:40 +0100)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Wed, 22 Jan 2020 14:47:32 +0000 (15:47 +0100)
The package will be used for custom CPU models as a SectionConfig, hence
the name. For now we simply move some CPU related helper functions and
declarations over from QemuServer to reduce clutter there.

Exports are to avoid changing all call sites, functions have useful
names on their own.

Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
PVE/QemuServer.pm
PVE/QemuServer/CPUConfig.pm [new file with mode: 0644]
PVE/QemuServer/Makefile

index bcdadca9b6b14466fe50730f1a884b428e01426e..7374bf1d1234d90f61c1ca45a794f99aefe4e7b3 100644 (file)
@@ -43,6 +43,7 @@ use PVE::QMPClient;
 use PVE::QemuConfig;
 use PVE::QemuServer::Helpers qw(min_version config_aware_timeout);
 use PVE::QemuServer::Cloudinit;
+use PVE::QemuServer::CPUConfig qw(print_cpu_device get_cpu_options);
 use PVE::QemuServer::Machine;
 use PVE::QemuServer::Memory;
 use PVE::QemuServer::Monitor qw(mon_cmd);
@@ -114,108 +115,6 @@ sub nodename {
     return $nodename_cache;
 }
 
-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-Server' => 'GenuineIntel',
-    'Skylake-Server-IBRS' => 'GenuineIntel',
-    'Cascadelake-Server' => 'GenuineIntel',
-    KnightsMill => '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',
-
-    # generic types, use vendor from host node
-    host => 'default',
-    kvm32 => 'default',
-    kvm64 => 'default',
-    qemu32 => 'default',
-    qemu64 => 'default',
-    max => 'default',
-};
-
-my @supported_cpu_flags = (
-    'pcid',
-    'spec-ctrl',
-    'ibpb',
-    'ssbd',
-    'virt-ssbd',
-    'amd-ssbd',
-    'amd-no-ssb',
-    'pdpe1gb',
-    'md-clear',
-    'hv-tlbflush',
-    'hv-evmcs',
-    'aes'
-);
-my $cpu_flag = qr/[+-](@{[join('|', @supported_cpu_flags)]})/;
-
-my $cpu_fmt = {
-    cputype => {
-       description => "Emulated CPU type.",
-       type => 'string',
-       enum => [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
-       default => 'kvm64',
-       default_key => 1,
-    },
-    hidden => {
-       description => "Do not identify as a KVM virtual machine.",
-       type => 'boolean',
-       optional => 1,
-       default => 0
-    },
-    'hv-vendor-id' => {
-       type => 'string',
-       pattern => qr/[a-zA-Z0-9]{1,12}/,
-       format_description => 'vendor-id',
-       description => 'The Hyper-V vendor ID. Some drivers or programs inside Windows guests need a specific ID.',
-       optional => 1,
-    },
-    flags => {
-       description => "List of additional CPU flags separated by ';'."
-                    . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
-                    . " Currently supported flags: @{[join(', ', @supported_cpu_flags)]}.",
-       format_description => '+FLAG[;-FLAG...]',
-       type => 'string',
-       pattern => qr/$cpu_flag(;$cpu_flag)*/,
-       optional => 1,
-    },
-};
-
 my $watchdog_fmt = {
     model => {
        default_key => 1,
@@ -611,7 +510,7 @@ EODESCR
        optional => 1,
        description => "Emulated CPU type.",
        type => 'string',
-       format => $cpu_fmt,
+       format => $PVE::QemuServer::CPUConfig::cpu_fmt,
     },
     parent => get_standard_option('pve-snapshot-name', {
        optional => 1,
@@ -2121,26 +2020,6 @@ sub print_netdev_full {
     return $netdev;
 }
 
-
-sub print_cpu_device {
-    my ($conf, $id) = @_;
-
-    my $kvm = $conf->{kvm} // 1;
-    my $cpu = $kvm ? "kvm64" : "qemu64";
-    if (my $cputype = $conf->{cpu}) {
-       my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
-           or die "Cannot parse cpu description: $cputype\n";
-       $cpu = $cpuconf->{cputype};
-    }
-
-    my $cores = $conf->{cores} || 1;
-
-    my $current_core = ($id - 1) % $cores;
-    my $current_socket = int(($id - 1 - $current_core)/$cores);
-
-    return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
-}
-
 my $vga_map = {
     'cirrus' => 'cirrus-vga',
     'std' => 'VGA',
@@ -3516,61 +3395,6 @@ sub query_understood_cpu_flags {
     return \@flags;
 }
 
-sub get_cpu_options {
-    my ($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough) = @_;
-
-    my $cpuFlags = [];
-    my $ostype = $conf->{ostype};
-
-    my $cpu = $kvm ? "kvm64" : "qemu64";
-    if ($arch eq 'aarch64') {
-       $cpu = 'cortex-a57';
-    }
-    my $hv_vendor_id;
-    if (my $cputype = $conf->{cpu}) {
-       my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
-           or die "Cannot parse cpu description: $cputype\n";
-       $cpu = $cpuconf->{cputype};
-       $kvm_off = 1 if $cpuconf->{hidden};
-       $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
-
-       if (defined(my $flags = $cpuconf->{flags})) {
-           push @$cpuFlags, split(";", $flags);
-       }
-    }
-
-    push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
-
-    push @$cpuFlags , '-x2apic' if $ostype && $ostype eq 'solaris';
-
-    push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
-
-    push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
-
-    if (min_version($machine_version, 2, 3) && $arch eq 'x86_64') {
-
-       push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
-       push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
-    }
-
-    add_hyperv_enlightenments($cpuFlags, $winversion, $machine_version, $conf->{bios}, $gpu_passthrough, $hv_vendor_id) if $kvm;
-
-    push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
-
-    push @$cpuFlags, 'kvm=off' if $kvm_off;
-
-    if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
-       push @$cpuFlags, "vendor=${cpu_vendor}"
-           if $cpu_vendor ne 'default';
-    } elsif ($arch ne 'aarch64') {
-       die "internal error"; # should not happen
-    }
-
-    $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
-
-    return ('-cpu', $cpu);
-}
-
 sub config_to_command {
     my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
 
@@ -7288,45 +7112,6 @@ sub scsihw_infos {
     return ($maxdev, $controller, $controller_prefix);
 }
 
-sub add_hyperv_enlightenments {
-    my ($cpuFlags, $winversion, $machine_version, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
-
-    return if $winversion < 6;
-    return if $bios && $bios eq 'ovmf' && $winversion < 8;
-
-    if ($gpu_passthrough || defined($hv_vendor_id)) {
-       $hv_vendor_id //= 'proxmox';
-       push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
-    }
-
-    if (min_version($machine_version, 2, 3)) {
-       push @$cpuFlags , 'hv_spinlocks=0x1fff';
-       push @$cpuFlags , 'hv_vapic';
-       push @$cpuFlags , 'hv_time';
-    } else {
-       push @$cpuFlags , 'hv_spinlocks=0xffff';
-    }
-
-    if (min_version($machine_version, 2, 6)) {
-       push @$cpuFlags , 'hv_reset';
-       push @$cpuFlags , 'hv_vpindex';
-       push @$cpuFlags , 'hv_runtime';
-    }
-
-    if ($winversion >= 7) {
-       push @$cpuFlags , 'hv_relaxed';
-
-       if (min_version($machine_version, 2, 12)) {
-           push @$cpuFlags , 'hv_synic';
-           push @$cpuFlags , 'hv_stimer';
-       }
-
-       if (min_version($machine_version, 3, 1)) {
-           push @$cpuFlags , 'hv_ipi';
-       }
-    }
-}
-
 sub windows_version {
     my ($ostype) = @_;
 
diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm
new file mode 100644 (file)
index 0000000..86febe8
--- /dev/null
@@ -0,0 +1,232 @@
+package PVE::QemuServer::CPUConfig;
+
+use strict;
+use warnings;
+
+use PVE::JSONSchema;
+use PVE::QemuServer::Helpers qw(min_version);
+
+use base qw(Exporter);
+
+our @EXPORT_OK = qw(
+print_cpu_device
+get_cpu_options
+);
+
+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-Server' => 'GenuineIntel',
+    'Skylake-Server-IBRS' => 'GenuineIntel',
+    'Cascadelake-Server' => 'GenuineIntel',
+    KnightsMill => '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',
+
+    # generic types, use vendor from host node
+    host => 'default',
+    kvm32 => 'default',
+    kvm64 => 'default',
+    qemu32 => 'default',
+    qemu64 => 'default',
+    max => 'default',
+};
+
+my @supported_cpu_flags = (
+    'pcid',
+    'spec-ctrl',
+    'ibpb',
+    'ssbd',
+    'virt-ssbd',
+    'amd-ssbd',
+    'amd-no-ssb',
+    'pdpe1gb',
+    'md-clear',
+    'hv-tlbflush',
+    'hv-evmcs',
+    'aes'
+);
+my $cpu_flag = qr/[+-](@{[join('|', @supported_cpu_flags)]})/;
+
+our $cpu_fmt = {
+    cputype => {
+       description => "Emulated CPU type.",
+       type => 'string',
+       enum => [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
+       default => 'kvm64',
+       default_key => 1,
+    },
+    hidden => {
+       description => "Do not identify as a KVM virtual machine.",
+       type => 'boolean',
+       optional => 1,
+       default => 0
+    },
+    'hv-vendor-id' => {
+       type => 'string',
+       pattern => qr/[a-zA-Z0-9]{1,12}/,
+       format_description => 'vendor-id',
+       description => 'The Hyper-V vendor ID. Some drivers or programs inside Windows guests need a specific ID.',
+       optional => 1,
+    },
+    flags => {
+       description => "List of additional CPU flags separated by ';'."
+                    . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
+                    . " Currently supported flags: @{[join(', ', @supported_cpu_flags)]}.",
+       format_description => '+FLAG[;-FLAG...]',
+       type => 'string',
+       pattern => qr/$cpu_flag(;$cpu_flag)*/,
+       optional => 1,
+    },
+};
+
+# Print a QEMU device node for a given VM configuration for hotplugging CPUs
+sub print_cpu_device {
+    my ($conf, $id) = @_;
+
+    my $kvm = $conf->{kvm} // 1;
+    my $cpu = $kvm ? "kvm64" : "qemu64";
+    if (my $cputype = $conf->{cpu}) {
+       my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
+           or die "Cannot parse cpu description: $cputype\n";
+       $cpu = $cpuconf->{cputype};
+    }
+
+    my $cores = $conf->{cores} || 1;
+
+    my $current_core = ($id - 1) % $cores;
+    my $current_socket = int(($id - 1 - $current_core)/$cores);
+
+    return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
+}
+
+# Calculate QEMU's '-cpu' argument from a given VM configuration
+sub get_cpu_options {
+    my ($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough) = @_;
+
+    my $cpuFlags = [];
+    my $ostype = $conf->{ostype};
+
+    my $cpu = $kvm ? "kvm64" : "qemu64";
+    if ($arch eq 'aarch64') {
+       $cpu = 'cortex-a57';
+    }
+    my $hv_vendor_id;
+    if (my $cputype = $conf->{cpu}) {
+       my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
+           or die "Cannot parse cpu description: $cputype\n";
+       $cpu = $cpuconf->{cputype};
+       $kvm_off = 1 if $cpuconf->{hidden};
+       $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
+
+       if (defined(my $flags = $cpuconf->{flags})) {
+           push @$cpuFlags, split(";", $flags);
+       }
+    }
+
+    push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
+
+    push @$cpuFlags , '-x2apic' if $ostype && $ostype eq 'solaris';
+
+    push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
+
+    push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
+
+    if (min_version($machine_version, 2, 3) && $arch eq 'x86_64') {
+
+       push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
+       push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
+    }
+
+    add_hyperv_enlightenments($cpuFlags, $winversion, $machine_version, $conf->{bios}, $gpu_passthrough, $hv_vendor_id) if $kvm;
+
+    push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
+
+    push @$cpuFlags, 'kvm=off' if $kvm_off;
+
+    if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
+       push @$cpuFlags, "vendor=${cpu_vendor}"
+           if $cpu_vendor ne 'default';
+    } elsif ($arch ne 'aarch64') {
+       die "internal error"; # should not happen
+    }
+
+    $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
+
+    return ('-cpu', $cpu);
+}
+
+sub add_hyperv_enlightenments {
+    my ($cpuFlags, $winversion, $machine_version, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
+
+    return if $winversion < 6;
+    return if $bios && $bios eq 'ovmf' && $winversion < 8;
+
+    if ($gpu_passthrough || defined($hv_vendor_id)) {
+       $hv_vendor_id //= 'proxmox';
+       push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
+    }
+
+    if (min_version($machine_version, 2, 3)) {
+       push @$cpuFlags , 'hv_spinlocks=0x1fff';
+       push @$cpuFlags , 'hv_vapic';
+       push @$cpuFlags , 'hv_time';
+    } else {
+       push @$cpuFlags , 'hv_spinlocks=0xffff';
+    }
+
+    if (min_version($machine_version, 2, 6)) {
+       push @$cpuFlags , 'hv_reset';
+       push @$cpuFlags , 'hv_vpindex';
+       push @$cpuFlags , 'hv_runtime';
+    }
+
+    if ($winversion >= 7) {
+       push @$cpuFlags , 'hv_relaxed';
+
+       if (min_version($machine_version, 2, 12)) {
+           push @$cpuFlags , 'hv_synic';
+           push @$cpuFlags , 'hv_stimer';
+       }
+
+       if (min_version($machine_version, 3, 1)) {
+           push @$cpuFlags , 'hv_ipi';
+       }
+    }
+}
+
+1;
index 670105a86da70c577c9047ee8a3a86f88e978aa9..6a49626d2cb1f53e8cbbefc53ce40a7c938a013b 100644 (file)
@@ -8,6 +8,7 @@ SOURCES=PCI.pm          \
        Helpers.pm      \
        Monitor.pm      \
        Machine.pm      \
+       CPUConfig.pm    \
 
 .PHONY: install
 install: ${SOURCES}