[pve-devel] [PATCH v7 qemu-server 05/10] Add helpers to better structure CPU option handling

Stefan Reiter s.reiter at proxmox.com
Thu Jan 16 16:40:51 CET 2020


To avoid hardcoding even more CPU-flag related things for custom CPU
models, introduce a dynamic approach to resolving flags.

resolve_cpu_flags takes a list of hashes (as documented in the
comment) and resolves them to a valid "-cpu" argument without
duplicates. This also helps by providing a reason why specific CPU flags
have been added, and thus allows for useful warning messages should a
flag be overwritten by another.

Signed-off-by: Stefan Reiter <s.reiter at proxmox.com>
---
 PVE/QemuServer/CPUConfig.pm | 64 +++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/PVE/QemuServer/CPUConfig.pm b/PVE/QemuServer/CPUConfig.pm
index 49adb59..73c9ee5 100644
--- a/PVE/QemuServer/CPUConfig.pm
+++ b/PVE/QemuServer/CPUConfig.pm
@@ -297,6 +297,70 @@ sub print_cpu_device {
     return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
 }
 
+# Resolves multiple arrays of hashes representing CPU flags with metadata to a
+# single string in QEMU "-cpu" compatible format. Later arrays have higher
+# priority.
+#
+# Hashes take the following format:
+# {
+#     aes => {
+#         op => "+", # defaults to "" if undefined
+#         reason => "to support AES acceleration", # for override warnings
+#         value => "" # needed for kvm=off (value: off) etc...
+#     },
+#     ...
+# }
+sub resolve_cpu_flags {
+    my $flags = {};
+
+    for my $hash (@_) {
+	for my $flag_name (keys %$hash) {
+	    my $flag = $hash->{$flag_name};
+	    my $old_flag = $flags->{$flag_name};
+
+	    $flag->{op} //= "";
+	    $flag->{reason} //= "unknown origin";
+
+	    if ($old_flag) {
+		my $value_changed = (defined($flag->{value}) != defined($old_flag->{value})) ||
+				    (defined($flag->{value}) && $flag->{value} ne $old_flag->{value});
+
+		if ($old_flag->{op} eq $flag->{op} && !$value_changed) {
+		    $flags->{$flag_name}->{reason} .= " & $flag->{reason}";
+		    next;
+		}
+
+		my $old = print_cpuflag_hash($flag_name, $flags->{$flag_name});
+		my $new = print_cpuflag_hash($flag_name, $flag);
+		warn "warning: CPU flag/setting $new overwrites $old\n";
+	    }
+
+	    $flags->{$flag_name} = $flag;
+	}
+    }
+
+    my $flag_str = '';
+    # sort for command line stability
+    for my $flag_name (sort keys %$flags) {
+	$flag_str .= ',';
+	$flag_str .= $flags->{$flag_name}->{op};
+	$flag_str .= $flag_name;
+	$flag_str .= "=$flags->{$flag_name}->{value}"
+	    if $flags->{$flag_name}->{value};
+    }
+
+    return $flag_str;
+}
+
+sub print_cpuflag_hash {
+    my ($flag_name, $flag) = @_;
+    my $formatted = "'$flag->{op}$flag_name";
+    $formatted .= "=$flag->{value}" if defined($flag->{value});
+    $formatted .= "'";
+    $formatted .= " ($flag->{reason})" if defined($flag->{reason});
+    return $formatted;
+}
+
 # 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) = @_;
-- 
2.20.1





More information about the pve-devel mailing list