[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