]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
use non SMM ovmf code file for i440fx machines
[qemu-server.git] / PVE / QemuServer.pm
index 5aafa180e1d2ead16225800e0fe2972cdba49ee1..794558bff2471a0e3dabbc4adf49f25618097695 100644 (file)
@@ -64,6 +64,14 @@ eval {
 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
 my $OVMF = {
     x86_64 => {
+       '4m-no-smm' => [
+           "$EDK2_FW_BASE/OVMF_CODE_4M.fd",
+           "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
+       ],
+       '4m-no-smm-ms' => [
+           "$EDK2_FW_BASE/OVMF_CODE_4M.fd",
+           "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
+       ],
        '4m' => [
            "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
            "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
@@ -292,9 +300,9 @@ my $confdesc = {
        default => 0,
     },
     hotplug => {
-        optional => 1,
-        type => 'string', format => 'pve-hotplug-features',
-        description => "Selectively enable hotplug features. This is a comma separated list of"
+       optional => 1,
+       type => 'string', format => 'pve-hotplug-features',
+       description => "Selectively enable hotplug features. This is a comma separated list of"
            ." hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable"
            ." hotplug completely. Using '1' as value is an alias for the default `network,disk,usb`.",
         default => 'network,disk,usb',
@@ -319,12 +327,12 @@ my $confdesc = {
            ." total of '2' CPU time. Value '0' indicates no CPU limit.",
        minimum => 0,
        maximum => 128,
-        default => 0,
+       default => 0,
     },
     cpuunits => {
        optional => 1,
        type => 'integer',
-        description => "CPU weight for a VM, will be clamped to [1, 10000] in cgroup v2.",
+       description => "CPU weight for a VM, will be clamped to [1, 10000] in cgroup v2.",
        verbose_description => "CPU weight for a VM. Argument is used in the kernel fair scheduler."
            ." The larger the number is, the more CPU time this VM gets. Number is relative to"
            ." weights of all the other running VMs.",
@@ -341,15 +349,15 @@ my $confdesc = {
        default => 512,
     },
     balloon => {
-        optional => 1,
-        type => 'integer',
-        description => "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
+       optional => 1,
+       type => 'integer',
+       description => "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
        minimum => 0,
     },
     shares => {
-        optional => 1,
-        type => 'integer',
-        description => "Amount of memory shares for auto-ballooning. The larger the number is, the"
+       optional => 1,
+       type => 'integer',
+       description => "Amount of memory shares for auto-ballooning. The larger the number is, the"
            ." more memory this VM gets. Number is relative to weights of all other running VMs."
            ." Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
        minimum => 0,
@@ -386,7 +394,7 @@ my $confdesc = {
     ostype => {
        optional => 1,
        type => 'string',
-        enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 win11 l24 l26 solaris)],
+       enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 win11 l24 l26 solaris)],
        description => "Specify guest operating system.",
        verbose_description => <<EODESC,
 Specify guest operating system. This is used to enable special
@@ -411,8 +419,8 @@ EODESC
     boot => {
        optional => 1,
        type => 'string', format => 'pve-qm-boot',
-       description => "Specify guest boot order. Use with 'order=', usage with"
-                    . " no key or 'legacy=' is deprecated.",
+       description => "Specify guest boot order. Use the 'order=' sub-property as usage with no"
+           ." key or 'legacy=' is deprecated.",
     },
     bootdisk => {
        optional => 1,
@@ -1844,7 +1852,6 @@ sub print_vga_device {
     my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
     my $vgaid = "vga" . ($id // '');
     my $pciaddr;
-
     if ($q35 && $vgaid eq 'vga') {
        # the first display uses pcie.0 bus on q35 machines
        $pciaddr = print_pcie_addr($vgaid, $bridges, $arch, $machine);
@@ -2112,9 +2119,16 @@ sub verify_usb_device {
 sub json_config_properties {
     my $prop = shift;
 
+    my $skip_json_config_opts = {
+       parent => 1,
+       snaptime => 1,
+       vmstate => 1,
+       runningmachine => 1,
+       runningcpu => 1,
+    };
+
     foreach my $opt (keys %$confdesc) {
-       next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' ||
-           $opt eq 'runningmachine' || $opt eq 'runningcpu';
+       next if $skip_json_config_opts->{$opt};
        $prop->{$opt} = $confdesc->{$opt};
     }
 
@@ -3159,15 +3173,16 @@ sub get_vm_machine {
     return $machine;
 }
 
-sub get_ovmf_files($$) {
-    my ($arch, $efidisk) = @_;
+sub get_ovmf_files($$$) {
+    my ($arch, $efidisk, $smm) = @_;
 
     my $types = $OVMF->{$arch}
        or die "no OVMF images known for architecture '$arch'\n";
 
     my $type = 'default';
     if (defined($efidisk->{efitype}) && $efidisk->{efitype} eq '4m') {
-       $type = $efidisk->{'pre-enrolled-keys'} ? "4m-ms" : "4m";
+       $type = $smm ? "4m" : "4m-no-smm";
+       $type .= '-ms' if $efidisk->{'pre-enrolled-keys'};
     }
 
     return $types->{$type}->@*;
@@ -3313,11 +3328,8 @@ sub config_to_command {
         $pbs_backing) = @_;
 
     my $cmd = [];
-    my $globalFlags = [];
-    my $machineFlags = [];
-    my $rtcFlags = [];
+    my ($globalFlags, $machineFlags, $rtcFlags) = ([], [], []);
     my $devices = [];
-    my $pciaddr = '';
     my $bridges = {};
     my $ostype = $conf->{ostype};
     my $winversion = windows_version($ostype);
@@ -3433,7 +3445,7 @@ sub config_to_command {
            $d = parse_drive('efidisk0', $efidisk);
        }
 
-       my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch, $d);
+       my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch, $d, $q35);
        die "uefi base image '$ovmf_code' not found\n" if ! -f $ovmf_code;
 
        my ($path, $format);
@@ -3478,8 +3490,7 @@ sub config_to_command {
        push @$cmd, '-drive', "if=pflash,unit=1$cache,format=$format,id=drive-efidisk0$size_str,file=${path}${read_only_str}";
     }
 
-    # load q35 config
-    if ($q35) {
+    if ($q35) { # tell QEMU to load q35 config early
        # we use different pcie-port hardware for qemu >= 4.0 for passthrough
        if (min_version($machine_version, 4, 0)) {
            push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
@@ -3512,10 +3523,8 @@ sub config_to_command {
     }
 
     # enable absolute mouse coordinates (needed by vnc)
-    my $tablet;
-    if (defined($conf->{tablet})) {
-       $tablet = $conf->{tablet};
-    } else {
+    my $tablet = $conf->{tablet};
+    if (!defined($tablet)) {
        $tablet = $defaults->{tablet};
        $tablet = 0 if $qxlnum; # disable for spice because it is not needed
        $tablet = 0 if $vga->{type} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
@@ -3543,23 +3552,22 @@ sub config_to_command {
 
     # serial devices
     for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++)  {
-       if (my $path = $conf->{"serial$i"}) {
-           if ($path eq 'socket') {
-               my $socket = "/var/run/qemu-server/${vmid}.serial$i";
-               push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
-               # On aarch64, serial0 is the UART device. Qemu only allows
-               # connecting UART devices via the '-serial' command line, as
-               # the device has a fixed slot on the hardware...
-               if ($arch eq 'aarch64' && $i == 0) {
-                   push @$devices, '-serial', "chardev:serial$i";
-               } else {
-                   push @$devices, '-device', "isa-serial,chardev=serial$i";
-               }
+       my $path = $conf->{"serial$i"} or next;
+       if ($path eq 'socket') {
+           my $socket = "/var/run/qemu-server/${vmid}.serial$i";
+           push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
+           # On aarch64, serial0 is the UART device. Qemu only allows
+           # connecting UART devices via the '-serial' command line, as
+           # the device has a fixed slot on the hardware...
+           if ($arch eq 'aarch64' && $i == 0) {
+               push @$devices, '-serial', "chardev:serial$i";
            } else {
-               die "no such serial device\n" if ! -c $path;
-               push @$devices, '-chardev', "tty,id=serial$i,path=$path";
                push @$devices, '-device', "isa-serial,chardev=serial$i";
            }
+       } else {
+           die "no such serial device\n" if ! -c $path;
+           push @$devices, '-chardev', "tty,id=serial$i,path=$path";
+           push @$devices, '-device', "isa-serial,chardev=serial$i";
        }
     }
 
@@ -3593,11 +3601,9 @@ sub config_to_command {
 
     my $allowed_vcpus = $cpuinfo->{cpus};
 
-    die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
-       if ($allowed_vcpus < $maxcpus);
-
-    if($hotplug_features->{cpu} && min_version($machine_version, 2, 7)) {
+    die "MAX $allowed_vcpus vcpus allowed per VM on this node\n" if ($allowed_vcpus < $maxcpus);
 
+    if ($hotplug_features->{cpu} && min_version($machine_version, 2, 7)) {
        push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
         for (my $i = 2; $i <= $vcpus; $i++)  {
            my $cpustr = print_cpu_device($conf,$i);
@@ -3745,13 +3751,13 @@ sub config_to_command {
 
     # enable balloon by default, unless explicitly disabled
     if (!defined($conf->{balloon}) || $conf->{balloon}) {
-       $pciaddr = print_pci_addr("balloon0", $bridges, $arch, $machine_type);
+       my $pciaddr = print_pci_addr("balloon0", $bridges, $arch, $machine_type);
        push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
     }
 
     if ($conf->{watchdog}) {
        my $wdopts = parse_watchdog($conf->{watchdog});
-       $pciaddr = print_pci_addr("watchdog", $bridges, $arch, $machine_type);
+       my $pciaddr = print_pci_addr("watchdog", $bridges, $arch, $machine_type);
        my $watchdog = $wdopts->{model} || 'i6300esb';
        push @$devices, '-device', "$watchdog$pciaddr";
        push @$devices, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
@@ -3795,7 +3801,7 @@ sub config_to_command {
            die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
                if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
 
-           $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges, $arch, $machine_type);
+           my $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges, $arch, $machine_type);
            my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ? "virtio-scsi-pci" : $scsihw;
 
            my $iothread = '';
@@ -3818,7 +3824,7 @@ sub config_to_command {
 
         if ($drive->{interface} eq 'sata') {
            my $controller = int($drive->{index} / $PVE::QemuServer::Drive::MAX_SATA_DISKS);
-           $pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $machine_type);
+           my $pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $machine_type);
            push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr"
                if !$ahcicontroller->{$controller};
            $ahcicontroller->{$controller}=1;
@@ -3883,15 +3889,12 @@ sub config_to_command {
     # pci.4 is nested in pci.1
     $bridges->{1} = 1 if $bridges->{4};
 
-    if (!$q35) {
-       # add pci bridges
-        if (min_version($machine_version, 2, 3)) {
+    if (!$q35) { # add pci bridges
+       if (min_version($machine_version, 2, 3)) {
           $bridges->{1} = 1;
           $bridges->{2} = 1;
        }
-
        $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
-
     }
 
     for my $k (sort {$b cmp $a} keys %$bridges) {
@@ -3901,11 +3904,10 @@ sub config_to_command {
        if ($k == 2 && $legacy_igd) {
            $k_name = "$k-igd";
        }
-       $pciaddr = print_pci_addr("pci.$k_name", undef, $arch, $machine_type);
-
+       my $pciaddr = print_pci_addr("pci.$k_name", undef, $arch, $machine_type);
        my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
-       if ($q35) {
-           # add after -readconfig pve-q35.cfg
+
+       if ($q35) { # add after -readconfig pve-q35.cfg
            splice @$devices, 2, 0, '-device', $devstr;
        } else {
            unshift @$devices, '-device', $devstr if $k > 0;
@@ -4036,43 +4038,33 @@ sub vm_deviceplug {
     qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
 
     if ($deviceid eq 'tablet') {
-
        qemu_deviceadd($vmid, print_tabletdevice_full($conf, $arch));
-
     } elsif ($deviceid eq 'keyboard') {
-
        qemu_deviceadd($vmid, print_keyboarddevice_full($conf, $arch));
-
     } elsif ($deviceid =~ m/^usb(\d+)$/) {
-
        die "usb hotplug currently not reliable\n";
        # since we can't reliably hot unplug all added usb devices and usb
        # passthrough breaks live migration we disable usb hotplugging for now
        #qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
-
     } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
-
        qemu_iothread_add($vmid, $deviceid, $device);
 
-        qemu_driveadd($storecfg, $vmid, $device);
-        my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
+       qemu_driveadd($storecfg, $vmid, $device);
+       my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
 
-        qemu_deviceadd($vmid, $devicefull);
+       qemu_deviceadd($vmid, $devicefull);
        eval { qemu_deviceaddverify($vmid, $deviceid); };
        if (my $err = $@) {
            eval { qemu_drivedel($vmid, $deviceid); };
            warn $@ if $@;
            die $err;
         }
-
     } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
-
-
-        my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
-        my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
+       my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
+       my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
        my $scsihw_type = $scsihw eq 'virtio-scsi-single' ? "virtio-scsi-pci" : $scsihw;
 
-        my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
+       my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
 
        if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread}) {
            qemu_iothread_add($vmid, $deviceid, $device);
@@ -4083,11 +4075,9 @@ sub vm_deviceplug {
            $devicefull .= ",num_queues=$device->{queues}";
        }
 
-        qemu_deviceadd($vmid, $devicefull);
-        qemu_deviceaddverify($vmid, $deviceid);
-
+       qemu_deviceadd($vmid, $devicefull);
+       qemu_deviceaddverify($vmid, $deviceid);
     } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
-
         qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device, $arch, $machine_type);
         qemu_driveadd($storecfg, $vmid, $device);
 
@@ -4098,9 +4088,7 @@ sub vm_deviceplug {
            warn $@ if $@;
            die $err;
         }
-
     } elsif ($deviceid =~ m/^(net)(\d+)$/) {
-
        return if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
 
        my $machine_type = PVE::QemuServer::Machine::qemu_machine_pxe($vmid, $conf);
@@ -4119,16 +4107,13 @@ sub vm_deviceplug {
            warn $@ if $@;
            die $err;
        }
-
     } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
-
        my $bridgeid = $2;
        my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
        my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
 
        qemu_deviceadd($vmid, $devicefull);
        qemu_deviceaddverify($vmid, $deviceid);
-
     } else {
        die "can't hotplug device '$deviceid'\n";
     }
@@ -7556,7 +7541,8 @@ sub get_efivars_size {
     my ($conf) = @_;
     my $arch = get_vm_arch($conf);
     my $efidisk = $conf->{efidisk0} ? parse_drive('efidisk0', $conf->{efidisk0}) : undef;
-    my (undef, $ovmf_vars) = get_ovmf_files($arch, $efidisk);
+    my $smm = PVE::QemuServer::Machine::machine_type_is_q35($conf);
+    my (undef, $ovmf_vars) = get_ovmf_files($arch, $efidisk, $smm);
     die "uefi vars image '$ovmf_vars' not found\n" if ! -f $ovmf_vars;
     return -s $ovmf_vars;
 }
@@ -7581,10 +7567,10 @@ sub update_tpmstate_size {
     $conf->{tpmstate0} = print_drive($disk);
 }
 
-sub create_efidisk($$$$$$) {
-    my ($storecfg, $storeid, $vmid, $fmt, $arch, $efidisk) = @_;
+sub create_efidisk($$$$$$$) {
+    my ($storecfg, $storeid, $vmid, $fmt, $arch, $efidisk, $smm) = @_;
 
-    my (undef, $ovmf_vars) = get_ovmf_files($arch, $efidisk);
+    my (undef, $ovmf_vars) = get_ovmf_files($arch, $efidisk, $smm);
     die "EFI vars default image not found\n" if ! -f $ovmf_vars;
 
     my $vars_size_b = -s $ovmf_vars;