From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 046481FF09B for ; Mon, 28 Sep 2026 07:49:28 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 5EF71217B8; Mon, 28 Sep 2026 07:48:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=genua.de; s=202307; t=1790574488; bh=cSlRWKCTGDGHLMQlPj+7PJZCPZAGeDYcJlch6mqvqjE=; h=Date:From:To:Subject:References:In-Reply-To:From; b=JACKbU+UlbzG3i2JUx/KT5qeiYtYxZgyhG+a1ahNo85x3UmfSX70+OgacFXIDXDBq fT2Uztmo3O2xwMRke6l4aImWStNaGOgwZbT5JX/hzXx4UuKpaytzDMMtkh+r5Jx9dU Ox1MGWjz9SNBE5E3ztLH9bmK/Ftzg4kTiT3/lBDozvAI7G79glGyUBB9B3YmhGru2s KlXJVQHjLanD90bbfI9sF1PJU49mHai2oDnMKKJ+f74O5pipPss5cG/21ewza17oPj hQZ/cIvhs4iafmb1uummzDd01L9ApntWWDK/bYmNsMc7QNMvaUxkfLNFxwxsBXaT+D MwOqUb/JxYNfA== Date: Mon, 28 Sep 2026 07:48:06 +0200 From: Christian Ludwig To: Subject: [PATCH v2 qemu-server 07/16] config: add the efi-firmware option Message-ID: <819dba534c9f906bad8d34de900e7ca1028eca8b.1790337726.git@genua.de> References: MIME-Version: 1.0 In-Reply-To: X-Originating-IP: [192.168.217.185] X-ClientProxiedBy: kch1-mta09.win.genua.de (10.208.16.109) To kch1-mta07.win.genua.de (10.208.16.107) Content-Type: text/plain; charset="us-ascii" Content-Disposition: inline X-SPAM-LEVEL: Spam detection results: 0 AWL 0.084 Adjusted score from AWL reputation of From: address DKIM_SIGNED 0.1 Message has a DKIM or DK signature, not necessarily valid DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's domain DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from domain DMARC_PASS -0.1 DMARC pass policy SPF_HELO_PASS -0.001 SPF: HELO matches SPF record SPF_PASS -0.001 SPF: sender matches SPF record UNPARSEABLE_RELAY 0.001 Informational: message has unparseable relay lines Message-ID-Hash: QSR6F3WKZJL6SQYY6K4KKO5LLESASJMD X-Message-ID-Hash: QSR6F3WKZJL6SQYY6K4KKO5LLESASJMD X-MailFrom: christian_ludwig@genua.de X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Add the 'efi-firmware' config key, pointing to a volume of the efi-firmware content type. A custom firmware image does not make sense for a legacy BIOS, so require bios=ovmf when generating the command line. Include the volume when activating a VM's volumes. Firmware images are content and not owned by the VM, like ISO images, so refuse migration unless they are on a shared storage. Signed-off-by: Christian Ludwig --- src/PVE/QemuConfig.pm | 2 +- src/PVE/QemuMigrate.pm | 2 ++ src/PVE/QemuServer.pm | 18 ++++++++++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/PVE/QemuConfig.pm b/src/PVE/QemuConfig.pm index 26f0fda2..1d73048a 100644 --- a/src/PVE/QemuConfig.pm +++ b/src/PVE/QemuConfig.pm @@ -105,7 +105,7 @@ sub parse_volume { my ($class, $key, $volume_string, $noerr) = @_; my $volume; - if ($key eq 'vmstate') { + if ($key eq 'vmstate' || $key eq 'efi-firmware') { eval { PVE::JSONSchema::check_format('pve-volume-id', $volume_string) }; if (my $err = $@) { return if $noerr; diff --git a/src/PVE/QemuMigrate.pm b/src/PVE/QemuMigrate.pm index 8da6f15d..1ccdffab 100644 --- a/src/PVE/QemuMigrate.pm +++ b/src/PVE/QemuMigrate.pm @@ -440,6 +440,8 @@ sub scan_local_volumes { $self->target_storage_check_available($storecfg, $targetsid, $volid); return if $scfg->{shared} && !$self->{opts}->{remote}; + die "local efi-firmware image\n" if $attr->{is_firmware}; + $local_volumes->{$volid}->{ref} = 'pending' if $attr->{referenced_in_pending}; $local_volumes->{$volid}->{ref} = 'snapshot' if $attr->{referenced_in_snapshot}; $local_volumes->{$volid}->{ref} = 'unused' if $attr->{is_unused}; diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index 63d8c135..53b35b22 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -663,6 +663,14 @@ EODESCR description => "Select BIOS implementation.", default => 'seabios', }, + 'efi-firmware' => { + optional => 1, + type => 'string', + format => 'pve-volume-id', + description => "Custom EFI firmware code image (pflash0). Must be a volid " + . "referencing a 'efi-firmware' content type volume (e.g. " + . "'local:efi-firmware/custom.fd'). Requires bios=ovmf.", + }, vmgenid => { type => 'string', pattern => '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])', @@ -3255,6 +3263,9 @@ sub config_to_command { push @$cmd, '-smbios', "type=1" . $smbios_string; } + die "efi-firmware requires bios=ovmf\n" + if $conf->{'efi-firmware'} && (!$conf->{bios} || $conf->{bios} ne 'ovmf'); + if ($conf->{bios} && $conf->{bios} eq 'ovmf') { die "OVMF (UEFI) BIOS is not supported on 32-bit CPU types\n" if !$forcecpu && get_cpu_bitness($conf->{cpu}, $arch) == 32; @@ -4568,11 +4579,14 @@ sub foreach_volid { $volhash->{$volid}->{is_tpmstate} //= 0; $volhash->{$volid}->{is_tpmstate} = 1 if $key eq 'tpmstate0'; + $volhash->{$volid}->{is_firmware} //= 0; + $volhash->{$volid}->{is_firmware} = 1 if $key eq 'efi-firmware'; + $volhash->{$volid}->{drivename} = $key if is_valid_drivename($key); }; my $include_opts = { - extra_keys => ['vmstate'], + extra_keys => ['vmstate', 'efi-firmware'], include_unused => 1, }; @@ -6123,7 +6137,7 @@ sub get_current_vm_volumes { PVE::QemuConfig->foreach_volume_full( $conf, - { extra_keys => ['vmstate'] }, + { extra_keys => ['vmstate', 'efi-firmware'] }, sub { my ($ds, $drive) = @_; -- 2.34.1