From nobody Fri Jan 9 08:49:11 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1766969156; cv=none; d=zohomail.com; s=zohoarc; b=aGwxoQvkpDezNAXpduX0RXJZlC4IkCleOUjrC3tWSXxkzUWtqN77MMgi4dJaQjNqP6FmDIFxiiHwmHuS3qeCtU/a/pFamSctG0SJeJYy9mSZW6dc8w8/m/sh4xdeHTrS9+UTDuT3Ngcw3sjjFThHG3SzC2ua8ogvprj8F+R/gUA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1766969156; h=Content-Type:Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id:Cc; bh=Elw5JQqPQGAXZ0s5AtvF8v9D+eNEE8n6/3pAQFGkh/s=; b=T2uHejWiT9S+xfsGu11KOcWeeiLgLbIIsavs+TxVSkzxbMXXM75df8MnIQUSddamoUa/Dk6IcF/x3QbbABSgF/APkNAnd+95KL3tba0VKXWuYZgGOHSfkk+iT0AsdEVpX1iC1qCCFmMSsRUGRO0LtvnnwEFHj1J5bq8A2CqQjkU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1766969156455887.920594276151; Sun, 28 Dec 2025 16:45:56 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 749ED3F92F; Sun, 28 Dec 2025 19:45:55 -0500 (EST) Received: from [172.19.199.83] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id 2A2C241910; Sun, 28 Dec 2025 19:39:21 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 1B35D419FF; Sun, 28 Dec 2025 18:49:26 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 5198E41BEB for ; Sun, 28 Dec 2025 18:41:04 -0500 (EST) Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-630-VJ9HUz19PSqjfk22GvlSFA-1; Sun, 28 Dec 2025 18:41:02 -0500 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9EDD9180028B for ; Sun, 28 Dec 2025 23:41:01 +0000 (UTC) Received: from harajuku.usersys.redhat.com.homenet.telecomitalia.it (unknown [10.45.224.19]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id E1D1E1800665 for ; Sun, 28 Dec 2025 23:41:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1766965264; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Elw5JQqPQGAXZ0s5AtvF8v9D+eNEE8n6/3pAQFGkh/s=; b=TlgN96pn1r8yuiUJmUvrpg62pP4UTUG1wygC58Dbb2Fvy6SYfzz9efwXzW0fc3XHxIhR0a 9lSECMgcHA8ql20mv46xlXOtNAlvat6P7aWhr7HEJBYojBdgDJ1kUPVxeDi6TyyTNtNB4p IZOXCznjEPsCgbkNxk6jw09obezvxdw= X-MC-Unique: VJ9HUz19PSqjfk22GvlSFA-1 X-Mimecast-MFC-AGG-ID: VJ9HUz19PSqjfk22GvlSFA_1766965261 To: devel@lists.libvirt.org Subject: [PATCH 08/29] DONOTMERGE: qemu_firmware: Support extended syntax for ROM firmware descriptors Date: Mon, 29 Dec 2025 00:40:27 +0100 Message-ID: <20251228234048.1711701-9-abologna@redhat.com> In-Reply-To: <20251228234048.1711701-1-abologna@redhat.com> References: <20251228234048.1711701-1-abologna@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: bzg_DbILsR0NKsrkFN3M9hQfLzmQqgLGReDo2K-1bmg_1766965261 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: VKZQUHGGLKP3YWX5FCY4UUVME4ZOIS34 X-Message-ID-Hash: VKZQUHGGLKP3YWX5FCY4UUVME4ZOIS34 X-MailFrom: abologna@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; 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: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Andrea Bolognani via Devel Reply-To: Andrea Bolognani X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1766969157028158500 Content-Type: text/plain; charset="utf-8"; x-default="true" The legacy syntax can only describe stateless firmware builds, while the extended one can additionally describe split builds where an NVRAM file is used for variable storage. The extended syntax is basically identical to the one that we already have to support for flash firmware descriptors. It's a strict superset of the legacy one, so we can always store the former one internally and not worry about the differences past the parse phase. Some of the output files for qemufirmwaretest are updated as a consequence of this, but the changes are not semantically meaningful. DONOTMERGE: The extended syntax has not been accepted into the official spec yet. Signed-off-by: Andrea Bolognani --- src/qemu/qemu_firmware.c | 130 ++++++++++++++++-- ...tdx.json =3D> 50-edk2-ovmf-x64-microvm.json} | 12 +- .../firmware/60-edk2-ovmf-x64-inteltdx.json | 6 +- .../out/usr/share/qemu/firmware/91-bios.json | 33 +++++ 4 files changed, 166 insertions(+), 15 deletions(-) copy tests/qemufirmwaredata/out/usr/share/qemu/firmware/{60-edk2-ovmf-x64-= inteltdx.json =3D> 50-edk2-ovmf-x64-microvm.json} (56%) create mode 100644 tests/qemufirmwaredata/out/usr/share/qemu/firmware/91-b= ios.json diff --git a/src/qemu/qemu_firmware.c b/src/qemu/qemu_firmware.c index 5f5550424f..bf6090fac0 100644 --- a/src/qemu/qemu_firmware.c +++ b/src/qemu/qemu_firmware.c @@ -93,9 +93,26 @@ struct _qemuFirmwareMappingFlash { }; =20 =20 +typedef enum { + QEMU_FIRMWARE_MEMORY_MODE_SPLIT, + QEMU_FIRMWARE_MEMORY_MODE_STATELESS, + + QEMU_FIRMWARE_MEMORY_MODE_LAST, +} qemuFirmwareMemoryMode; + +VIR_ENUM_DECL(qemuFirmwareMemoryMode); +VIR_ENUM_IMPL(qemuFirmwareMemoryMode, + QEMU_FIRMWARE_MEMORY_MODE_LAST, + "split", + "stateless", +); + + typedef struct _qemuFirmwareMappingMemory qemuFirmwareMappingMemory; struct _qemuFirmwareMappingMemory { + qemuFirmwareMemoryMode mode; qemuFirmwareFile executable; + qemuFirmwareFile nvram_template; }; =20 =20 @@ -218,6 +235,7 @@ static void qemuFirmwareMappingMemoryFreeContent(qemuFirmwareMappingMemory *memory) { qemuFirmwareFileFreeContent(&memory->executable); + qemuFirmwareFileFreeContent(&memory->nvram_template); } =20 =20 @@ -405,15 +423,90 @@ qemuFirmwareMappingMemoryParse(const char *path, virJSONValue *doc, qemuFirmwareMappingMemory *memory) { - const char *filename; - - if (!(filename =3D virJSONValueObjectGetString(doc, "filename"))) { - VIR_DEBUG("missing 'filename' in '%s'", path); + virJSONValue *mode; + virJSONValue *executable; + virJSONValue *nvram_template; + virJSONValue *filename; + + mode =3D virJSONValueObjectGet(doc, "mode"); + executable =3D virJSONValueObjectGet(doc, "executable"); + nvram_template =3D virJSONValueObjectGet(doc, "nvram-template"); + filename =3D virJSONValueObjectGet(doc, "filename"); + + /* Firmware descriptors can use either the legacy syntax (filename) or + * the extended one (mode, executable and optionally nvram-template), + * but mixing and matching the two is not allowed. Malformed firmware + * descriptors will be ignored */ + if (!executable && !filename) { + VIR_DEBUG("Must have one of 'executable' and 'filename' in '%s'", = path); + return -1; + } + if (executable && filename) { + VIR_DEBUG("Cannot have both 'executable' and 'filename' in '%s'", = path); return -1; } + if (executable && !mode) { + VIR_DEBUG("Must have 'mode' with 'executable' in '%s'", path); + return -1; + } + if (filename && mode) { + VIR_DEBUG("Cannot have 'mode' with 'filename' in '%s'", path); + return -1; + } + if (filename && nvram_template) { + VIR_DEBUG("Cannot have 'nvram_template' with 'filename' in '%s'", = path); + return -1; + } + + if (mode) { + const char *modestr; + int modeval; + + modestr =3D virJSONValueGetString(mode); + if (!modestr) { + VIR_DEBUG("Value of 'mode' is not a string in '%s'", path); + return -1; + } =20 - memory->executable.filename =3D g_strdup(filename); - memory->executable.format =3D g_strdup("raw"); + modeval =3D qemuFirmwareMemoryModeTypeFromString(modestr); + if (modeval < 0) { + VIR_DEBUG("Unrecognized value '%s' for 'mode' in '%s'", modest= r, path); + return -1; + } + + memory->mode =3D modeval; + } else { + /* Default for legacy syntax */ + memory->mode =3D QEMU_FIRMWARE_MEMORY_MODE_STATELESS; + } + + if (executable) { + if (qemuFirmwareFileParse(path, executable, &memory->executable) <= 0) + return -1; + } + + if (memory->mode =3D=3D QEMU_FIRMWARE_MEMORY_MODE_SPLIT) { + if (!nvram_template) { + VIR_DEBUG("Missing mandatory 'nvram-template' for mode=3Dsplit= in '%s'", path); + return -1; + } + + if (qemuFirmwareFileParse(path, nvram_template, &memory->nvram_tem= plate) < 0) + return -1; + } + + if (filename) { + const char *filenameval; + + filenameval =3D virJSONValueGetString(filename); + if (!filenameval) { + VIR_DEBUG("Value of 'filename' is not a string in '%s'", path); + return -1; + } + + memory->executable.filename =3D g_strdup(filenameval); + memory->executable.format =3D g_strdup("raw"); + } =20 return 0; } @@ -697,11 +790,32 @@ static int qemuFirmwareMappingMemoryFormat(virJSONValue *mapping, qemuFirmwareMappingMemory *memory) { + g_autoptr(virJSONValue) executable =3D NULL; + g_autoptr(virJSONValue) nvram_template =3D NULL; + if (virJSONValueObjectAppendString(mapping, - "filename", - memory->executable.filename) < 0) + "mode", + qemuFirmwareMemoryModeTypeToString(= memory->mode)) < 0) + return -1; + + if (!(executable =3D qemuFirmwareFileFormat(memory->executable))) + return -1; + + if (virJSONValueObjectAppend(mapping, + "executable", + &executable) < 0) return -1; =20 + if (memory->mode =3D=3D QEMU_FIRMWARE_MEMORY_MODE_SPLIT) { + if (!(nvram_template =3D qemuFirmwareFileFormat(memory->nvram_temp= late))) + return -1; + + if (virJSONValueObjectAppend(mapping, + "nvram-template", + &nvram_template) < 0) + return -1; + } + return 0; } =20 diff --git a/tests/qemufirmwaredata/out/usr/share/qemu/firmware/60-edk2-ovm= f-x64-inteltdx.json b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/50= -edk2-ovmf-x64-microvm.json similarity index 56% copy from tests/qemufirmwaredata/out/usr/share/qemu/firmware/60-edk2-ovmf-x= 64-inteltdx.json copy to tests/qemufirmwaredata/out/usr/share/qemu/firmware/50-edk2-ovmf-x64= -microvm.json index 2630b57b05..ebe1c2db55 100644 --- a/tests/qemufirmwaredata/out/usr/share/qemu/firmware/60-edk2-ovmf-x64-i= nteltdx.json +++ b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/50-edk2-ovmf-x64-m= icrovm.json @@ -4,20 +4,20 @@ ], "mapping": { "device": "memory", - "filename": "/usr/share/edk2/ovmf/OVMF.inteltdx.secboot.fd" + "mode": "stateless", + "executable": { + "filename": "/usr/share/edk2/ovmf/MICROVM.fd", + "format": "raw" + } }, "targets": [ { "architecture": "x86_64", "machines": [ - "pc-q35-*" + "microvm" ] } ], "features": [ - "enrolled-keys", - "intel-tdx", - "secure-boot", - "verbose-dynamic" ] } diff --git a/tests/qemufirmwaredata/out/usr/share/qemu/firmware/60-edk2-ovm= f-x64-inteltdx.json b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/60= -edk2-ovmf-x64-inteltdx.json index 2630b57b05..68a1cb4ee0 100644 --- a/tests/qemufirmwaredata/out/usr/share/qemu/firmware/60-edk2-ovmf-x64-i= nteltdx.json +++ b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/60-edk2-ovmf-x64-i= nteltdx.json @@ -4,7 +4,11 @@ ], "mapping": { "device": "memory", - "filename": "/usr/share/edk2/ovmf/OVMF.inteltdx.secboot.fd" + "mode": "stateless", + "executable": { + "filename": "/usr/share/edk2/ovmf/OVMF.inteltdx.secboot.fd", + "format": "raw" + } }, "targets": [ { diff --git a/tests/qemufirmwaredata/out/usr/share/qemu/firmware/91-bios.jso= n b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/91-bios.json new file mode 100644 index 0000000000..10a22969f4 --- /dev/null +++ b/tests/qemufirmwaredata/out/usr/share/qemu/firmware/91-bios.json @@ -0,0 +1,33 @@ +{ + "interface-types": [ + "bios" + ], + "mapping": { + "device": "memory", + "mode": "stateless", + "executable": { + "filename": "/usr/share/seabios/bios-256k.bin", + "format": "raw" + } + }, + "targets": [ + { + "architecture": "i386", + "machines": [ + "pc-i440fx-*", + "pc-q35-*" + ] + }, + { + "architecture": "x86_64", + "machines": [ + "pc-i440fx-*", + "pc-q35-*" + ] + } + ], + "features": [ + "acpi-s3", + "acpi-s4" + ] +} --=20 2.52.0