* query_understood_cpu_flags returns all flags that QEMU/KVM knows about * query_supported_cpu_flags returns all flags that QEMU/KVM can use on this particular host.
To get supported flags, a temporary VM is started with QEMU, so we can issue the "query-cpu-model-expansion" QMP command. This is how libvirt queries supported flags for its "host-passthrough" CPU type. query_supported_cpu_flags is thus rather slow and shouldn't be called unnecessarily. Currently only supports x86_64, because QEMU-aarch64 doesn't provide the necessary querying functions. Signed-off-by: Stefan Reiter <s.rei...@proxmox.com> --- query_understood_cpu_flags is currently not used, but will be very useful for the later UI part. I think it thematically fits best with this patch though. v1 -> v2: * Change order of functions and add a single, more useful comment on usage * Do s/\.|-/_/g directly in query_understood_cpu_flags, since the other format is useless anyway * Add "die" and FIXME for aarch64, since it doesn't support querying atm (still, use get_host_arch()/get_basic_machine_info() for now, so once QEMU supports it, we theoretically just have to remove the "die") * Do QMP in extra eval, so we don't die before calling vm_stop PVE/QemuServer.pm | 112 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 70ed910..20c1061 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -3531,6 +3531,118 @@ sub get_command_for_arch($) { return $cmd; } +# To use query_supported_cpu_flags and query_understood_cpu_flags to get flags +# to use in a QEMU command line (-cpu element), first array_intersect the result +# of query_supported_ with query_understood_. This is necessary because: +# +# a) query_understood_ returns flags the host cannot use and +# b) query_supported_ (rather the QMP call) doesn't actually return CPU +# flags, but CPU settings - with most of them being flags. Those settings +# (and some flags, curiously) cannot be specified as a "-cpu" argument +# however. +# +# query_supported_ needs to start a temporary VM and is therefore rather +# expensive. If you need the value returned from this, you can get it much +# cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags'). +# +sub query_supported_cpu_flags { + my $flags = []; + + my $vmid = -1; + my $pidfile = pidfile_name($vmid); + + my ($arch, $default_machine) = get_basic_machine_info(); + + # FIXME: Once this is merged, the code below should work for ARM without any + # further modifications: + # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html + die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if + $arch eq "aarch64"; + + PVE::QemuConfig->lock_config($vmid, sub { + # We start a temporary (frozen) VM with vmid -1 to allow us to send a QMP command + my $rc = run_command([ + get_command_for_arch($arch), + '-machine', $default_machine, + '-display', 'none', + '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$vmid.qmp,server,nowait", + '-mon', 'chardev=qmp,mode=control', + '-pidfile', $pidfile, + '-S', '-daemonize' + ], noerr => 1, quiet => 0); + return if $rc; + + eval { + my $cmd_result = vm_mon_cmd_nocheck( + $vmid, + 'query-cpu-model-expansion', + type => 'full', + model => { name => 'host' } + ); + + my $props = $cmd_result->{model}->{props}; + if (%$props) { + foreach my $prop (keys %$props) { + push @$flags, $prop if "$props->{$prop}" eq '1'; + } + } + }; + my $err = $@; + + # force stop with 10 sec timeout and 'nocheck' + # always stop, even if QMP failed + vm_stop(undef, $vmid, 1, 1, 10, 0, 1); + + die $err if $err; + }); + + # QEMU returns some flags multiple times, with '_', '.' or '-' as separator + # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...). + # We only keep those with underscores, since they match the ones from + # /proc/cpuinfo (they do the same thing, but we get rid of duplicates). + @$flags = grep { + my $replaced = (my $underscore = $_) =~ s/\.|-/_/g; + !($replaced && grep { $_ eq $underscore } @$flags) + } @$flags; + + return $flags; +} + +sub query_understood_cpu_flags { + my $flags = []; + my $flag_section = 0; + + my $arch = get_host_arch(); + + # FIXME: Once the patch mentioned in query_supported_cpu_flags is merged, + # depending on if the ARM version of query-cpu-model-expansion also returns + # non-flags, this function might become irrelevant for ARM entirely. + die "CPU Flag detection only supported on x86_64\n" + if $arch ne "x86_64"; + + run_command( + [get_command_for_arch($arch), '-cpu', 'help'], + noerr => 1, + quiet => 1, + outfunc => sub { + my ($line) = @_; + + if ($flag_section) { + return if $line =~ m/^\s*$/; + $line =~ s/^\s*|\s*$//g; + # Convert all flags to underscore format, since that's what + # /proc/cpuinfo and query_supported_cpu_flags use + $line =~ s/\.|-/_/g; + push @$flags, split(/\s+/, $line); + } elsif ($line =~ m/^\s*Recognized CPUID flags:\s*$/) { + $flag_section = 1; + } + } + ); + + return $flags; +} + sub get_cpu_options { my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_; -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel