[pve-devel] [PATCH v6 qemu-server 03/12] Add CPUConfig file and migrate some helpers
Thomas Lamprecht
t.lamprecht at proxmox.com
Tue Jan 14 12:07:46 CET 2020
On 11/21/19 3:53 PM, Stefan Reiter wrote:
> 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 at proxmox.com>
> ---
can you please rebase this? (sorry for long delay :) )
> PVE/QemuServer.pm | 219 +---------------------------------
> PVE/QemuServer/CPUConfig.pm | 232 ++++++++++++++++++++++++++++++++++++
> PVE/QemuServer/Makefile | 1 +
> 3 files changed, 235 insertions(+), 217 deletions(-)
> create mode 100644 PVE/QemuServer/CPUConfig.pm
>
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index b37fee9..90d0c15 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -43,6 +43,7 @@ use PVE::QMPClient;
> use PVE::QemuConfig;
> use PVE::QemuServer::Helpers qw(min_version);
> 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);
> @@ -110,108 +111,6 @@ sub cgroups_write {
>
> my $nodename = PVE::INotify::nodename();
>
> -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,
> @@ -607,7 +506,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,
> @@ -2117,26 +2016,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',
> @@ -3501,61 +3380,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) = @_;
>
> @@ -7209,45 +7033,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
> index 0000000..86febe8
> --- /dev/null
> +++ b/PVE/QemuServer/CPUConfig.pm
> @@ -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;
> diff --git a/PVE/QemuServer/Makefile b/PVE/QemuServer/Makefile
> index 670105a..6a49626 100644
> --- a/PVE/QemuServer/Makefile
> +++ b/PVE/QemuServer/Makefile
> @@ -8,6 +8,7 @@ SOURCES=PCI.pm \
> Helpers.pm \
> Monitor.pm \
> Machine.pm \
> + CPUConfig.pm \
>
> .PHONY: install
> install: ${SOURCES}
>
More information about the pve-devel
mailing list