On October 7, 2019 2:47 pm, Stefan Reiter wrote: > If a cputype is custom (check via prefix), try to load options from the > custom CPU model config, and set values accordingly. > > While at it, extract currently hardcoded values into seperate sub and add > reasonings. > > Since the new flag resolving outputs flags in sorted order for > consistency, adapt the test cases to not break. Only the order is > changed, not which flags are present. > > Signed-off-by: Stefan Reiter <s.rei...@proxmox.com> > --- > > v3 -> v4: > * use is_custom_model > > v3: Since it's just a few lines, I included the test changes into this patch > directly. This way all patches in the series should be buildable without > problems. > > v2: It was quite interesting to dig through old commit messages/mail archives > to > find the actual reasons some of the hardcoded flags are included. I do feel > like > the "reason" field is quite useful though, both for future developers and > users. > > PVE/QemuServer/CPUConfig.pm | 185 +++++++++++++++------ > test/cfg2cmd/i440fx-win10-hostpci.conf.cmd | 2 +- > test/cfg2cmd/minimal-defaults.conf.cmd | 2 +- > test/cfg2cmd/q35-linux-hostpci.conf.cmd | 2 +- > test/cfg2cmd/q35-win10-hostpci.conf.cmd | 2 +- > test/cfg2cmd/simple1.conf.cmd | 2 +- > test/cfg2cmd/spice-usb3.conf.cmd | 2 +- > 7 files changed, 144 insertions(+), 53 deletions(-) > > diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm > index 405ad86..0948f67 100644 > --- a/PVE/QemuServer/CPUConfig.pm > +++ b/PVE/QemuServer/CPUConfig.pm > @@ -369,96 +369,187 @@ sub print_cpuflag_hash { > sub get_cpu_options { > my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, > $gpu_passthrough) = @_; > > - my $cpuFlags = []; > - my $ostype = $conf->{ostype}; > - > - my $cpu = $kvm ? "kvm64" : "qemu64"; > + my $cputype = $kvm ? "kvm64" : "qemu64"; > if ($arch eq 'aarch64') { > - $cpu = 'cortex-a57'; > + $cputype = 'cortex-a57'; > } > + > + my $cpuconf = {}; > + my $custom_cpuconf;
bad naming: $cpu (further below) $cpuconf $custom_cpuconf $custom_conf (a bit below) maybe $cpu -> $cpu_str (string that is generated to be passed via -cpu) $cpuconf -> $cpu $custom_cpuconf -> $custom_cpu $custom_conf -> inline, maybe even into get_model_by_name ? > 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 (my $cpu_prop_str = $conf->{cpu}) { > + $cpuconf = verify_vm_cpu_conf($cpu_prop_str) > + or die "Cannot parse cpu description: $cpu_prop_str\n"; s/verify_vm_cpu_conf/parse_cpu_conf_basic ? > > - if (defined(my $flags = $cpuconf->{flags})) { > - push @$cpuFlags, split(";", $flags); > - } > - } > + $cputype = $cpuconf->{cputype}; > > - push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64'; > + if (is_custom_model($cputype)) { > + my $custom_conf = load_custom_model_conf(); > + $custom_cpuconf = get_model_by_name($custom_conf, $cputype) > + or die "invalid custom model definition for '$cputype'\n"; > > - push @$cpuFlags , '-x2apic' > - if $conf->{ostype} && $conf->{ostype} eq 'solaris'; > + $cputype = $custom_cpuconf->{'reported-model'}; > + $kvm_off = $custom_cpuconf->{hidden}; this is a bit tricky - the schema default is 0, get_model_by_name applies this default, and now we override the passed-in explicit value with the default value from the custom CPU schema. maybe drop the default and add an 'if defined' here? > + $hv_vendor_id = $custom_cpuconf->{'hv-vendor-id'}; > + } > > - push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32'; > + # VM-specific settings override custom CPU config > + $kvm_off = $cpuconf->{hidden} > + if defined($cpuconf->{hidden}); > + $hv_vendor_id = $cpuconf->{'hv-vendor-id'} > + if defined($cpuconf->{'hv-vendor-id'}); > + } > > - push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/; > + my $pve_flags = get_pve_cpu_flags($conf, $kvm, $cputype, $arch, > + $machine_type, $kvmver); > > - if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3) && $arch > eq 'x86_64') { > + my $hv_flags = get_hyperv_enlightenments($winversion, $machine_type, > $kvmver, > + $conf->{bios}, $gpu_passthrough, $hv_vendor_id) if $kvm; > > - push @$cpuFlags , '+kvm_pv_unhalt' if $kvm; > - push @$cpuFlags , '+kvm_pv_eoi' if $kvm; > + my $custom_cputype_flags = {}; > + if ($custom_cpuconf && defined($custom_cpuconf->{flags})) { > + foreach my $flag (split(";", $custom_cpuconf->{flags})) { > + $flag =~ m/^([+-])(.*)$/; > + $custom_cputype_flags->{$2} = { > + op => $1, > + reason => "set by custom CPU model", > + } > + } this > } > > - add_hyperv_enlightenments($cpuFlags, $winversion, $machine_type, > $kvmver, $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; > + my $vm_flags = {}; > + if (defined(my $flags = $cpuconf->{flags})) { > + foreach my $flag (split(";", $flags)) { > + if ($flag =~ $cpu_flag_re) { > + $vm_flags->{$2} = { > + op => $1, > + reason => "manually set for VM", > + } > + } > + } and this do the same thing: sub parse_cpuflag_list { my ($re, $reason, $flaglist) = @_; my $res = {}; foreach my $flag (split(";", $flaglist)) { if ($flag =~ $re) { $res->{$2} = { op => $1, reason => $reason }; } } } just with different parameters. also, the RE in the first case is not the one used in the schema (which is not wrong per se, but is a bit confusing at first glance). > + } > > - if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) { > - push @$cpuFlags, "vendor=${cpu_vendor}" > - if $cpu_vendor ne 'default'; > + my $pve_forced_flags = {}; > + $pve_forced_flags->{'enforce'} = { > + reason => "error if requested CPU settings not available", > + } if $cputype ne 'host' && $kvm && $arch eq 'x86_64'; > + $pve_forced_flags->{'kvm'} = { > + value => "off", > + reason => "hide KVM virtualization from guest", > + } if $kvm_off; > + > + # $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) { > + $pve_forced_flags->{'vendor'} = { > + value => $cpu_vendor, > + } if $cpu_vendor ne 'default'; > } elsif ($arch ne 'aarch64') { > die "internal error"; # should not happen > } > > - $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags); > + my $cpu = $cputype; > + > + # will be resolved in parameter order > + $cpu .= resolve_cpu_flags($pve_flags, $hv_flags, $custom_cputype_flags, > + $vm_flags, $pve_forced_flags); > > return ('-cpu', $cpu); > } > > -sub add_hyperv_enlightenments { > - my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, > $gpu_passthrough, $hv_vendor_id) = @_; > +# Some hardcoded flags required by certain configurations > +sub get_pve_cpu_flags { > + my ($conf, $kvm, $cputype, $arch, $machine_type, $kvmver) = @_; > + > + my $pve_flags = {}; > + my $pve_msg = "set by PVE;"; > + > + $pve_flags->{'lahf_lm'} = { > + op => '+', > + reason => "$pve_msg to support Windows 8.1+", > + } if $cputype eq 'kvm64' && $arch eq 'x86_64'; > + > + $pve_flags->{'x2apic'} = { > + op => '-', > + reason => "$pve_msg incompatible with Solaris", > + } if $conf->{ostype} && $conf->{ostype} eq 'solaris'; > + > + $pve_flags->{'sep'} = { > + op => '+', > + reason => "$pve_msg to support Windows 8+ and improve Windows XP+", > + } if $cputype eq 'kvm64' || $cputype eq 'kvm32'; > + > + $pve_flags->{'rdtscp'} = { > + op => '-', > + reason => "$pve_msg broken on AMD Opteron", > + } if $cputype =~ m/^Opteron/; > + > + if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3) > + && $arch eq 'x86_64' && $kvm) { > + $pve_flags->{'kvm_pv_unhalt'} = { > + op => '+', > + reason => "$pve_msg improves Linux guest spinlock performance", 'to improve' to be consistent with 'to support' > + }; > + $pve_flags->{'kvm_pv_eoi'} = { > + op => '+', > + reason => "$pve_msg improves Linux guest interrupt performance", same > + }; > + } > + > + return $pve_flags; > +} > + > +sub get_hyperv_enlightenments { > + my ($winversion, $machine_type, $kvmver, $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)) { > + my $flags = {}; > + my $flagfn = sub { > + my ($flag, $value, $reason) = @_; > + $flags->{$flag} = { > + reason => $reason // "automatic Hyper-V enlightenment for Windows", > + value => $value, > + } > + }; > + > + my $hv_vendor_set = defined($hv_vendor_id); > + if ($gpu_passthrough || $hv_vendor_set) { > $hv_vendor_id //= 'proxmox'; > - push @$cpuFlags , "hv_vendor_id=$hv_vendor_id"; > + $flagfn->('hv_vendor_id', $hv_vendor_id, $hv_vendor_set ? > + "custom hv_vendor_id set" : "NVIDIA workaround for GPU > passthrough"); > } > > if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) { > - push @$cpuFlags , 'hv_spinlocks=0x1fff'; > - push @$cpuFlags , 'hv_vapic'; > - push @$cpuFlags , 'hv_time'; > + $flagfn->('hv_spinlocks', '0x1fff'); > + $flagfn->('hv_vapic'); > + $flagfn->('hv_time'); > } else { > - push @$cpuFlags , 'hv_spinlocks=0xffff'; > + $flagfn->('hv_spinlocks', '0xffff'); > } > > if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 6)) { > - push @$cpuFlags , 'hv_reset'; > - push @$cpuFlags , 'hv_vpindex'; > - push @$cpuFlags , 'hv_runtime'; > + $flagfn->('hv_reset'); > + $flagfn->('hv_vpindex'); > + $flagfn->('hv_runtime'); > } > > if ($winversion >= 7) { could maybe add something about the windows version to the reason in this branch? > - push @$cpuFlags , 'hv_relaxed'; > + $flagfn->('hv_relaxed'); > > if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 12)) { > - push @$cpuFlags , 'hv_synic'; > - push @$cpuFlags , 'hv_stimer'; > + $flagfn->('hv_synic'); > + $flagfn->('hv_stimer'); > } > > if (qemu_machine_feature_enabled ($machine_type, $kvmver, 3, 1)) { > - push @$cpuFlags , 'hv_ipi'; > + $flagfn->('hv_ipi'); > } > } > + > + return $flags; > } > > sub qemu_machine_feature_enabled { > diff --git a/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd > b/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd > index ff5d635..2a9174d 100644 > --- a/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd > +++ b/test/cfg2cmd/i440fx-win10-hostpci.conf.cmd > @@ -15,7 +15,7 @@ > -boot > 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' > \ > -vnc unix:/var/run/qemu-server/8006.vnc,password \ > -no-hpet \ > - -cpu > 'kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,hv_spinlocks=0x1fff,hv_vapic,hv_time,hv_reset,hv_vpindex,hv_runtime,hv_relaxed,hv_synic,hv_stimer,hv_ipi,enforce' > \ > + -cpu > 'kvm64,enforce,hv_ipi,hv_relaxed,hv_reset,hv_runtime,hv_spinlocks=0x1fff,hv_stimer,hv_synic,hv_time,hv_vapic,hv_vpindex,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep' > \ > -m 512 \ > -object 'memory-backend-ram,id=ram-node0,size=256M' \ > -numa 'node,nodeid=0,cpus=0,memdev=ram-node0' \ > diff --git a/test/cfg2cmd/minimal-defaults.conf.cmd > b/test/cfg2cmd/minimal-defaults.conf.cmd > index 5abebe9..444050b 100644 > --- a/test/cfg2cmd/minimal-defaults.conf.cmd > +++ b/test/cfg2cmd/minimal-defaults.conf.cmd > @@ -12,7 +12,7 @@ > -nodefaults \ > -boot > 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' > \ > -vnc unix:/var/run/qemu-server/8006.vnc,password \ > - -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \ > + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ > -m 512 \ > -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ > -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ > diff --git a/test/cfg2cmd/q35-linux-hostpci.conf.cmd > b/test/cfg2cmd/q35-linux-hostpci.conf.cmd > index 21fb18b..2072295 100644 > --- a/test/cfg2cmd/q35-linux-hostpci.conf.cmd > +++ b/test/cfg2cmd/q35-linux-hostpci.conf.cmd > @@ -14,7 +14,7 @@ > -nodefaults \ > -boot > 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' > \ > -vnc unix:/var/run/qemu-server/8006.vnc,password \ > - -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \ > + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ > -m 512 \ > -object 'memory-backend-ram,id=ram-node0,size=256M' \ > -numa 'node,nodeid=0,cpus=0,memdev=ram-node0' \ > diff --git a/test/cfg2cmd/q35-win10-hostpci.conf.cmd > b/test/cfg2cmd/q35-win10-hostpci.conf.cmd > index f2c08ca..81e43d4 100644 > --- a/test/cfg2cmd/q35-win10-hostpci.conf.cmd > +++ b/test/cfg2cmd/q35-win10-hostpci.conf.cmd > @@ -15,7 +15,7 @@ > -boot > 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' > \ > -vnc unix:/var/run/qemu-server/8006.vnc,password \ > -no-hpet \ > - -cpu > 'kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,hv_spinlocks=0x1fff,hv_vapic,hv_time,hv_reset,hv_vpindex,hv_runtime,hv_relaxed,hv_synic,hv_stimer,hv_ipi,enforce' > \ > + -cpu > 'kvm64,enforce,hv_ipi,hv_relaxed,hv_reset,hv_runtime,hv_spinlocks=0x1fff,hv_stimer,hv_synic,hv_time,hv_vapic,hv_vpindex,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep' > \ > -m 512 \ > -object 'memory-backend-ram,id=ram-node0,size=256M' \ > -numa 'node,nodeid=0,cpus=0,memdev=ram-node0' \ > diff --git a/test/cfg2cmd/simple1.conf.cmd b/test/cfg2cmd/simple1.conf.cmd > index b5c06cf..3485064 100644 > --- a/test/cfg2cmd/simple1.conf.cmd > +++ b/test/cfg2cmd/simple1.conf.cmd > @@ -12,7 +12,7 @@ > -nodefaults \ > -boot > 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' > \ > -vnc unix:/var/run/qemu-server/8006.vnc,password \ > - -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \ > + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ > -m 768 \ > -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ > -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ > diff --git a/test/cfg2cmd/spice-usb3.conf.cmd > b/test/cfg2cmd/spice-usb3.conf.cmd > index 680fa64..66b4e8d 100644 > --- a/test/cfg2cmd/spice-usb3.conf.cmd > +++ b/test/cfg2cmd/spice-usb3.conf.cmd > @@ -12,7 +12,7 @@ > -nodefaults \ > -boot > 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' > \ > -vnc unix:/var/run/qemu-server/8006.vnc,password \ > - -cpu kvm64,+lahf_lm,+sep,+kvm_pv_unhalt,+kvm_pv_eoi,enforce \ > + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ > -m 768 \ > -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ > -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ > -- > 2.20.1 > > > _______________________________________________ > pve-devel mailing list > pve-devel@pve.proxmox.com > https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel > > _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel