From patchwork Fri Feb 13 20:24:06 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1848 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014283; bh=eKK6MMxHedpJmVo2z158WX/GtqFGGEQdDhHHu1a3FzE=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=gWfMK4CFv1s/HzSlDHdoLdOSgkNRk1MymBQL5gLe7rb8fkESxrgUm8lW291PfDwWk 6SwetaorqtvA3ICkngSk8m7C7o+oN0lFihiXmN3tjUhoQqjJUB9UUxJSgBDbzuFrz9 2Mih/IFFTfwiyo3syybF0rt6fHPK3QgsA62FuwLCmx+Iz7HPXMXjI2l/+txu2Fkjzl KMxwelz7j25YcH3q9mSLK5w7t7rbnFEe0d4a43Y+f/Tid6tJL6BbH9eHrBK6XwcWmU Uzu6Pzunu4gPx+D9Yo6cJ224pIDl5sVIeLXpYUOg91aFR/TG4VdY3tPm0/JqV+FBtE vhN351ChhJ6ZA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 7CF2769B2D for ; Fri, 13 Feb 2026 13:24:43 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id Wxp9CY3ERWjD for ; Fri, 13 Feb 2026 13:24:43 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014283; bh=eKK6MMxHedpJmVo2z158WX/GtqFGGEQdDhHHu1a3FzE=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=gWfMK4CFv1s/HzSlDHdoLdOSgkNRk1MymBQL5gLe7rb8fkESxrgUm8lW291PfDwWk 6SwetaorqtvA3ICkngSk8m7C7o+oN0lFihiXmN3tjUhoQqjJUB9UUxJSgBDbzuFrz9 2Mih/IFFTfwiyo3syybF0rt6fHPK3QgsA62FuwLCmx+Iz7HPXMXjI2l/+txu2Fkjzl KMxwelz7j25YcH3q9mSLK5w7t7rbnFEe0d4a43Y+f/Tid6tJL6BbH9eHrBK6XwcWmU Uzu6Pzunu4gPx+D9Yo6cJ224pIDl5sVIeLXpYUOg91aFR/TG4VdY3tPm0/JqV+FBtE vhN351ChhJ6ZA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 6B4ED69B34 for ; Fri, 13 Feb 2026 13:24:43 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014281; bh=SqFb9yTvEUgxRK6OSXx9tGwz2hHWuXYr7QOjEXdrEOY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=B/ZONEPMF0LFAgVedsYkUg+A3aknPJlUWTqPiwgoIrl66T/TE/Y3B8nF/spmVdcbM geRj+TbEuHLq29Fed7EPGu+btyiX5tQN6jqqSqPo05hWlt1YZMdys7RMV/QJjbkPkZ S/WPiyc8AXOrZS1+Ns4BgAmYdUJ88kwXU62TP2pILs+hZRZZro8Y0rRduDuq9f3ciT Zd44TGp+7kkzo9jvtpRwXfu3doOYXTkmb2wCL5FULOBHH99iWvnN7xRFiSqKmPkmpZ rYHUBaoJHnwN9PuR8xkBctLQtBgXOpNx3SHyGcmyQFB4GyvsnRohbiPxc9z6fOTdFl fbxJ5uamVicgQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 12D7C69B34; Fri, 13 Feb 2026 13:24:41 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id 6I4LOjhGpSzd; Fri, 13 Feb 2026 13:24:41 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014277; bh=SOfKjelA/BKZNl4ZEkjhsKc0o8HJn/zu5MoiYyPkjGw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pJva16hb+LZcFccUmhTxxT+dEH0dDk7psMP2xnZ+2lR5q/h5AXdyLBl4XkcZmi/ZW lRcUlkYvma+m8nVL9CLjz14LTiSx/tOhU48SRW7mfl6ukuB0sEwjnSW02XtMAdF6rq 0uv+yg92m0lSyAhr4E+lo6K+Muic1YJgoUPx8UfusxYX7uLAv4ryLknYvnbV3uoJ7t /JJgMjOOsXIJg2C0wYf2nc17VxFztulcWtbAqRfVYMjvrQN1no7NXfijKbDzk8hd+D jNTzatDcdm8Qr53/sa6Ef5bZ4JQQQy2nf4vVWkc2g01YFRqYJv7EsDDBkYOlRAac6+ ASmpTDmXFWNOQ== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id BB8BA69B0E; Fri, 13 Feb 2026 13:24:36 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Fri, 13 Feb 2026 13:24:06 -0700 Message-ID: <20260213202417.223068-2-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260213202417.223068-1-sjg@u-boot.org> References: <20260213202417.223068-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: 6P6UCARSZGGFTJ2ORCWG23EKZYBE263U X-Message-ID-Hash: 6P6UCARSZGGFTJ2ORCWG23EKZYBE263U X-MailFrom: sjg@u-boot.org 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 CC: Simon Glass , "Claude Opus 4 . 6" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 1/8] dm: Fix linker list alignment for ll_entry_get() List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass The extern declaration in ll_entry_get() lacks the __aligned(4) attribute present in ll_entry_declare(). When the compiler sees an unaligned extern reference to a linker list entry in the same compilation unit as its definition, it may increase the section alignment beyond the expected struct size. This causes gaps in the linker list array, which the alignment checker reports as failures. For example, sandbox_dir is both defined and referenced via DM_DRIVER_GET() in sandboxfs.c. The compiler applies 32-byte alignment to its section instead of the 4-byte alignment from the definition, creating an 8-byte gap before it in the driver list. Add __aligned(4) to the extern declaration in ll_entry_get() to match ll_entry_declare() Co-developed-by: Claude Opus 4.6 Signed-off-by: Simon Glass --- include/linker_lists.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linker_lists.h b/include/linker_lists.h index 6a018f175ca..470dcfc621a 100644 --- a/include/linker_lists.h +++ b/include/linker_lists.h @@ -284,7 +284,8 @@ */ #define ll_entry_get(_type, _name, _list) \ ({ \ - extern _type _u_boot_list_2_##_list##_2_##_name; \ + extern _type _u_boot_list_2_##_list##_2_##_name \ + __aligned(4); \ _type *_ll_result = \ &_u_boot_list_2_##_list##_2_##_name; \ _ll_result; \ From patchwork Fri Feb 13 20:24:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1849 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014287; bh=e/6vrRsLrV9kzVTGKo15QPb4JeSRWzY/zCghVr0hF7c=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=e7K0sL0NExeqlJ1Ho76n73VfHexOXimM8uYhwglz7paH1GUwG6OJqujaimyFox6nX 0urWJCBskvG0tb3ATtL5saaxRRFns8pOo/8mgym8DyGELnxMPYufUYQjahzErFef6R TpFRoyyfKTTN18uGuofk8Cob5l1Y5gcPvTQtAFxUqzq8n0sqm8QlRwDr7zciolfCQ8 NWfxVK2xnKbr066yTT2++5G9m2mielbIBPQNpdOGWWoAX5f+80EL1vJnYTbyqRwgs9 2osJOu4/sP7f/kauwnThB5oeFKqSugQEoKpfSOqcw5adAoOGe3xFYrsEdFcpnxmYXg YRvHrxr4cs3Kw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 12BB169B36 for ; Fri, 13 Feb 2026 13:24:47 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id gXfHH1yihjDf for ; Fri, 13 Feb 2026 13:24:47 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014286; bh=e/6vrRsLrV9kzVTGKo15QPb4JeSRWzY/zCghVr0hF7c=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=Afx59sUThjgxJhUgs2eERDfGbnCBp8HaSO1IPIYKsfBKRd+Rg4dWFqXvgqouJdIXz VKBige3at1IMHACeVrPNUNT7wY5uMt3VxyUYllAZ0IaMeXhZQMqqjQuxDrFRELTcZ0 Z4Q3HlbYHtz6grq5IVWTDSwWyaL5lI8ar+Rc9IR0bfd6kh7lCm8WxRNN/Bbx8iI7pS bVSM1Gdtl+8g+0HDwQi0YjwAN5L0iBqvGdt3ekO983TQ/sMXHsbsFT1dXHYzTYcBFU 8HhrNroaYCTKC33CIRBBpgwaO6XT0obC0jp4zJvBZ+FDRVV2SYtvOQUA03Qv2ZN4FS PT5HwxSgm77pw== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id F20BB69B2D for ; Fri, 13 Feb 2026 13:24:46 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014286; bh=kE/ASVsYcwr/ZqkhXY4dAfiKGh9Pn/FSQ+XlKV/Rs0E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jT5Xwx9FUVNWi9PXNRQnT2yNgu95BH23IZskLO6r+WwFAUqiEbAEyyxqSqpeeK5R+ 5+EypBQivGclHSi+0XMeH9kzlrApMFyHF6SLH8sCfwNVWZOu9m1nhJX+oliO/Bv3sV MaOW2oBN4hvtl53SDnvcrbAU4M8/N1dBcIx+U7KV0Bwp41VXA3waMrOw+YelA2J6d6 pHU5b8c7Dd1+QKTEy+Y7+NADO8MnybyC6+nwpBfgw6eZynnkUaIE1E77e+vFO7Vlis kt3zXhl275b0xd3Ag723Qo/IcGTSMjGw8MD/mhEqatgRMw0GttQiqmHUfXpE+y+9cI 5G3nch9QURK+A== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 0354569B2D; Fri, 13 Feb 2026 13:24:46 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id 4Wdqhu03zwQ0; Fri, 13 Feb 2026 13:24:45 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014281; bh=7z0nuLEj+Ps8Y0qRVUzN94E6SP3D6JTSgN1Jb7h6HLw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gXq6CS/NYB6nCC8czzK741J5oNHrQl3PZy7vZBwRT9dhU/xX59ce5xfVUIzYIknhf tCf4k1+vj/FmjR+IwaRmMoOK+FK/9xOfXgOyotAUq4N0NrrQFrT2R1ZMTQQ/Sjsidw LkQR4zRvxwlSdlwTRym0Zqdkkl5o+/1MMn9XfvnH3OLOp8hyJCikfxLC71euhF6OBl 0ePnAciiZthBDIaPnz5VtthpeXo3a5LDagFADoR8AQeLuc/b3EUf77uq9bm3Pevu+s PvhZ6eWGRlv+bQrX8fq14Ax9DGY2KVZhpidXKbn0dnglfzzhiUMj/IDdpQTIDnZ9c0 WmIK+HUY/u2Rg== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 4EFD369B0E; Fri, 13 Feb 2026 13:24:41 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Fri, 13 Feb 2026 13:24:07 -0700 Message-ID: <20260213202417.223068-3-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260213202417.223068-1-sjg@u-boot.org> References: <20260213202417.223068-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: LAYLRPHGK4DSLBTEOQT7H75RN645Y3GX X-Message-ID-Hash: LAYLRPHGK4DSLBTEOQT7H75RN645Y3GX X-MailFrom: sjg@u-boot.org 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 CC: Simon Glass , "Claude Opus 4 . 6" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 2/8] part_find: Fix PARTITION_TYPE_GUID dependency warning List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass CMD_PART_FIND selects PARTITION_TYPE_GUID which depends on EFI_PARTITION, causing an unmet-dependency warning when EFI_PARTITION is not enabled. Since part_find searches by type GUID, which is a GPT concept, change the dependency from PARTITIONS to EFI_PARTITION. This satisfies the PARTITION_TYPE_GUID dependency and makes sense, since EFI_PARTITION already selects PARTITIONS Co-developed-by: Claude Opus 4.6 Signed-off-by: Simon Glass --- cmd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index 243fa55677b..09fc13626bd 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1637,7 +1637,7 @@ config CMD_PART config CMD_PART_FIND bool "part_find" - depends on PARTITIONS + depends on EFI_PARTITION default y if SANDBOX || EFI_APP select HAVE_BLOCK_DEVICE select PARTITION_UUIDS From patchwork Fri Feb 13 20:24:08 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1850 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014291; bh=geCW4x5MlzwErgIq+eTGPWG8Ngg4JS7+tpssgSCjWMg=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=boTgnGfwtjj79frVfr16D7hifnHPNiSMtAvuEJF77RnbOBCURHMzVdPtQm+VJcdQ+ je7OXR4rgL0en6HpPDd4oee4HqIc/2Aeiv6vshK1IGEZwQLKVL+UyTxgX41yC4Nb7a gPsZ+Xmc3uNECPaU0hsWyHCRYsLPO4VVmxN6maAJs7CwJaH2HyuTvB9+y7rH8zGsy8 GFp1w56vELGisjNHr5nSMi78erIHDxN19w9v35fxyMoWm7QmTUUhog6wP/XLEvok51 Asb2iVVtsIKa45wnTcTP+JnqOq1zdw0u8lHxpTkA5FvvP6iX6BQg2gNWgrP0BJOlmx y2rw4/MDTAOIA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 7C26F69B3F for ; Fri, 13 Feb 2026 13:24:51 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id TyxhHi9v5Oh0 for ; Fri, 13 Feb 2026 13:24:51 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014290; bh=geCW4x5MlzwErgIq+eTGPWG8Ngg4JS7+tpssgSCjWMg=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=gbktJmSJ7aZsYgDD0dK7tNSrLJQTyit0kh8mn2HXYMNTw5/aLLdgCXwRdH7pnuRiu 0GDwFzyq1QoFfZySrPTfarYQ96yyF4f99sL2U2pWo5ePs0Y+yA9Llfnp2jX/w+wRHE ffVrvhGt9fgB6IPkaiRvtxP33DaJMT70h/yvKxWsjHeZfSZtrqUt7lZgv3Cti703qC Yhc4LYK7KVCf2iC9p2SJ56eL83hRFuWgRu3OlHXRDR433jbHeSfB6OiAH0i2BpC7/6 EroyiX2TleWTn7fXGjG4tN7xBb2KPave1FnTS+5UALhmUzZzE36hWyyGcMLexRmd7g 7M5CTFWQPknWA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id D007369B0E for ; Fri, 13 Feb 2026 13:24:50 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014289; bh=fLcKweeBsPyzkXNp/Vp3VtmINTwWwvj5sfp1l6+pc04=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tXDw1vUWplvhgMmJ/CuRRmTFxgUDV69tFcxHPlb38pAbZ2S0WQjZlZa1fCs+c+bwr jK6xpDwZjBCOktWdfgGlrVsRAPl08Vr4NlKwEDc0IXkHu27hyx4Tnr4putwqfrWdDQ ByzaSzx+NXvA9ZtgC1XsYRCrRZiouOFw2zM9HK7WmuUf9OidcXOT1k7KAYcQOk7RCU b9RxVpI2F0hcgfYnYVcvCGQ+cbPhWaeTUbRjK7tq4+xpjf0ED7GmUMOsdXljll0p4h NybHvNtzzvrWUsraOfaVTLLZaX2dstXfvx/RuPOGcwPEsOyBkb4iiLF+i0DjtFGwHo As6XUIMv9EDvQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 5082C69B2D; Fri, 13 Feb 2026 13:24:49 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id fkN9QB6lIP2u; Fri, 13 Feb 2026 13:24:49 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014286; bh=rPoYz+voeEdHzGhoRCKqrVDowGM9FwDinQmgw6FgBSU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FKSAAcnHVL5I8fy97atx8St8kJmeg3cJBRE1a4Ci6cL1EvFDiwz7PU1KvF0m9nFFA TF7zCUbFMZklMMFf1V27y9nBOdLe1HbGDrOOf0zAr8SJJya2V6CajqOJ+5foKW2TNs ok1NRm7wW9kSAYCIWpjD2yigArGpTQ0VtWsJ3uFHoeKmGfLxOpZ5tVOxc1nK4tno9S 6t0itX1gsdTxPlbrB8m3TmwPaNVyvadHzol9RnqnrLju1MsZ3OP92Znrp20UocqEDC yBhMilf+3VChGRNnmBtyhR/IU1+sE7sgRhgluE/YsK44sV3Fj1P9Hk3dbkQjjRuuky loeODaxL46B7w== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id DEE5269A66; Fri, 13 Feb 2026 13:24:45 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Fri, 13 Feb 2026 13:24:08 -0700 Message-ID: <20260213202417.223068-4-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260213202417.223068-1-sjg@u-boot.org> References: <20260213202417.223068-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: ZVWVKILFCPS3M3PLYUSVJF25357XG3AR X-Message-ID-Hash: ZVWVKILFCPS3M3PLYUSVJF25357XG3AR X-MailFrom: sjg@u-boot.org 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 CC: Simon Glass , "Claude Sonnet 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 3/8] boot: Add BLS Type #1 entry parser List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add a parser for Boot Loader Specification (BLS) Type #1 entry files, which use a simple key-value format with one field per line. The parser modifies the input buffer in place, adding null terminators to delimit fields. Entry structure fields (except options) point directly into the caller's buffer, which must remain valid for the lifetime of the entry. The options field is allocated separately to support concatenation of multiple option lines. Supported fields: - title: Human-readable entry name - version: OS version string - linux: Kernel path (required) - options: Kernel command line (concatenated if multiple) - initrd: Initramfs paths (can appear multiple times) - devicetree: Device tree blob path - devicetree-overlay: Device tree overlay path - architecture: Target architecture - machine-id: OS identifier - sort-key: Sorting identifier Unknown fields are ignored for forward compatibility. Comments (lines starting with #) and blank lines are skipped. The implementation includes comprehensive unit tests covering basic parsing, multiple options/initrds, error handling, and edge cases. Co-developed-by: Claude Sonnet 4.5 Signed-off-by: Simon Glass --- boot/Kconfig | 21 +++ boot/Makefile | 1 + boot/bls_parse.c | 297 ++++++++++++++++++++++++++++++++++++++++++ include/bls.h | 100 ++++++++++++++ test/boot/Makefile | 1 + test/boot/bls_parse.c | 176 +++++++++++++++++++++++++ 6 files changed, 596 insertions(+) create mode 100644 boot/bls_parse.c create mode 100644 include/bls.h create mode 100644 test/boot/bls_parse.c diff --git a/boot/Kconfig b/boot/Kconfig index 63f7d228ea8..63a0cf0bd7a 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -690,6 +690,27 @@ config BOOTMETH_EXTLINUX_LOCALBOOT This attempts to find a kernel and initrd on the disk and boot it, in the case where there is no "localcmd" in the environment. +config BOOTMETH_BLS + bool "Bootdev support for Boot Loader Specification (BLS) Type #1" + select PXE_UTILS + default y if SANDBOX + help + Enables support for Boot Loader Specification (BLS) Type #1 entries. + This makes bootdevs look for '*.conf' files in 'loader/entries/' + directories on each filesystem they scan. + + BLS is a standard for boot entry configuration used by Fedora, RHEL, + and other distributions. Each .conf file describes a single boot + entry with fields like kernel path, initrd, and boot options. + + The specification is here: + + https://uapi-group.org/specifications/specs/boot_loader_specification/ + + This supports standard BLS fields (title, linux, initrd, options, + devicetree) and works with U-Boot FIT images using the path#config + syntax. + config BOOTMETH_EFI bool "Bootdev support for EFI boot" depends on EFI_BINARY_EXEC diff --git a/boot/Makefile b/boot/Makefile index b2a475d4917..1e75f7ece79 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_$(PHASE_)BOOTSTD_PROG) += prog_boot.o obj-$(CONFIG_$(PHASE_)BOOTMETH_EXTLINUX) += ext_pxe_common.o bootmeth_extlinux.o obj-$(CONFIG_$(PHASE_)BOOTMETH_EXTLINUX_PXE) += ext_pxe_common.o bootmeth_pxe.o +obj-$(CONFIG_$(PHASE_)BOOTMETH_BLS) += bls_parse.o obj-$(CONFIG_$(PHASE_)BOOTMETH_EFI) += bootmeth_efi.o obj-$(CONFIG_$(PHASE_)BOOTMETH_CROS) += bootmeth_cros.o obj-$(CONFIG_$(PHASE_)BOOTMETH_FEL) += bootmeth_fel.o diff --git a/boot/bls_parse.c b/boot/bls_parse.c new file mode 100644 index 00000000000..9a067736655 --- /dev/null +++ b/boot/bls_parse.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Boot Loader Specification (BLS) Type #1 parser + * + * Copyright 2026 Canonical Ltd + * Written by Simon Glass + */ + +#define LOG_CATEGORY UCLASS_BOOTSTD + +#include +#include +#include +#include +#include + +/** + * enum bls_token_t - BLS Type #1 field tokens + * + * Token identifiers for BLS entry fields. Using an enum avoids repeated + * string comparisons during parsing. + * + * Note: The enum values correspond to indices in bls_token_names[] + */ +enum bls_token_t { + TOK_TITLE = 0, + TOK_VERSION, + TOK_LINUX, + TOK_OPTIONS, + TOK_INITRD, + TOK_DEVICETREE, + TOK_DEVICETREE_OVERLAY, + TOK_ARCHITECTURE, + TOK_MACHINE_ID, + TOK_SORT_KEY, + + TOK_COUNT, +}; + +/* BLS field names indexed by enum bls_token_t */ +static const char *const bls_token_names[] = { + [TOK_TITLE] = "title", + [TOK_VERSION] = "version", + [TOK_LINUX] = "linux", + [TOK_OPTIONS] = "options", + [TOK_INITRD] = "initrd", + [TOK_DEVICETREE] = "devicetree", + [TOK_DEVICETREE_OVERLAY] = "devicetree-overlay", + [TOK_ARCHITECTURE] = "architecture", + [TOK_MACHINE_ID] = "machine-id", + [TOK_SORT_KEY] = "sort-key", +}; + +/** + * bls_lookup_token() - Look up a token by name + * + * @key: Field name to look up + * Return: Token enum value, or TOK_COUNT if not recognized + */ +static enum bls_token_t bls_lookup_token(const char *key) +{ + int i; + + for (i = 0; i < TOK_COUNT; i++) { + if (!strcmp(key, bls_token_names[i])) + return i; + } + + return TOK_COUNT; +} + +/** + * bls_append_str() - Append a string to an existing field + * + * Used for fields that can appear multiple times (e.g., options). + * Concatenates with a space separator. + * + * @fieldp: Pointer to field to append to (may be NULL) + * @value: String to append + * Return: 0 on success, -ENOMEM if allocation fails + */ +static int bls_append_str(char **fieldp, const char *value) +{ + size_t old_len, val_len, new_len; + char *new_str; + + if (!*fieldp) { + *fieldp = strdup(value); + return *fieldp ? 0 : -ENOMEM; + } + + old_len = strlen(*fieldp); + val_len = strlen(value); + new_len = old_len + 1 + val_len + 1; /* +1 for space, +1 for nul */ + + new_str = realloc(*fieldp, new_len); + if (!new_str) + return -ENOMEM; + + new_str[old_len] = ' '; + memcpy(new_str + old_len + 1, value, val_len + 1); + + *fieldp = new_str; + + return 0; +} + +/** + * bls_skip_whitespace() - Skip leading whitespace + * + * @strp: Pointer to string pointer (updated to first non-whitespace char) + */ +static void bls_skip_whitespace(char **strp) +{ + char *p = *strp; + + while (*p && isspace(*p)) + p++; + *strp = p; +} + +/** + * bls_parse_line() - Parse a single line from a BLS entry file + * + * Parses one line of a BLS entry. Lines are in "key value" format where + * the key and value are separated by whitespace. The value extends to + * the end of the line. + * + * @line: Line to parse (will be modified) + * @keyp: Returns pointer to key string + * @valuep: Returns pointer to value string + * Return: 0 on success, -EINVAL if line is invalid + */ +static int bls_parse_line(char *line, char **keyp, char **valuep) +{ + char *p = line; + char *key, *value; + + /* Skip leading whitespace */ + bls_skip_whitespace(&p); + + /* Skip blank lines and comments */ + if (!*p || *p == '#') + return -EINVAL; + + /* Extract key */ + key = p; + while (*p && !isspace(*p)) + p++; + if (!*p) + return -EINVAL; /* No value */ + + *p++ = '\0'; + + /* Skip whitespace before value */ + bls_skip_whitespace(&p); + if (!*p) + return -EINVAL; /* No value */ + + value = p; + + /* Remove trailing whitespace from value */ + p = value + strlen(value) - 1; + while (p >= value && isspace(*p)) + *p-- = '\0'; + + *keyp = key; + *valuep = value; + + return 0; +} + +int bls_parse_entry(const char *buf, size_t size, struct bls_entry *entry) +{ + char *data = (char *)buf; + char *line, *next; + bool err = false; + + /* Initialize entry to zero */ + memset(entry, '\0', sizeof(*entry)); + + /* Initialize initrds list */ + alist_init_struct(&entry->initrds, char *); + + log_debug("parsing BLS entry, size %zx\n", size); + + /* Parse buffer line by line, modifying it in place */ + line = data; + while (line < data + size) { + enum bls_token_t token; + char *key, *value; + int ret; + + /* Find end of line */ + next = memchr(line, '\n', data + size - line); + if (next) { + *next = '\0'; + next++; + } else { + next = data + size; + } + + ret = bls_parse_line(line, &key, &value); + if (ret) { + line = next; + continue; /* Skip blank lines and comments */ + } + + log_debug("BLS field: '%s' = '%s'\n", key, value); + line = next; + + /* Look up token and parse supported fields */ + token = bls_lookup_token(key); + switch (token) { + case TOK_TITLE: + /* Point into buffer */ + entry->title = value; + break; + case TOK_VERSION: + /* Point into buffer */ + entry->version = value; + break; + case TOK_LINUX: + /* Point into buffer */ + entry->kernel = value; + break; + case TOK_OPTIONS: + /* Multiple times - allocate and concatenate */ + if (bls_append_str(&entry->options, value)) + err = true; + break; + case TOK_INITRD: + /* Multiple times - add pointer to buffer */ + if (!alist_add(&entry->initrds, value)) + err = true; + break; + case TOK_DEVICETREE: + /* Point into buffer */ + entry->devicetree = value; + break; + case TOK_DEVICETREE_OVERLAY: + /* Point into buffer */ + entry->dt_overlays = value; + break; + case TOK_ARCHITECTURE: + /* Point into buffer */ + entry->architecture = value; + break; + case TOK_MACHINE_ID: + /* Point into buffer */ + entry->machine_id = value; + break; + case TOK_SORT_KEY: + /* Point into buffer */ + entry->sort_key = value; + break; + default: + /* Ignore unknown fields for forward compatibility */ + log_debug("Ignoring unknown BLS field: %s\n", key); + break; + } + } + + /* Check for errors during parsing */ + if (err) + return -ENOMEM; + + /* + * Validate required fields: BLS spec requires at least one of + * 'linux' or 'efi'. We only support 'linux' for Type #1 entries. + */ + if (!entry->kernel) { + log_err("BLS entry missing required 'linux' field\n"); + return -EINVAL; + } + + return 0; +} + +void bls_entry_uninit(struct bls_entry *entry) +{ + if (!entry) + return; + + /* + * Most fields point into the parsed buffer and don't need freeing. + * Only options is allocated (for concatenation of multiple lines). + */ + free(entry->options); + + /* + * Uninit initrds list. The strings in the list point into the buffer, + * so we don't free them, just the list structure. + */ + alist_uninit(&entry->initrds); +} + diff --git a/include/bls.h b/include/bls.h new file mode 100644 index 00000000000..eb32b323f1a --- /dev/null +++ b/include/bls.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Boot Loader Specification (BLS) Type #1 support + * + * Copyright 2026 Canonical Ltd + * Written by Simon Glass + */ + +#ifndef __BLS_H +#define __BLS_H + +#include +#include + +/** + * struct bls_entry - represents a single BLS boot entry + * + * This structure holds the parsed fields from a BLS Type #1 entry file. + * BLS entries use a simple key-value format with one field per line. + * + * Most fields point directly into the parsed buffer and are only valid while + * the buffer remains valid. The exception is @options which is allocated + * because multiple option lines must be concatenated. + * + * @title: Human-readable name (points into buffer) + * @version: OS version string (points into buffer) + * @kernel: Kernel path or FIT image - required (points into buffer) + * Can include FIT config syntax: path#config + * @options: Kernel command line - ALLOCATED, must be freed + * Multiple options lines are concatenated with spaces + * @initrds: List of initrd paths (alist of char * pointing into buffer) + * Multiple initrd lines are supported and accumulated + * @devicetree: Device tree blob path (points into buffer) + * @dt_overlays: Device tree overlays (points into buffer) + * @architecture: Target architecture (points into buffer) + * @machine_id: OS identifier (points into buffer) + * @sort_key: Sorting identifier (points into buffer) + * @filename: Path to .conf file (points into buffer) + */ +struct bls_entry { + char *title; + char *version; + char *kernel; + char *options; /* Allocated */ + struct alist initrds; /* list of char * into buffer */ + char *devicetree; + char *dt_overlays; + char *architecture; + char *machine_id; + char *sort_key; + char *filename; +}; + +/** + * bls_parse_entry() - Parse a BLS entry file + * + * Parses the contents of a BLS Type #1 entry file into a pre-allocated + * entry structure. The format is simple key-value pairs with one field per + * line. Lines starting with '#' are comments and blank lines are ignored. + * + * The entry is initialized to zero before parsing. Most entry fields will + * point directly into the buffer (which is modified to add null terminators). + * The buffer must remain valid for the lifetime of the entry. Only the + * 'options' field is allocated separately because multiple option lines must + * be concatenated. + * + * The caller must call bls_entry_uninit() on the entry when done, regardless + * of whether this function succeeds or fails, to free any allocated memory. + * + * Supported fields: + * title - Human-readable name + * version - OS version string + * linux - Kernel path (required) + * options - Kernel command line (allocated, can appear multiple times) + * initrd - Initramfs path (can appear multiple times) + * devicetree - Device tree blob path + * + * Unknown fields are ignored for forward compatibility. + * + * @buf: Buffer containing the BLS entry file contents (will be modified) + * @size: Size of the buffer in bytes + * @entry: BLS entry structure to fill in (will be initialized) + * Return: 0 on success, -ENOMEM if out of memory, -EINVAL if required fields + * are missing + */ +int bls_parse_entry(const char *buf, size_t size, struct bls_entry *entry); + + +/** + * bls_entry_uninit() - Clean up a BLS entry's fields + * + * Frees all allocated fields within the entry but does not free the entry + * structure itself. Use this for stack-allocated entries. + * + * @entry: Entry to clean up + */ +void bls_entry_uninit(struct bls_entry *entry); + + +#endif /* __BLS_H */ diff --git a/test/boot/Makefile b/test/boot/Makefile index 329f4acbd52..a57e8553b2e 100644 --- a/test/boot/Makefile +++ b/test/boot/Makefile @@ -4,6 +4,7 @@ ifdef CONFIG_UT_BOOTSTD obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o +obj-$(CONFIG_BOOTMETH_BLS) += bls_parse.o obj-$(CONFIG_CMDLINE) += pxe.o obj-$(CONFIG_FIT) += image.o obj-$(CONFIG_$(PHASE_)FIT_PRINT) += fit_print.o diff --git a/test/boot/bls_parse.c b/test/boot/bls_parse.c new file mode 100644 index 00000000000..01da816aee8 --- /dev/null +++ b/test/boot/bls_parse.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for Boot Loader Specification (BLS) parser + * + * Copyright 2026 Canonical Ltd + * Written by Simon Glass + */ + +#include +#include + +/* Test basic BLS entry parsing */ +static int bls_test_parse_basic(struct unit_test_state *uts) +{ + struct bls_entry entry; + char buf[] = + "title Test Entry\n" + "version 1.0\n" + "linux /vmlinuz\n" + "options root=/dev/sda\n" + "initrd /initrd.img\n" + "devicetree /test.dtb\n"; + + ut_assertok(bls_parse_entry(buf, sizeof(buf) - 1, &entry)); + ut_asserteq_str("Test Entry", entry.title); + ut_asserteq_str("1.0", entry.version); + ut_asserteq_str("/vmlinuz", entry.kernel); + ut_asserteq_str("root=/dev/sda", entry.options); + ut_asserteq(1, entry.initrds.count); + ut_asserteq_str("/test.dtb", entry.devicetree); + + bls_entry_uninit(&entry); + + return 0; +} +UNIT_TEST(bls_test_parse_basic, 0, bootstd); + +/* Test multiple options lines are concatenated */ +static int bls_test_parse_multi_options(struct unit_test_state *uts) +{ + struct bls_entry entry; + char buf[] = + "title Test\n" + "linux /vmlinuz\n" + "options root=/dev/sda\n" + "options quiet splash\n"; + + ut_assertok(bls_parse_entry(buf, sizeof(buf) - 1, &entry)); + ut_asserteq_str("root=/dev/sda quiet splash", entry.options); + + bls_entry_uninit(&entry); + + return 0; +} +UNIT_TEST(bls_test_parse_multi_options, 0, bootstd); + +/* Test multiple initrd lines */ +static int bls_test_parse_multi_initrd(struct unit_test_state *uts) +{ + struct bls_entry entry; + char buf[] = + "title Test\n" + "linux /vmlinuz\n" + "initrd /initrd1.img\n" + "initrd /initrd2.img\n"; + const char **initrd; + + ut_assertok(bls_parse_entry(buf, sizeof(buf) - 1, &entry)); + ut_asserteq(2, entry.initrds.count); + + initrd = alist_get(&entry.initrds, 0, char *); + ut_asserteq_str("/initrd1.img", *initrd); + + initrd = alist_get(&entry.initrds, 1, char *); + ut_asserteq_str("/initrd2.img", *initrd); + + bls_entry_uninit(&entry); + + return 0; +} +UNIT_TEST(bls_test_parse_multi_initrd, 0, bootstd); + +/* Test comments and blank lines are ignored */ +static int bls_test_parse_comments(struct unit_test_state *uts) +{ + struct bls_entry entry; + char buf[] = + "# This is a comment\n" + "title Test\n" + "\n" + "# Another comment\n" + "linux /vmlinuz\n" + "\n"; + + ut_assertok(bls_parse_entry(buf, sizeof(buf) - 1, &entry)); + ut_asserteq_str("Test", entry.title); + ut_asserteq_str("/vmlinuz", entry.kernel); + + bls_entry_uninit(&entry); + + return 0; +} +UNIT_TEST(bls_test_parse_comments, 0, bootstd); + +/* Test missing required field returns error */ +static int bls_test_parse_missing_kernel(struct unit_test_state *uts) +{ + struct bls_entry entry; + char buf[] = + "title Test\n" + "options root=/dev/sda\n"; + + ut_asserteq(-EINVAL, bls_parse_entry(buf, sizeof(buf) - 1, &entry)); + + bls_entry_uninit(&entry); + + return 0; +} +UNIT_TEST(bls_test_parse_missing_kernel, 0, bootstd); + +/* Test unknown fields are ignored */ +static int bls_test_parse_unknown_field(struct unit_test_state *uts) +{ + struct bls_entry entry; + char buf[] = + "title Test\n" + "linux /vmlinuz\n" + "unknown_field some_value\n" + "another_unknown 123\n"; + + ut_assertok(bls_parse_entry(buf, sizeof(buf) - 1, &entry)); + ut_asserteq_str("Test", entry.title); + + bls_entry_uninit(&entry); + + return 0; +} +UNIT_TEST(bls_test_parse_unknown_field, 0, bootstd); + +/* Test all supported fields */ +static int bls_test_parse_all_fields(struct unit_test_state *uts) +{ + struct bls_entry entry; + char buf[] = + "title Full Test\n" + "version 2.0.1\n" + "linux /boot/vmlinuz-2.0.1\n" + "options root=/dev/sda1 ro\n" + "options quiet splash\n" + "initrd /boot/initrd-2.0.1.img\n" + "devicetree /boot/dtb-2.0.1.dtb\n" + "devicetree-overlay /boot/overlay.dtbo\n" + "architecture x86_64\n" + "machine-id abc123\n" + "sort-key 001\n"; + const char **initrd; + + ut_assertok(bls_parse_entry(buf, sizeof(buf) - 1, &entry)); + ut_asserteq_str("Full Test", entry.title); + ut_asserteq_str("2.0.1", entry.version); + ut_asserteq_str("/boot/vmlinuz-2.0.1", entry.kernel); + ut_asserteq_str("root=/dev/sda1 ro quiet splash", entry.options); + ut_asserteq(1, entry.initrds.count); + initrd = alist_get(&entry.initrds, 0, char *); + ut_asserteq_str("/boot/initrd-2.0.1.img", *initrd); + ut_asserteq_str("/boot/dtb-2.0.1.dtb", entry.devicetree); + ut_asserteq_str("/boot/overlay.dtbo", entry.dt_overlays); + ut_asserteq_str("x86_64", entry.architecture); + ut_asserteq_str("abc123", entry.machine_id); + ut_asserteq_str("001", entry.sort_key); + + bls_entry_uninit(&entry); + + return 0; +} +UNIT_TEST(bls_test_parse_all_fields, 0, bootstd); From patchwork Fri Feb 13 20:24:09 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1851 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014295; bh=PdDYbV24z49WhVNh8EzMBSCFM4Uf1LLBt540BbbR/n4=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=jQL60pczL2yNvq4A06I7Nc6GwOMh1H8abYcd5jRdM9g0uFwtPB17fW6HJH2ZRNVqd P6kvhm4VTIEOsEjj9Tev6BnAorVtpQfpfy5n9aZJPoHJYrI0ZtKj1b7r81UK9mCUQI 03mKcehF757PPbKPbiPbOf8I69UUq4RSMJRgqdGXrvrOpM2gVKeuyygomhkTamAbBB jonJnp+M7t6CyhgG7yd0XV2uK54UeUClLFRolrMCPuV289ahya9CQWICwV5lqt3HfR hdWXN6hpnkoWGxkeV46PfM/lXvzJCGnQJHgvSH3dVmYGPbb33cbwiFbEUIkADOOoJs J8SBdE8Pa2lxQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 726AB69B3A for ; Fri, 13 Feb 2026 13:24:55 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id huxtujtgs6SL for ; Fri, 13 Feb 2026 13:24:55 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014295; bh=PdDYbV24z49WhVNh8EzMBSCFM4Uf1LLBt540BbbR/n4=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=jQL60pczL2yNvq4A06I7Nc6GwOMh1H8abYcd5jRdM9g0uFwtPB17fW6HJH2ZRNVqd P6kvhm4VTIEOsEjj9Tev6BnAorVtpQfpfy5n9aZJPoHJYrI0ZtKj1b7r81UK9mCUQI 03mKcehF757PPbKPbiPbOf8I69UUq4RSMJRgqdGXrvrOpM2gVKeuyygomhkTamAbBB jonJnp+M7t6CyhgG7yd0XV2uK54UeUClLFRolrMCPuV289ahya9CQWICwV5lqt3HfR hdWXN6hpnkoWGxkeV46PfM/lXvzJCGnQJHgvSH3dVmYGPbb33cbwiFbEUIkADOOoJs J8SBdE8Pa2lxQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 5FDEF69B2D for ; Fri, 13 Feb 2026 13:24:55 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014293; bh=Bpey8WLf7E8ubiZuAwq0vM4zBWiL/xRDizUZb0LdOzs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ugvlDHzA/PZ6bQ8+ftVGnO431uoLGA1JrWMei0CKXnynYxaZr8kmn3FYtreku3Qv6 BM8Bx6DdnEhRkaF8BVxrCm7E4vdK8gpQcGVFRHpAGf1Y6ybxAoXEUYydZ6K+NkpJzj oaEdPSEFuK8jvbxCozTXf62a4HN893O2Rd2XglpZOBXwpmu8LzBmrzTuIAF4U+kXYB 4iVsKeWJMK+NRjd53+8bHW9u8Hm2AtPdFp0Y+QfqxA657TK9h74ZcbNe+8FiGp0aR8 nBZfDgMKZ32bHEkbO7mOGbFzpOEX2pIUX25vbxbWtk20Sc7RW8mvSvtugUVbXylyBT NPOPQ1iW1yYqg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id D0B3569B0E; Fri, 13 Feb 2026 13:24:53 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id oopcGJ9JkgzR; Fri, 13 Feb 2026 13:24:53 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014288; bh=Lcj73yExCDuA3WuwUGXyWOA3FZV9flHJ6xx/ctB+bIw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XIAjLlM1j+zM5Eha84MjO0KMfJgIFyroA4Id/tgoP72q4orphXPwOLi+Z3a/BqYWT +PS0nP/aIneMCkMuTR5EI98PNd82wXg5NueP28w5+VkVNfy7AOgK1Fald3WVBTvE+X Ym7ycPaPC7N99mMroo2ZGL+xL9nSoMJrcVYIeZz9GZw8wVkbLDGmTh3E5ms2fYcYdZ BlW9PQh+Xgw+AfSWo8rxmEbTxWkW9KKvyD+RfKNvpC8nL5tvDc8VIvNQt3eO/FfKlC xRGew+wshworXyg5vB1ePRGL6IisWkeK/Zi3V0xnoC93jQzpGjmBTaF4oho8E/tCn6 eBqDX+iI6bj1w== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id A66AF69B3D; Fri, 13 Feb 2026 13:24:47 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Fri, 13 Feb 2026 13:24:09 -0700 Message-ID: <20260213202417.223068-5-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260213202417.223068-1-sjg@u-boot.org> References: <20260213202417.223068-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: LALIOZR3XBMP2ZEPB3QKFIFHKS42HUNB X-Message-ID-Hash: LALIOZR3XBMP2ZEPB3QKFIFHKS42HUNB X-MailFrom: sjg@u-boot.org 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 CC: Simon Glass , "Claude Sonnet 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 4/8] boot: Add BLS Type #1 bootmethod List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add a bootmethod for Boot Loader Specification (BLS) Type #1 entries, enabling U-Boot to discover and boot from BLS configuration files. The bootmethod looks for a single BLS entry file at loader/entry.conf on each bootdev partition. When found, it parses the entry using the BLS parser and creates a bootflow that can be booted or displayed in menus. Implementation details: - Searches for loader/entry.conf with standard bootdev prefix support - Parses the BLS entry and registers discovered images (kernel, initrd, FDT) - Converts the BLS entry to a PXE label for boot execution - Reuses the existing PXE infrastructure for file loading and boot - Supports FITs with #config syntax in the linux field - Handles multiple initrd lines (uses the first due to a PXE limitation) - Skips reloading files if already loaded (an optimisation) Current limitations: - Single entry file only (not multiple entries in loader/entries/) - Only first initrd used (PXE infrastructure limitation) - No devicetree-overlay support - No architecture/machine-id filtering - No version-based sorting - No UKI/EFI support (Type #2) The bootmethod integrates with the standard bootflow framework and appears in bootflow menus alongside extlinux and EFI entries. Documentation is provided in doc/usage/bls.rst covering the BLS format, supported features, and current limitations. Co-developed-by: Claude Sonnet 4.5 Signed-off-by: Simon Glass --- boot/Makefile | 2 +- boot/bootflow.c | 1 + boot/bootmeth_bls.c | 438 ++++++++++++++++++++++++++++++++++++++++++++ doc/usage/bls.rst | 128 +++++++++++++ doc/usage/index.rst | 1 + include/bootflow.h | 2 + 6 files changed, 571 insertions(+), 1 deletion(-) create mode 100644 boot/bootmeth_bls.c create mode 100644 doc/usage/bls.rst diff --git a/boot/Makefile b/boot/Makefile index 1e75f7ece79..7cb28e52e50 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -29,7 +29,7 @@ obj-$(CONFIG_$(PHASE_)BOOTSTD_PROG) += prog_boot.o obj-$(CONFIG_$(PHASE_)BOOTMETH_EXTLINUX) += ext_pxe_common.o bootmeth_extlinux.o obj-$(CONFIG_$(PHASE_)BOOTMETH_EXTLINUX_PXE) += ext_pxe_common.o bootmeth_pxe.o -obj-$(CONFIG_$(PHASE_)BOOTMETH_BLS) += bls_parse.o +obj-$(CONFIG_$(PHASE_)BOOTMETH_BLS) += bls_parse.o bootmeth_bls.o obj-$(CONFIG_$(PHASE_)BOOTMETH_EFI) += bootmeth_efi.o obj-$(CONFIG_$(PHASE_)BOOTMETH_CROS) += bootmeth_cros.o obj-$(CONFIG_$(PHASE_)BOOTMETH_FEL) += bootmeth_fel.o diff --git a/boot/bootflow.c b/boot/bootflow.c index 0c389f78a28..0925c879e3d 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -30,6 +30,7 @@ enum { static const char *const bootflow_img[BFI_COUNT - BFI_FIRST] = { "extlinux_cfg", + "bls_cfg", "logo", "efi", "cmdline", diff --git a/boot/bootmeth_bls.c b/boot/bootmeth_bls.c new file mode 100644 index 00000000000..c9a2afbb6f3 --- /dev/null +++ b/boot/bootmeth_bls.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Bootmethod for Boot Loader Specification (BLS) Type #1 + * + * Copyright 2026 Canonical Ltd + * Written by Simon Glass + * + * This implements support for BLS Type #1 entries as defined in: + * https://uapi-group.org/specifications/specs/boot_loader_specification/ + * + * Supported features: + * - Single BLS entry file at loader/entry.conf + * - Fields: title, version, linux, options, initrd, devicetree + * - Multiple options lines (concatenated with spaces) + * - Multiple initrd lines (only first used, PXE limitation) + * - FITs with #config syntax in linux field + * - Zero-copy parsing (fields point into bootflow buffer) + * + * Current limitations: + * - Single entry file only, not multiple entries in loader/entries/ + * - Only first initrd used (PXE infrastructure supports one) + * - No devicetree-overlay support + * - No architecture/machine-id filtering + * - No version-based sorting + * - No UKI/EFI support (Type #2) + */ + +#define LOG_CATEGORY UCLASS_BOOTSTD + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Single BLS entry file to check */ +#define BLS_ENTRY_FILE "loader/entry.conf" + +/** + * struct bls_info - context information for BLS getfile callback + * + * @dev: Bootmethod device being used to boot + * @bflow: Bootflow being booted + */ +struct bls_info { + struct udevice *dev; + struct bootflow *bflow; +}; + +static int bls_get_state_desc(struct udevice *dev, char *buf, int maxsize) +{ + if (IS_ENABLED(CONFIG_SANDBOX)) { + int len; + + len = snprintf(buf, maxsize, "OK"); + + return len + 1 < maxsize ? 0 : -ENOSPC; + } + + return 0; +} + +static int bls_getfile(struct pxe_context *ctx, const char *file_path, + ulong *addrp, ulong align, enum bootflow_img_t type, + ulong *sizep) +{ + struct bls_info *info = ctx->userdata; + int ret; + + /* Allow up to 1GB */ + *sizep = 1 << 30; + ret = bootmeth_read_file(info->dev, info->bflow, file_path, addrp, + align, type, sizep); + if (ret) + return log_msg_ret("read", ret); + + return 0; +} + +static int bls_check(struct udevice *dev, struct bootflow_iter *iter) +{ + int ret; + + /* This only works on block devices */ + ret = bootflow_iter_check_blk(iter); + if (ret) + return log_msg_ret("blk", ret); + + return 0; +} + +/** + * bls_to_pxe_label() - Convert bootflow to PXE label for boot execution + * + * @bflow: Bootflow containing BLS entry and discovered images + * @labelp: Returns allocated PXE label structure + * Return: 0 on success, -ENOMEM if out of memory + */ +static int bls_to_pxe_label(struct bootflow *bflow, + struct pxe_label **labelp) +{ + struct pxe_label *label; + struct bootflow_img *img; + int ret; + + label = calloc(1, sizeof(*label)); + if (!label) + return log_msg_ret("alloc", -ENOMEM); + + INIT_LIST_HEAD(&label->list); + alist_init_struct(&label->files, struct pxe_file); + + label->menu = strdup(bflow->os_name ?: ""); + label->append = strdup(bflow->cmdline ?: ""); + if (!label->menu || !label->append) { + ret = -ENOMEM; + goto err; + } + + /* Extract kernel, initrd and FDT from the bootflow images */ + alist_for_each(img, &bflow->images) { + char **fieldp; + + if (img->type == (enum bootflow_img_t)IH_TYPE_KERNEL) + fieldp = &label->kernel; + else if (img->type == (enum bootflow_img_t)IH_TYPE_RAMDISK) + fieldp = &label->initrd; + else if (img->type == (enum bootflow_img_t)IH_TYPE_FLATDT) + fieldp = &label->fdt; + else + continue; + + if (!*fieldp) { + *fieldp = strdup(img->fname); + if (!*fieldp) { + ret = -ENOMEM; + goto err; + } + } + } + + *labelp = label; + return 0; + +err: + label_destroy(label); + return ret; +} + +/** + * bls_entry_init() - Parse entry and register images with bootflow + * + * @entry: Entry structure to initialize + * @bflow: Bootflow to populate + * @size: Size of BLS entry file in bflow->buf + * Return: 0 on success, -ve on error + */ +static int bls_entry_init(struct bls_entry *entry, struct bootflow *bflow, + loff_t size) +{ + char **initrd; + int ret; + + /* Parse BLS entry (fields point into bflow->buf) */ + ret = bls_parse_entry(bflow->buf, size, entry); + if (ret) + return log_msg_ret("parse", ret); + + /* Save title as os_name */ + if (entry->title) { + bflow->os_name = strdup(entry->title); + if (!bflow->os_name) + return log_msg_ret("name", -ENOMEM); + } + + /* Transfer cmdline ownership to bflow */ + if (entry->options) { + bflow->cmdline = entry->options; + entry->options = NULL; + } + + /* Register discovered images (not yet loaded, addr=0) */ + if (entry->kernel) { + if (!bootflow_img_add(bflow, entry->kernel, + (enum bootflow_img_t)IH_TYPE_KERNEL, + 0, 0)) + return log_msg_ret("imk", -ENOMEM); + } + + alist_for_each(initrd, &entry->initrds) { + if (!bootflow_img_add(bflow, *initrd, + (enum bootflow_img_t)IH_TYPE_RAMDISK, + 0, 0)) + return log_msg_ret("imi", -ENOMEM); + } + + if (entry->devicetree) { + if (!bootflow_img_add(bflow, entry->devicetree, + (enum bootflow_img_t)IH_TYPE_FLATDT, + 0, 0)) + return log_msg_ret("imf", -ENOMEM); + } + + return 0; +} + +static int bls_read_bootflow(struct udevice *dev, struct bootflow *bflow) +{ + struct bls_entry entry; + struct blk_desc *desc; + const char *const *prefixes; + struct udevice *bootstd; + const char *prefix; + loff_t size; + int ret, i; + + log_debug("BLS: starting part %d\n", bflow->part); + + /* Get bootstd device for prefixes */ + ret = uclass_first_device_err(UCLASS_BOOTSTD, &bootstd); + if (ret) { + log_debug("no bootstd\n"); + return log_msg_ret("std", ret); + } + + /* Block devices require a partition table */ + if (bflow->blk && !bflow->part) { + log_debug("no partition table\n"); + return -ENOENT; + } + + prefixes = bootstd_get_prefixes(bootstd); + desc = bflow->blk ? dev_get_uclass_plat(bflow->blk) : NULL; + + /* Try each prefix to find the BLS entry file */ + i = 0; + do { + prefix = prefixes ? prefixes[i] : NULL; + log_debug("trying prefix %s\n", prefix); + + ret = bootmeth_try_file(bflow, desc, prefix, BLS_ENTRY_FILE); + } while (ret && prefixes && prefixes[++i]); + + if (ret) { + log_debug("no BLS entry file found\n"); + return log_msg_ret("try", ret); + } + + size = bflow->size; + + /* Read the file */ + ret = bootmeth_alloc_file(bflow, 0x10000, ARCH_DMA_MINALIGN, + BFI_BLS_CFG); + if (ret) + return log_msg_ret("read", ret); + + ret = bls_entry_init(&entry, bflow, size); + bls_entry_uninit(&entry); + + return ret; +} + +/** + * bls_load_files() - Load files using an existing label + * + * @dev: Bootmethod device + * @bflow: Bootflow to load files for + * @pxe_ctx: Returns initialized PXE context (caller must destroy) + * @label: PXE label to use for loading + * Return: 0 on success, -ve on error + */ +static int bls_load_files(struct udevice *dev, struct bootflow *bflow, + struct pxe_context *pxe_ctx, + struct pxe_label *label) +{ + const struct bootflow_img *first_img; + struct bls_info info; + struct pxe_file *file; + bool already_loaded; + int ret; + + /* Check if files are already loaded (first image has address) */ + first_img = alist_get(&bflow->images, 0, struct bootflow_img); + already_loaded = first_img && first_img->addr; + + /* Set up PXE context */ + info.dev = dev; + info.bflow = bflow; + ret = pxe_setup_ctx(pxe_ctx, bls_getfile, &info, true, bflow->fname, + false, false, bflow); + if (ret) + return log_msg_ret("ctx", ret); + + if (!already_loaded) { + /* Load files (kernel, initrd, FDT) */ + ret = pxe_load_files(pxe_ctx, label, NULL); + if (ret) { + pxe_destroy_ctx(pxe_ctx); + return log_msg_ret("load", ret); + } + + /* Update loaded images with their addresses */ + alist_for_each(file, &label->files) { + struct bootflow_img *img; + + /* Find the corresponding image in bootflow */ + alist_for_each(img, &bflow->images) { + if (!strcmp(img->fname, file->path)) { + img->addr = file->addr; + img->size = file->size; + break; + } + } + } + } + + /* Process FDT (apply overlays, etc.) */ + ret = pxe_setup_label(pxe_ctx, label); + if (ret) { + pxe_destroy_ctx(pxe_ctx); + return log_msg_ret("setup", ret); + } + + return 0; +} + +/** + * bls_load_all() - Load all files needed for boot + * + * @dev: Bootmethod device + * @bflow: Bootflow to load files for + * @pxe_ctx: Returns initialized PXE context (caller must destroy) + * @labelp: Returns PXE label (caller must destroy) + * Return: 0 on success, -ve on error + */ +static int bls_load_all(struct udevice *dev, struct bootflow *bflow, + struct pxe_context *pxe_ctx, + struct pxe_label **labelp) +{ + struct pxe_label *label; + int ret; + + /* Convert bootflow to PXE label for boot execution */ + ret = bls_to_pxe_label(bflow, &label); + if (ret) + return log_msg_ret("label", ret); + + ret = bls_load_files(dev, bflow, pxe_ctx, label); + if (ret) { + label_destroy(label); + return ret; + } + + *labelp = label; + + return 0; +} + +static int __maybe_unused bls_read_all(struct udevice *dev, + struct bootflow *bflow) +{ + struct pxe_context pxe_ctx; + struct pxe_label *label; + int ret; + + ret = bls_load_all(dev, bflow, &pxe_ctx, &label); + if (ret) + return ret; + + pxe_destroy_ctx(&pxe_ctx); + label_destroy(label); + + return 0; +} + +static int bls_boot(struct udevice *dev, struct bootflow *bflow) +{ + struct pxe_context pxe_ctx; + struct pxe_label *label; + int ret; + + ret = bls_load_all(dev, bflow, &pxe_ctx, &label); + if (ret) + return ret; + + /* Boot the label */ + pxe_ctx.label = label; + ret = pxe_boot(&pxe_ctx); + + /* Cleanup */ + pxe_destroy_ctx(&pxe_ctx); + label_destroy(label); + + return log_msg_ret("boot", ret); +} + +static int bls_bootmeth_bind(struct udevice *dev) +{ + struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); + + plat->desc = IS_ENABLED(CONFIG_BOOTSTD_FULL) ? + "Boot Loader Specification (BLS) Type #1" : "bls"; + + return 0; +} + +static struct bootmeth_ops bls_bootmeth_ops = { + .get_state_desc = bls_get_state_desc, + .check = bls_check, + .read_bootflow = bls_read_bootflow, + .read_file = bootmeth_common_read_file, +#if CONFIG_IS_ENABLED(BOOTSTD_FULL) + .read_all = bls_read_all, +#endif + .boot = bls_boot, +}; + +static const struct udevice_id bls_bootmeth_ids[] = { + { .compatible = "u-boot,boot-loader-specification" }, + { } +}; + +/* Put a number before 'bls' to provide a default ordering */ +U_BOOT_DRIVER(bootmeth_2bls) = { + .name = "bootmeth_bls", + .id = UCLASS_BOOTMETH, + .of_match = bls_bootmeth_ids, + .ops = &bls_bootmeth_ops, + .bind = bls_bootmeth_bind, +}; diff --git a/doc/usage/bls.rst b/doc/usage/bls.rst new file mode 100644 index 00000000000..5f5f0efb8a4 --- /dev/null +++ b/doc/usage/bls.rst @@ -0,0 +1,128 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +Boot Loader Specification (BLS) Type #1 Support +================================================ + +U-Boot supports Boot Loader Specification (BLS) Type #1 boot entries as defined +in the `Boot Loader Specification`_. + +.. _Boot Loader Specification: https://uapi-group.org/specifications/specs/boot_loader_specification/ + +Overview +-------- + +BLS provides a standardised way to describe boot entries. U-Boot's BLS support +allows it to boot operating systems configured with BLS entries, which is used +by Fedora, RHEL, and other distributions. + +The current implementation supports a single BLS entry file at +``loader/entry.conf``. Future versions may support multiple entries in +``loader/entries/``. + +Configuration +------------- + +Enable BLS support with:: + + CONFIG_BOOTMETH_BLS=y + +This automatically selects ``CONFIG_PXE_UTILS`` for boot execution. + +BLS Entry Format +---------------- + +BLS entries use a simple key-value format, one field per line. Lines starting +with ``#`` are comments. Example:: + + title Fedora Linux 39 + version 6.7.0-1.fc39.x86_64 + options root=/dev/sda3 ro quiet + linux /vmlinuz-6.7.0-1.fc39.x86_64 + initrd /initramfs-6.7.0-1.fc39.x86_64.img + devicetree /dtbs/6.7.0-1.fc39.x86_64/board.dtb + +Supported Fields +---------------- + +**Required (at least one):** + +* ``linux`` - Path to Linux kernel image (Type #1); supports FITs with + ``path#config`` syntax + +**Optional:** + +* ``title`` - Human-readable menu display name +* ``version`` - OS version identifier (parsed but not used for sorting) +* ``options`` - Kernel command line parameters (may appear multiple times; all + occurrences are concatenated) +* ``initrd`` - Initial ramdisk path (may appear multiple times, but only first + is used due to PXE limitation) +* ``devicetree`` - Device tree blob path +* ``devicetree-overlay`` - Device tree overlays (parsed but not yet supported) +* ``architecture`` - Target architecture (parsed but not used for filtering) +* ``machine-id`` - OS identifier (parsed but not used for filtering) +* ``sort-key`` - Primary sorting key (parsed but not used for sorting) + +**Not supported (out of scope for Type #1):** + +* ``efi`` - EFI program path (Type #2/UKI) +* ``uki`` - Unified Kernel Image path +* ``uki-url`` - Remote UKI reference +* ``profile`` - Multi-profile UKI selector + +FIT Support +----------- + +U-Boot's BLS implementation works seamlessly with FITs using the standard +``path#config`` syntax in the ``linux`` field:: + + linux /boot/image.fit#config-1 + +The PXE boot infrastructure handles FIT parsing automatically. + +Multiple Values +--------------- + +Fields that support multiple occurrences: + +* ``options`` - All values are concatenated with spaces +* ``initrd`` - Multiple paths can be specified, but only the first is used + (limitation of PXE boot infrastructure) + +Usage +----- + +BLS boot entries are discovered automatically during standard boot:: + + => bootflow scan + => bootflow list + => bootflow select 0 + => bootflow boot + +The BLS entry at ``loader/entry.conf`` is discovered as a bootflow. + +Implementation Notes +-------------------- + +* Single BLS entry file support (``loader/entry.conf``) +* Boot execution reuses U-Boot's PXE infrastructure for kernel loading +* Unknown fields are ignored for forward compatibility +* The bootmethod is ordered as ``bootmeth_2bls`` (after extlinux) +* Zero-copy parsing: most fields point into bootflow buffer (except ``options`` + which is allocated for concatenation) + +Current Limitations +------------------- + +* Only single entry file, not multiple entries directory scanning +* Only first initrd used (PXE infrastructure limitation) +* No devicetree-overlay support +* No architecture/machine-id filtering +* No version-based or sort-key sorting +* No UKI/Type #2 support + +See Also +-------- + +* doc/develop/bootstd.rst - Standard boot framework +* doc/usage/cmd/bootflow.rst - Bootflow command reference diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 1e0ffacebaf..4e2089389f0 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -6,6 +6,7 @@ Use U-Boot spl_boot blkmap + bls console dfu environment diff --git a/include/bootflow.h b/include/bootflow.h index be94fba80d3..6c6f07db97d 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -135,6 +135,7 @@ struct bootflow { * bootflow_img[] * * @BFI_EXTLINUX_CFG: extlinux configuration-file + * @BFI_BLS_CFG: Boot Loader Specification (BLS) configuration-file * @BFI_LOGO: logo image * @BFI_EFI: EFI PE image * @BFI_CMDLINE: OS command-line string @@ -145,6 +146,7 @@ struct bootflow { enum bootflow_img_t { BFI_FIRST = IH_TYPE_COUNT, BFI_EXTLINUX_CFG = BFI_FIRST, + BFI_BLS_CFG, BFI_LOGO, BFI_EFI, BFI_CMDLINE, From patchwork Fri Feb 13 20:24:10 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1852 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014300; bh=aVrtMblhkPnvaJ2MMyWIlresXOsy8vBZ3rRa/umWgoM=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=elKus2f3168DppKdKUfAgoANZBZfmrNvDZCtu2aRvll0L0zA1FETo4N+fO4VvHw86 nhu676FUw4p9VGX2aHTM1tL0fHCTPYLj/AeWplYe/r7G6UUBu0t/sDcerk3a3RelWl aMZU0vrh0MrRsl0h8jdLeliM20/Mn6+llRTg19gWCt2fANphj/9E4xouDqf41+dwz2 Ff2tRp0GBOlqj4P7FsOwOdP8qtsU3OZIynCuFD2bDNhakgM0bACKwtLyEj7JpfiaQQ xptpXKmcpsYrN9JV89PdjO4ARUj6/2s3o+NHHC8tqPk90DZK1U5A7bBx/8iOChEFp9 PAeaN7/gbl9Hg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 14F9769A66 for ; Fri, 13 Feb 2026 13:25:00 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 1MLetGhATRvh for ; Fri, 13 Feb 2026 13:25:00 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014300; bh=aVrtMblhkPnvaJ2MMyWIlresXOsy8vBZ3rRa/umWgoM=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=elKus2f3168DppKdKUfAgoANZBZfmrNvDZCtu2aRvll0L0zA1FETo4N+fO4VvHw86 nhu676FUw4p9VGX2aHTM1tL0fHCTPYLj/AeWplYe/r7G6UUBu0t/sDcerk3a3RelWl aMZU0vrh0MrRsl0h8jdLeliM20/Mn6+llRTg19gWCt2fANphj/9E4xouDqf41+dwz2 Ff2tRp0GBOlqj4P7FsOwOdP8qtsU3OZIynCuFD2bDNhakgM0bACKwtLyEj7JpfiaQQ xptpXKmcpsYrN9JV89PdjO4ARUj6/2s3o+NHHC8tqPk90DZK1U5A7bBx/8iOChEFp9 PAeaN7/gbl9Hg== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 001DE69B2D for ; Fri, 13 Feb 2026 13:24:59 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014297; bh=kjJE+RrnjWHJpzfku4UsfGsrjeOwkNUme1bPehRexRo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vaYZecXNDe3re1U7I4F1Y09SK581W2hz/ypucdLspJPH2H7SbWYUwPdLhYhv7Uizh 3pDwrHjtQOCwCmi/dSN+zNmQGo/ol7NebRHkVUAD8qJ0FeNosqDax9p2F+o17CHAM4 N1B1WcuYsIZmqsonngA8WYZaW5ewaGNnNZaRB4B50qlGxO8fk7xRpiQAEQtqdmzxIR 1Wc+iHyhCgEuH+XiEa+mR1IBMZHQ5koS7mE6u/3ZgGwblkB5sXX6k+IhwP0WZUGNFi 65Sn7rPmbW4SDA00C0j3rvHX42zto+Y2Iub6DjBKuqstsnGKtNGQ4tbKCMekCPK49x NT1UVrNHbj6sg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id DB79B69B2D; Fri, 13 Feb 2026 13:24:57 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id UzJzddghFbyR; Fri, 13 Feb 2026 13:24:57 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014292; bh=sf8+GliADNEFARWgxc27ONZ8SIPAmYwcIgG2w5QF5E0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pd0OyOYm9WNA3VTU3p+sQzggcw0ji4P39+zTRL6oVAzZCGh6BppZI7NYZSfUoLaTh H5knsiiHiv12EkwdBYrBisXpLyrkNDKa4ujxESDc4zWwy5mnVzTRBdlAeU9Wft21Kg UNSQ4SUtIVa5ngVaejywk4uHz+0iHwIbd3YpR5AE8MGQ8aGiYS/LuO98OnUuxn1w7Y BJuKz2ARbcENYnBEi7yguVz38U6bnKcHMyweLJ60htDSV1l8Mhuo6fWWmS/oP2ysAW hRE5QACgHdAhX+6aOANvPA4TCW5sDTNMLP/V3XgNSbQ0KYY7nU4zc395lgTXXW4iM+ iHT95P5UlEr5Q== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 903E569A66; Fri, 13 Feb 2026 13:24:52 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Fri, 13 Feb 2026 13:24:10 -0700 Message-ID: <20260213202417.223068-6-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260213202417.223068-1-sjg@u-boot.org> References: <20260213202417.223068-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: PBSEUYLXZ66WXYZX73ZKDU7CHBTBQTFS X-Message-ID-Hash: PBSEUYLXZ66WXYZX73ZKDU7CHBTBQTFS X-MailFrom: sjg@u-boot.org 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 CC: Simon Glass , "Claude Sonnet 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 5/8] test: Add bootflow test for BLS bootmethod List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add a test that verifies the BLS bootmethod can discover and boot from a Boot Loader Specification entry file. The test creates a disk image (mmc15) with a BLS entry at loader/entry.conf and verifies that bootflow scan finds it and reports it correctly. Test coverage: - Disk image creation with BLS entry format - Bootflow discovery via 'bootflow scan' - Bootflow listing and info display - Integration with standard bootdev framework The disk image setup creates a minimal BLS Type #1 entry with kernel, initrd, devicetree, and boot options. Co-developed-by: Claude Sonnet 4.5 Signed-off-by: Simon Glass --- arch/sandbox/dts/test.dts | 7 ++++ test/boot/bootflow.c | 54 ++++++++++++++++++++++++++++++ test/py/img/bls.py | 70 +++++++++++++++++++++++++++++++++++++++ test/py/tests/test_ut.py | 2 ++ 4 files changed, 133 insertions(+) create mode 100644 test/py/img/bls.py diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 33c25014e94..90167567757 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -1296,6 +1296,13 @@ filename = "mmc14.img"; }; + /* This is used for BLS tests */ + mmc15 { + status = "disabled"; + compatible = "sandbox,mmc"; + filename = "mmc15.img"; + }; + pch { compatible = "sandbox,pch"; }; diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 9a9cc68fa11..e1e50319740 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -36,6 +36,7 @@ DECLARE_GLOBAL_DATA_PTR; extern U_BOOT_DRIVER(bootmeth_android); extern U_BOOT_DRIVER(bootmeth_cros); extern U_BOOT_DRIVER(bootmeth_2script); +extern U_BOOT_DRIVER(bootmeth_2bls); /* Use this as the vendor for EFI to tell the app to exit boot services */ static u16 __efi_runtime_data test_vendor[] = u"U-Boot testing"; @@ -684,6 +685,13 @@ static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev, "android", 0, ofnode_null(), &dev)); } + /* Enable the BLS bootmeth if needed */ + if (IS_ENABLED(CONFIG_BOOTMETH_BLS) && bind_cros_android) { + ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); + ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_2bls), + "bls", 0, ofnode_null(), &dev)); + } + /* Change the order to include the device */ std = dev_get_priv(bootstd); old_order = std->bootdev_order; @@ -1809,3 +1817,49 @@ static int bootflow_cmd_info_encrypted(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootflow_cmd_info_encrypted, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE); + +/* Check 'bootflow scan' finds a BLS bootflow */ +static int bootflow_cmd_bls(struct unit_test_state *uts) +{ + struct bootstd_priv *std; + const char **old_order; + + ut_assertok(prep_mmc_bootdev(uts, "mmc15", true, &old_order)); + ut_assertok(run_command("bootflow scan", 0)); + ut_assert_console_end(); + + /* Restore the order used by the device tree */ + ut_assertok(bootstd_get_priv(&std)); + free(std->bootdev_order); + std->bootdev_order = old_order; + + ut_assertok(run_command("bootflow list", 0)); + ut_assert_nextline("Showing all bootflows"); + ut_assert_nextline("Seq Method State Uclass Part E Name Filename"); + ut_assert_nextlinen("---"); + ut_assert_nextlinen(" 0 extlinux"); + ut_assert_nextline(" 1 bls ready mmc 1 mmc15.bootdev.part_1 /loader/entry.conf"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(2 bootflows, 2 valid)"); + ut_assert_console_end(); + + /* Select the BLS bootflow and check info */ + ut_assertok(run_command("bootflow select 1", 0)); + ut_assert_console_end(); + ut_assertok(run_command("bootflow info", 0)); + ut_assert_nextline("Name: mmc15.bootdev.part_1"); + ut_assert_nextline("Device: mmc15.bootdev"); + ut_assert_nextline("Block dev: mmc15.blk"); + ut_assert_nextline("Method: bls"); + ut_assert_nextline("State: ready"); + ut_assert_nextline("Partition: 1"); + if (IS_ENABLED(CONFIG_BLK_LUKS)) + ut_assert_nextline("Encrypted: no"); + ut_assert_nextline("Subdir: (none)"); + ut_assert_nextline("Filename: /loader/entry.conf"); + ut_assert_skip_to_line("Error: 0"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_cmd_bls, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE); diff --git a/test/py/img/bls.py b/test/py/img/bls.py new file mode 100644 index 00000000000..0f55aad8ba5 --- /dev/null +++ b/test/py/img/bls.py @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2026 Canonical Ltd + +"""Create BLS test disk images""" + +import gzip +import os + +import utils +from fs_helper import DiskHelper, FsHelper +from img.common import mkdir_cond + + +def setup_bls_image(config, log, devnum, basename): + """Create a 20MB BLS disk image with a single FAT partition + + Args: + config (ArbitraryAttributeContainer): Configuration + log (multiplexed_log.Logfile): Log to write to + devnum (int): Device number to use, e.g. 5 + basename (str): Base name to use in the filename, e.g. 'mmc' + """ + vmlinux = 'vmlinuz-6.8.0' + initrd = 'initrd.img-6.8.0' + dtb = 'sandbox.dtb' + + # BLS Type #1 entry format + script = f'''title Test Boot +version 6.8.0 +linux /{vmlinux} +options root=/dev/mmcblk0p2 ro quiet +initrd /{initrd} +devicetree /{dtb}''' + + fsh = FsHelper(config, 'vfat', 18, prefix=basename) + fsh.setup() + + # Create loader directory for BLS entry + loader = os.path.join(fsh.srcdir, 'loader') + mkdir_cond(loader) + + # Create BLS entry file + conf = os.path.join(loader, 'entry.conf') + with open(conf, 'w', encoding='ascii') as fd: + print(script, file=fd) + + # Create compressed kernel image + inf = os.path.join(config.persistent_data_dir, 'inf') + with open(inf, 'wb') as fd: + fd.write(gzip.compress(b'vmlinux')) + mkimage = config.build_dir + '/tools/mkimage' + utils.run_and_log_no_ubman( + log, f'{mkimage} -f auto -d {inf} {os.path.join(fsh.srcdir, vmlinux)}') + + # Create initrd file + with open(os.path.join(fsh.srcdir, initrd), 'w', encoding='ascii') as fd: + print('initrd', file=fd) + + # Create device tree blob + dtb_file = os.path.join(fsh.srcdir, dtb) + utils.run_and_log_no_ubman( + log, f'dtc -o {dtb_file}', stdin=b'/dts-v1/; / {};') + + fsh.mk_fs() + + # Create disk image with single bootable partition + img = DiskHelper(config, devnum, basename) + img.add_fs(fsh, DiskHelper.VFAT, bootable=True) + img.create() + fsh.cleanup() diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index da36898d803..e64ccd407a0 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -23,6 +23,7 @@ from img.common import mkdir_cond, copy_partition, setup_extlinux_image from img.fedora import setup_fedora_image from img.ubuntu import setup_ubuntu_image from img.armbian import setup_bootmenu_image +from img.bls import setup_bls_image from img.chromeos import setup_cros_image from img.android import setup_android_image from img.efi import setup_efi_image @@ -79,6 +80,7 @@ def test_ut_dm_init_bootstd(u_boot_config, u_boot_log): u_boot_log (multiplexed_log.Logfile): Log to write to """ setup_fedora_image(u_boot_config, u_boot_log, 1, 'mmc') + setup_bls_image(u_boot_config, u_boot_log, 15, 'mmc') setup_bootmenu_image(u_boot_config, u_boot_log) setup_cedit_file(u_boot_config, u_boot_log) setup_cros_image(u_boot_config, u_boot_log) From patchwork Fri Feb 13 20:24:11 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1853 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014304; bh=IFZtM8hWItHBvY/dxi8jmj+I2C1Md2V/x9pkL6rTK0E=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=AJ7Xos9BPq8DTGp+iZ1lgTCKNrVs33yX3yiK554nsslbdmzvxXuC7XV9/RMe/03iS xTe6JwW5q7CvTrMiMA9N5anLL56zPoHVWObKwBitzgoe5rsNdqBECb8jkLlowbEzI0 3AKQoZr2auAuFhpMF2Jt7B664Ts+V01ng5mUGVGg61ZAudbulQ8XZgghKg1cSFQxS4 FmY9STSHUmR/EfFDxotLdjXRdbF9YIbsNCwQO87h+54Cs3Ypb3yre7QaqUEyTOtXZu GFiZsWjEh5x/QUb3642nSJFM79Rxt47d3XgsNXaCdbMmUp46Fc/QpdMB4ZoLKE2VTc STR35bL6o+kmA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id D93EB69B0E for ; Fri, 13 Feb 2026 13:25:04 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id PQ5QGQb1sj_W for ; Fri, 13 Feb 2026 13:25:04 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014304; bh=IFZtM8hWItHBvY/dxi8jmj+I2C1Md2V/x9pkL6rTK0E=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=AJ7Xos9BPq8DTGp+iZ1lgTCKNrVs33yX3yiK554nsslbdmzvxXuC7XV9/RMe/03iS xTe6JwW5q7CvTrMiMA9N5anLL56zPoHVWObKwBitzgoe5rsNdqBECb8jkLlowbEzI0 3AKQoZr2auAuFhpMF2Jt7B664Ts+V01ng5mUGVGg61ZAudbulQ8XZgghKg1cSFQxS4 FmY9STSHUmR/EfFDxotLdjXRdbF9YIbsNCwQO87h+54Cs3Ypb3yre7QaqUEyTOtXZu GFiZsWjEh5x/QUb3642nSJFM79Rxt47d3XgsNXaCdbMmUp46Fc/QpdMB4ZoLKE2VTc STR35bL6o+kmA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C857869B34 for ; Fri, 13 Feb 2026 13:25:04 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014302; bh=HBmlg9nYlSImZJHOcFZTFYBv6usS2FtAbWaYgzdizE4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VnuPnqeg2C4YTbibVl7ZQyiBS5izOQtO6aykyXXqM5MDlXDFqMsC4DATiAF38tB6s mxwYLwSUyKCD4kffKNTVz26WyoNTh4vu00E9qRSAle/hZU6L3y5gjn+QxJjqzeIZEV jwMWLrqwdrvC7d1Uni79LwMGdP/fzt4wCgFK0xwzOu8V53LTshbfdScqtJ8KP82FWa loro3yWnqEBloUL+41harQZXcHsEvrTR2ue3HrQaGJSvR0PqAWS5d5pHIaMHdS0QFv VNxpoiGvT5lJHBo+xiXlU91m3wSQ8QmGtaxWpKIFki+4YZOM449pVXBs6fiIQgDYXu 5KG30mOuzn5eA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id D279469B34; Fri, 13 Feb 2026 13:25:02 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id a2_0PtcFH8vc; Fri, 13 Feb 2026 13:25:02 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014297; bh=Hi2PEoCvHoFYww0NROai8qKYxD6X8HfPBtZaXBUF2rE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ci+iKwfaJmWbyogdarrrCEF3txKlCRImINgxLj99g6C83eJ9TsbJobxv0UZVetsxh S2oz5KbTOfwov5a6tsgXb7bx8hInl9wxcm0l/Z4H66JmSULEzx7b3QAQtnBymDGRa3 Bccxoeee4o5kFq/WKI4NolICk0aCBqOHYTlcGuL1mDKSqc9C+Ym/WV00GhDOxEEmHk 96eATA5CZJ8OhKNapI2pDa6ls73c8rYYBSAq7gB8yGjmFR48F/gSp0jMuZGfoNZj7G 3d3JSTbo8L4BlFrlJ4le3YH8I+bZ2YxQFlHMeMUPj1rBXNQNgDIfgKX0wPgtGxAMv+ YDjk8JAxlBL0w== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id F00F469B0E; Fri, 13 Feb 2026 13:24:56 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Fri, 13 Feb 2026 13:24:11 -0700 Message-ID: <20260213202417.223068-7-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260213202417.223068-1-sjg@u-boot.org> References: <20260213202417.223068-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: JKX2LHJOEXH5QS637FKNWJQ4DRAMIJFF X-Message-ID-Hash: JKX2LHJOEXH5QS637FKNWJQ4DRAMIJFF X-MailFrom: sjg@u-boot.org 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 CC: Simon Glass , "Claude Sonnet 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 6/8] pxe: Support multiple initrd files using alist List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Replace the single char *initrd field in struct pxe_label with an alist of initrd paths (struct alist initrds) to support multiple initrd files. This enhancement enables BLS (Boot Loader Specification) support for multiple initrd lines, which is a key feature of the BLS format. Changes made: - Replace char *initrd with struct alist initrds in pxe_label - Initialize initrds alist in label_create() - Free initrds alist entries in label_destroy() - Update PXE parser to append multiple INITRD directives to the alist - Update pxe_load_files() to load all initrds consecutively in memory - Update BLS bootmeth to add all ramdisk images to initrds alist - Update tests to check initrds.count instead of checking initrd pointer The PXE file loading code now: - Loads each initrd file consecutively starting at ramdisk_addr_r - Tracks the total size of all initrds for bootm - Handles FIT images where initrd path matches kernel (shares address) This maintains backwards compatibility with existing single-initrd PXE files while enabling multi-initrd support for BLS and future use cases. Co-developed-by: Claude Sonnet 4.5 Signed-off-by: Simon Glass --- boot/Kconfig | 17 +++++++ boot/bootmeth_bls.c | 44 +++++++++++------ boot/pxe_parse.c | 64 ++++++++++++++++++++----- boot/pxe_utils.c | 114 ++++++++++++++++++++++++++++++++++++++------ include/pxe_utils.h | 5 +- test/boot/pxe.c | 12 +++-- 6 files changed, 209 insertions(+), 47 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index 63a0cf0bd7a..cff58795bc1 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -469,6 +469,22 @@ config PXE_UTILS help Utilities for parsing PXE file formats. +config PXE_INITRD_LIST + bool "Support multiple initrd files in PXE/extlinux" + depends on PXE_UTILS + help + Enable support for multiple initrd files in PXE/extlinux + configurations. This allows loading multiple initrd images + consecutively in memory, as required by Boot Loader Specification + (BLS) Type #1 entries. + + When enabled, the PXE parser can handle multiple 'initrd' lines + and load all specified initrd files. When disabled, only a single + initrd is supported, reducing code size. + + Say Y if you need BLS support or multiple initrds. Say N to save + code space if you only use single initrd configurations. + config BOOT_DEFAULTS_FEATURES bool select SUPPORT_RAW_INITRD @@ -693,6 +709,7 @@ config BOOTMETH_EXTLINUX_LOCALBOOT config BOOTMETH_BLS bool "Bootdev support for Boot Loader Specification (BLS) Type #1" select PXE_UTILS + select PXE_INITRD_LIST default y if SANDBOX help Enables support for Boot Loader Specification (BLS) Type #1 entries. diff --git a/boot/bootmeth_bls.c b/boot/bootmeth_bls.c index c9a2afbb6f3..2c66e14c641 100644 --- a/boot/bootmeth_bls.c +++ b/boot/bootmeth_bls.c @@ -125,25 +125,39 @@ static int bls_to_pxe_label(struct bootflow *bflow, goto err; } - /* Extract kernel, initrd and FDT from the bootflow images */ + /* Extract kernel, initrds and FDT from the bootflow images */ alist_for_each(img, &bflow->images) { - char **fieldp; - - if (img->type == (enum bootflow_img_t)IH_TYPE_KERNEL) - fieldp = &label->kernel; - else if (img->type == (enum bootflow_img_t)IH_TYPE_RAMDISK) - fieldp = &label->initrd; - else if (img->type == (enum bootflow_img_t)IH_TYPE_FLATDT) - fieldp = &label->fdt; - else - continue; - - if (!*fieldp) { - *fieldp = strdup(img->fname); - if (!*fieldp) { + char *fname; + + fname = strdup(img->fname); + if (!fname) { + ret = -ENOMEM; + goto err; + } + + switch ((int)img->type) { + case IH_TYPE_KERNEL: + if (!label->kernel) + label->kernel = fname; + else + free(fname); + break; + case IH_TYPE_RAMDISK: + if (!alist_add(&label->initrds, fname)) { + free(fname); ret = -ENOMEM; goto err; } + break; + case IH_TYPE_FLATDT: + if (!label->fdt) + label->fdt = fname; + else + free(fname); + break; + default: + free(fname); + break; } } diff --git a/boot/pxe_parse.c b/boot/pxe_parse.c index 42f9125cb1d..28f957cfa70 100644 --- a/boot/pxe_parse.c +++ b/boot/pxe_parse.c @@ -107,6 +107,8 @@ static struct pxe_label *label_create(void) return NULL; memset(label, 0, sizeof(struct pxe_label)); alist_init_struct(&label->files, struct pxe_file); + if (IS_ENABLED(CONFIG_PXE_INITRD_LIST)) + alist_init(&label->initrds, sizeof(char *), 4); return label; } @@ -121,7 +123,15 @@ void label_destroy(struct pxe_label *label) free(label->kernel); free(label->config); free(label->append); - free(label->initrd); + if (IS_ENABLED(CONFIG_PXE_INITRD_LIST)) { + const char **initrd; + + alist_for_each(initrd, &label->initrds) + free((void *)*initrd); + alist_uninit(&label->initrds); + } else { + free(label->initrd); + } free(label->fdt); free(label->fdtdir); alist_for_each(file, &label->files) @@ -579,6 +589,7 @@ static int parse_label(char **c, struct pxe_menu *cfg, const char *limit) struct token t; int len; char *s = *c; + char *initrd_path; struct pxe_label *label; int err; @@ -612,26 +623,57 @@ static int parse_label(char **c, struct pxe_menu *cfg, const char *limit) break; case T_APPEND: err = parse_sliteral(c, &label->append, limit); - if (label->initrd) - break; + if (IS_ENABLED(CONFIG_PXE_INITRD_LIST)) { + if (label->initrds.count) + break; + } else { + if (label->initrd) + break; + } s = strstr(label->append, "initrd="); if (!s) break; s += 7; len = (int)(strchr(s, ' ') - s); - label->initrd = malloc(len + 1); - strlcpy(label->initrd, s, len); - label->initrd[len] = '\0'; + initrd_path = malloc(len + 1); + if (!initrd_path) { + err = -ENOMEM; + break; + } + strlcpy(initrd_path, s, len + 1); + if (IS_ENABLED(CONFIG_PXE_INITRD_LIST)) { + if (!alist_add(&label->initrds, initrd_path)) { + free(initrd_path); + err = -ENOMEM; + break; + } + } else { + label->initrd = initrd_path; + } + err = label_add_file(label, initrd_path, PFT_INITRD); break; case T_INITRD: - if (!label->initrd) { - err = parse_sliteral(c, &label->initrd, limit); - if (err < 0) + if (IS_ENABLED(CONFIG_PXE_INITRD_LIST)) { + if (label->initrds.count) + break; + } else { + if (label->initrd) break; - err = label_add_file(label, label->initrd, - PFT_INITRD); } + err = parse_sliteral(c, &initrd_path, limit); + if (err < 0) + break; + if (IS_ENABLED(CONFIG_PXE_INITRD_LIST)) { + if (!alist_add(&label->initrds, initrd_path)) { + free(initrd_path); + err = -ENOMEM; + break; + } + } else { + label->initrd = initrd_path; + } + err = label_add_file(label, initrd_path, PFT_INITRD); break; case T_FDT: if (!label->fdt) { diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 5c1d08feebf..e5f1f3e46c2 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -622,11 +622,71 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label, */ static int generate_localboot(struct pxe_label *label) { + char *initrd_path; + label->kernel = strdup("/vmlinuz"); label->kernel_label = strdup(label->kernel); - label->initrd = strdup("/initrd.img"); - if (!label->kernel || !label->kernel_label || !label->initrd) + initrd_path = strdup("/initrd.img"); + if (!label->kernel || !label->kernel_label || !initrd_path) return -ENOMEM; + if (IS_ENABLED(CONFIG_PXE_INITRD_LIST)) { + if (!alist_add(&label->initrds, initrd_path)) { + free(initrd_path); + return -ENOMEM; + } + } else { + label->initrd = initrd_path; + } + + return 0; +} + +/** + * pxe_load_initrds() - Load all initrd files consecutively + * + * @ctx: PXE context + * @label: Label containing initrd file paths + * @initrd_addr: Starting address for first initrd + * @total_sizep: Returns total size of all initrds + * Return: 0 on success, -EIO on error + */ +static int pxe_load_initrds(struct pxe_context *ctx, struct pxe_label *label, + ulong initrd_addr, ulong *total_sizep) +{ + const char **initrd_path; + ulong total_size = 0; + int ret; + int i; + + /* Load each initrd consecutively */ + for (i = 0; i < label->initrds.count; i++) { + ulong size; + + initrd_path = alist_get(&label->initrds, i, char *); + /* Use ramdisk_addr_r for first, then append */ + if (i == 0) { + ret = get_relfile_envaddr(ctx, *initrd_path, + "ramdisk_addr_r", SZ_2M, + (enum bootflow_img_t)IH_TYPE_RAMDISK, + &initrd_addr, &size); + ctx->initrd_addr = initrd_addr; + } else { + /* Load subsequent initrds after the previous one */ + ulong addr = initrd_addr + total_size; + + ret = get_relfile_envaddr(ctx, *initrd_path, + NULL, SZ_2M, + (enum bootflow_img_t)IH_TYPE_RAMDISK, + &addr, &size); + } + if (ret < 0) { + printf("Skipping %s for failure retrieving initrd %s\n", + label->name, *initrd_path); + return -EIO; + } + total_size += size; + } + *total_sizep = total_size; return 0; } @@ -634,6 +694,9 @@ static int generate_localboot(struct pxe_label *label) int pxe_load_files(struct pxe_context *ctx, struct pxe_label *label, char *fdtfile) { + const char **initrd_path; + ulong initrd_addr = 0; + ulong total_size = 0; int ret; if (!label->kernel) { @@ -649,18 +712,38 @@ int pxe_load_files(struct pxe_context *ctx, struct pxe_label *label, return -EIO; } - /* For FIT, the label can be identical to kernel one */ - if (label->initrd && !strcmp(label->kernel_label, label->initrd)) { - ctx->initrd_addr = ctx->kern_addr; - } else if (label->initrd) { - ret = get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r", - SZ_2M, - (enum bootflow_img_t)IH_TYPE_RAMDISK, - &ctx->initrd_addr, &ctx->initrd_size); - if (ret < 0) { - printf("Skipping %s for failure retrieving initrd\n", - label->name); - return -EIO; + /* Load initrds if present */ + if (IS_ENABLED(CONFIG_PXE_INITRD_LIST)) { + if (label->initrds.count) { + /* For FIT, check if first initrd is identical to kernel */ + initrd_path = alist_get(&label->initrds, 0, char *); + if (!strcmp(label->kernel_label, *initrd_path)) { + ctx->initrd_addr = ctx->kern_addr; + ctx->initrd_size = ctx->kern_size; + } else { + ret = pxe_load_initrds(ctx, label, initrd_addr, + &total_size); + if (ret) + return ret; + ctx->initrd_size = total_size; + } + } + } else { + if (label->initrd) { + if (!strcmp(label->kernel_label, label->initrd)) { + ctx->initrd_addr = ctx->kern_addr; + ctx->initrd_size = ctx->kern_size; + } else { + if (get_relfile_envaddr(ctx, label->initrd, + "ramdisk_addr_r", SZ_2M, + (enum bootflow_img_t)IH_TYPE_RAMDISK, + &ctx->initrd_addr, + &ctx->initrd_size) < 0) { + printf("Skipping %s for failure retrieving initrd\n", + label->name); + return -EIO; + } + } } } @@ -697,7 +780,8 @@ int pxe_load_label(struct pxe_context *ctx, struct pxe_label *label) if (label->localboot) { if (label->localboot_val >= 0) { - if (IS_ENABLED(CONFIG_BOOTMETH_EXTLINUX_LOCALBOOT)) { + if (IS_ENABLED(CONFIG_BOOTMETH_EXTLINUX_LOCALBOOT) && + !label->kernel) { ret = generate_localboot(label); if (ret) return ret; diff --git a/include/pxe_utils.h b/include/pxe_utils.h index 48d36bdd14c..3367230eb1c 100644 --- a/include/pxe_utils.h +++ b/include/pxe_utils.h @@ -39,7 +39,9 @@ * @kernel: the path to the kernel file to use for this label * @config: FIT configuration to use (after '#'), or NULL if none * @append: kernel command line to use when booting this label - * @initrd: path to the initrd to use for this label. + * @initrd: path to single initrd (used if !CONFIG_PXE_INITRD_LIST) + * @initrds: list of initrd paths (alist of char *) (used if + * CONFIG_PXE_INITRD_LIST) * @fdt: path to FDT to use * @fdtdir: path to FDT directory to use * @files: list of files to load (alist of struct pxe_file) @@ -60,6 +62,7 @@ struct pxe_label { char *config; char *append; char *initrd; + struct alist initrds; char *fdt; char *fdtdir; struct alist files; diff --git a/test/boot/pxe.c b/test/boot/pxe.c index f4a124eafda..cd831807b94 100644 --- a/test/boot/pxe.c +++ b/test/boot/pxe.c @@ -203,7 +203,9 @@ static int pxe_test_parse_norun(struct unit_test_state *uts) ut_asserteq_str("/vmlinuz", label->kernel); ut_assertnull(label->config); ut_asserteq_str("root=/dev/sda1 quiet", label->append); - ut_asserteq_str("/initrd.img", label->initrd); + ut_asserteq(1, label->initrds.count); + ut_asserteq_str("/initrd.img", + *alist_get(&label->initrds, 0, char *)); ut_asserteq_str("/dtb/board.dtb", label->fdt); ut_assertnull(label->fdtdir); ut_asserteq(5, label->files.count); @@ -233,7 +235,7 @@ static int pxe_test_parse_norun(struct unit_test_state *uts) ut_asserteq_str("/vmlinuz-rescue", label->kernel); ut_assertnull(label->config); ut_asserteq_str("single", label->append); - ut_assertnull(label->initrd); + ut_asserteq(0, label->initrds.count); ut_assertnull(label->fdt); ut_asserteq_str("/dtb/", label->fdtdir); ut_asserteq(1, label->files.count); @@ -255,7 +257,7 @@ static int pxe_test_parse_norun(struct unit_test_state *uts) ut_assertnull(label->kernel); ut_assertnull(label->config); ut_assertnull(label->append); - ut_assertnull(label->initrd); + ut_asserteq(0, label->initrds.count); ut_assertnull(label->fdt); ut_assertnull(label->fdtdir); ut_asserteq(0, label->files.count); @@ -275,7 +277,7 @@ static int pxe_test_parse_norun(struct unit_test_state *uts) ut_asserteq_str("/boot/image.fit", label->kernel); ut_asserteq_str("#config-1", label->config); ut_asserteq_str("console=ttyS0", label->append); - ut_assertnull(label->initrd); + ut_asserteq(0, label->initrds.count); ut_assertnull(label->fdt); ut_assertnull(label->fdtdir); ut_asserteq(1, label->files.count); @@ -297,7 +299,7 @@ static int pxe_test_parse_norun(struct unit_test_state *uts) ut_asserteq_str("/boot/included-kernel", label->kernel); ut_assertnull(label->config); ut_asserteq_str("root=/dev/sdb1", label->append); - ut_assertnull(label->initrd); + ut_asserteq(0, label->initrds.count); ut_assertnull(label->fdt); ut_assertnull(label->fdtdir); ut_asserteq(1, label->files.count); From patchwork Fri Feb 13 20:24:12 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1854 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014309; bh=KYE0MRTIiLQF3eKwD2+2Z5YMs8XjFIj3wLV1zvkOUFw=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=cJrVzdS357xKOZa5+1eDSU/WEy0N0zASaUIyb4mpCSTiV1bZgOawKg7eWqtQ7rx2n kzJw6h2pW2CBuWt0hZAa1o120m/ue+7R5xPMDojIp3A0Tce/fof5j3kQgzJ84tk1vc QrBGkjQbko+GsvQPKdbNVR+qOeBWJ32OojgfqaltPiJdvFC7xLMiFdKG4PURKJmdfY WvDkUO/iq2dCpewoPfRv76AShHoXO0ifSBTGgF3GVhMeTRZPLxUTDqAl/p9e6j9dtD A1X12hrUE+IyL0ZbFY6BtaG9KR/kZ0HlgRZeEf2etzUewF6OH9BXYHIjqp2NuhsTw5 RmnysR30ax67Q== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 5C78069B3A for ; Fri, 13 Feb 2026 13:25:09 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id HPJgmHVHhWGg for ; Fri, 13 Feb 2026 13:25:09 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014309; bh=KYE0MRTIiLQF3eKwD2+2Z5YMs8XjFIj3wLV1zvkOUFw=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=cJrVzdS357xKOZa5+1eDSU/WEy0N0zASaUIyb4mpCSTiV1bZgOawKg7eWqtQ7rx2n kzJw6h2pW2CBuWt0hZAa1o120m/ue+7R5xPMDojIp3A0Tce/fof5j3kQgzJ84tk1vc QrBGkjQbko+GsvQPKdbNVR+qOeBWJ32OojgfqaltPiJdvFC7xLMiFdKG4PURKJmdfY WvDkUO/iq2dCpewoPfRv76AShHoXO0ifSBTGgF3GVhMeTRZPLxUTDqAl/p9e6j9dtD A1X12hrUE+IyL0ZbFY6BtaG9KR/kZ0HlgRZeEf2etzUewF6OH9BXYHIjqp2NuhsTw5 RmnysR30ax67Q== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 4991A69B2D for ; Fri, 13 Feb 2026 13:25:09 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014307; bh=Qp7PqeoRI58JWGmBtat4jQ3EeCixNzBb9kS3oD9Csqw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UtT+rtTP0xUbObicFDBkCYavp8VtM0lPA3qtj3mV9fKvs4jqTVmiRQUUPOFKIEDjv KRnoAwhLgpy9vDoA/wBkj1c6SteauAXO51sPs+DXBZg490SXuID5kZrbLZWB4K0e0I V+hkNxdb/DuKfgPYyLS90i1N5OSF0h93YEA7uMBZL0Yxp4NVDQeVjrkZc7p0VX1bOm mjwvzE4U0bKzjVotwM6Ti/4xHfpqXCKY0pkMZBOaaRlS+cHmTtBZNybmqLE3MZPrzi Dxc1uec9FNW9YPQi1eaqwMCbK+ubC0+kRrRTTPxLv+5kreHz4mQbbsNrFxTe4nhs3S iRFj1t7vZp5WA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 4D3BB69B2D; Fri, 13 Feb 2026 13:25:07 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id BIR3OGCkANq8; Fri, 13 Feb 2026 13:25:07 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014301; bh=oSw/aW2kr6glHcP9Q6H4AO7KfVlJqiPPVc2ZJoz1fFA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=eGPVakU95f09UYQB0cF6FxZDinzlwFHMcqF4Z4DZD1NjT1d/8shh2Am9ZlOVO0Dp5 zj57Yu+K8geVn4O9SVFP0IGN8No2pEMuqVIx5MoXXRiOBttpjxFNhBFiozT7hjDYah jQkXuZ12gNh8BjKqFQXfKPC6WueKtSaSZJc4hsTc3y3nij/8GrLWko01sF+YFnobut 3qj+5JcVElspcqSARE5CERs4woj/HJrzovwW+9PYkSKquQTjaK8QEdCBf6P18uz+Dz JS2+ch4mkwRZTsdYPswtp3cYNRQ+GmWewBv5WPle81GMNdNu2dpsRb1K9dDZbAPddC pGQKBypx5CK7g== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 6A4A669A66; Fri, 13 Feb 2026 13:25:01 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Fri, 13 Feb 2026 13:24:12 -0700 Message-ID: <20260213202417.223068-8-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260213202417.223068-1-sjg@u-boot.org> References: <20260213202417.223068-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: CY65I7AK3574GM7CG7N7AVLWYGL63NQM X-Message-ID-Hash: CY65I7AK3574GM7CG7N7AVLWYGL63NQM X-MailFrom: sjg@u-boot.org 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 CC: Simon Glass , "Claude Opus 4 . 6" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 7/8] bls: Add 'fit' field for FIT image support List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass The BLS parser only accepts 'linux' as the kernel field. This does not distinguish between a plain kernel image and a FIT image, making it harder for the bootmethod to handle them differently. Add a 'fit' field as an alternative to 'linux' for specifying a FIT image path. The parser now accepts either 'linux' or 'fit' as the required kernel field. When both are present, 'fit' takes priority in the bootmethod. Add a parser unit test for a fit-only entry. Co-developed-by: Claude Opus 4.6 Signed-off-by: Simon Glass --- boot/bls_parse.c | 12 +++++++++--- boot/bootmeth_bls.c | 7 ++++++- include/bls.h | 7 +++++-- test/boot/bls_parse.c | 24 ++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/boot/bls_parse.c b/boot/bls_parse.c index 9a067736655..1e4f6330430 100644 --- a/boot/bls_parse.c +++ b/boot/bls_parse.c @@ -26,6 +26,7 @@ enum bls_token_t { TOK_TITLE = 0, TOK_VERSION, TOK_LINUX, + TOK_FIT, TOK_OPTIONS, TOK_INITRD, TOK_DEVICETREE, @@ -42,6 +43,7 @@ static const char *const bls_token_names[] = { [TOK_TITLE] = "title", [TOK_VERSION] = "version", [TOK_LINUX] = "linux", + [TOK_FIT] = "fit", [TOK_OPTIONS] = "options", [TOK_INITRD] = "initrd", [TOK_DEVICETREE] = "devicetree", @@ -224,6 +226,10 @@ int bls_parse_entry(const char *buf, size_t size, struct bls_entry *entry) /* Point into buffer */ entry->kernel = value; break; + case TOK_FIT: + /* Point into buffer */ + entry->fit = value; + break; case TOK_OPTIONS: /* Multiple times - allocate and concatenate */ if (bls_append_str(&entry->options, value)) @@ -267,10 +273,10 @@ int bls_parse_entry(const char *buf, size_t size, struct bls_entry *entry) /* * Validate required fields: BLS spec requires at least one of - * 'linux' or 'efi'. We only support 'linux' for Type #1 entries. + * 'linux' or 'efi'. We also accept 'fit' for FIT images. */ - if (!entry->kernel) { - log_err("BLS entry missing required 'linux' field\n"); + if (!entry->kernel && !entry->fit) { + log_err("BLS entry missing required 'linux' or 'fit' field\n"); return -EINVAL; } diff --git a/boot/bootmeth_bls.c b/boot/bootmeth_bls.c index 2c66e14c641..13353906fff 100644 --- a/boot/bootmeth_bls.c +++ b/boot/bootmeth_bls.c @@ -202,7 +202,12 @@ static int bls_entry_init(struct bls_entry *entry, struct bootflow *bflow, } /* Register discovered images (not yet loaded, addr=0) */ - if (entry->kernel) { + if (entry->fit) { + if (!bootflow_img_add(bflow, entry->fit, + (enum bootflow_img_t)IH_TYPE_KERNEL, + 0, 0)) + return log_msg_ret("imf", -ENOMEM); + } else if (entry->kernel) { if (!bootflow_img_add(bflow, entry->kernel, (enum bootflow_img_t)IH_TYPE_KERNEL, 0, 0)) diff --git a/include/bls.h b/include/bls.h index eb32b323f1a..e00b5998999 100644 --- a/include/bls.h +++ b/include/bls.h @@ -24,8 +24,9 @@ * * @title: Human-readable name (points into buffer) * @version: OS version string (points into buffer) - * @kernel: Kernel path or FIT image - required (points into buffer) + * @kernel: Kernel path - required unless @fit is set (points into buffer) * Can include FIT config syntax: path#config + * @fit: FIT image path - required unless @kernel is set (points into buffer) * @options: Kernel command line - ALLOCATED, must be freed * Multiple options lines are concatenated with spaces * @initrds: List of initrd paths (alist of char * pointing into buffer) @@ -41,6 +42,7 @@ struct bls_entry { char *title; char *version; char *kernel; + char *fit; char *options; /* Allocated */ struct alist initrds; /* list of char * into buffer */ char *devicetree; @@ -70,7 +72,8 @@ struct bls_entry { * Supported fields: * title - Human-readable name * version - OS version string - * linux - Kernel path (required) + * linux - Kernel path (required unless 'fit' is present) + * fit - FIT image path (required unless 'linux' is present) * options - Kernel command line (allocated, can appear multiple times) * initrd - Initramfs path (can appear multiple times) * devicetree - Device tree blob path diff --git a/test/boot/bls_parse.c b/test/boot/bls_parse.c index 01da816aee8..63ae60d6091 100644 --- a/test/boot/bls_parse.c +++ b/test/boot/bls_parse.c @@ -137,6 +137,30 @@ static int bls_test_parse_unknown_field(struct unit_test_state *uts) } UNIT_TEST(bls_test_parse_unknown_field, 0, bootstd); +/* Test FIT-only entry (no linux field) */ +static int bls_test_parse_fit(struct unit_test_state *uts) +{ + struct bls_entry entry; + char buf[] = + "title FIT Test\n" + "version 1.0\n" + "fit /boot/image.fit\n" + "options root=/dev/sda\n" + "initrd /initrd.img\n"; + + ut_assertok(bls_parse_entry(buf, sizeof(buf) - 1, &entry)); + ut_asserteq_str("FIT Test", entry.title); + ut_assertnull(entry.kernel); + ut_asserteq_str("/boot/image.fit", entry.fit); + ut_asserteq_str("root=/dev/sda", entry.options); + ut_asserteq(1, entry.initrds.count); + + bls_entry_uninit(&entry); + + return 0; +} +UNIT_TEST(bls_test_parse_fit, 0, bootstd); + /* Test all supported fields */ static int bls_test_parse_all_fields(struct unit_test_state *uts) { From patchwork Fri Feb 13 20:24:13 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1855 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014313; bh=zgHRKEn0pIPKsfjz59h1YsyrH0pBqMfXYT3rcj8o60Q=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=gtaDsM8kozzJxyaoGSe5mue69FoBPYPy1f4RQ+x50FxkUTEtD8HV0tAAXd3zIXbXj y5Q4QIaKmQtnTtZA6pdijYNJekLwBPw/OzINQnzlSMqq9JqCAaIq86pyKa3w3YMket LWFtwMoWpP2M3nBLb8GFSlXFlsHaXXeMbNlw9VOggwGABA4nTQl6KZnNd8A8uGMxcJ cBhqWgGGDruRkXDpuIM9aRrbCJCSC5u4ND+fy8flOzzkTVYuAI/llad0LKBN9Ew9iv g7yQco+pCMCCNND55Mfzr2zCQaw20cqpykhRiPLhgPECtZoA7bY1w44NNqnWv/6OmS OVqZKi2QEwnPA== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 2DF6169B34 for ; Fri, 13 Feb 2026 13:25:13 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id mgVCFp8WGXbh for ; Fri, 13 Feb 2026 13:25:13 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014313; bh=zgHRKEn0pIPKsfjz59h1YsyrH0pBqMfXYT3rcj8o60Q=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=gtaDsM8kozzJxyaoGSe5mue69FoBPYPy1f4RQ+x50FxkUTEtD8HV0tAAXd3zIXbXj y5Q4QIaKmQtnTtZA6pdijYNJekLwBPw/OzINQnzlSMqq9JqCAaIq86pyKa3w3YMket LWFtwMoWpP2M3nBLb8GFSlXFlsHaXXeMbNlw9VOggwGABA4nTQl6KZnNd8A8uGMxcJ cBhqWgGGDruRkXDpuIM9aRrbCJCSC5u4ND+fy8flOzzkTVYuAI/llad0LKBN9Ew9iv g7yQco+pCMCCNND55Mfzr2zCQaw20cqpykhRiPLhgPECtZoA7bY1w44NNqnWv/6OmS OVqZKi2QEwnPA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 1AB3969A66 for ; Fri, 13 Feb 2026 13:25:13 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014311; bh=TQisWVumTcDV4sW8OT50jqvQjLE3uk2ll+0/4o/wgsc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JoKCs51sbzLt9FiFF6M8nXiyrFNMapIno6VZylHopZLF2wiKIRMnYUggW2DmnWV2i du11hTmvNF0g40Jkhe8tl9nip2d8hiUMt6vzMONr//+nztn2BOglPRi0RA/j+hiSxm 17qPROwe7C6P1IAqLLmlef/8UYygH/whRc7ab7h8mLZTIzdK6ZEghR0/nDrE6CRwnk MZtcIp2ady/6ShYCc8j5ATvvU13BSIoFn8KynsjkipNXCeFNbox8xyAnRwal2iyohv 2V/uUrybVPC2+OC0opSf2UkH5MiQ2aNzMfmfZcMJe5dLYnxb/dMVG3qn6App2PN2qG PiwU1TAvYNE4w== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C4B1269B3A; Fri, 13 Feb 2026 13:25:11 -0700 (MST) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id WqU5Q4labGYL; Fri, 13 Feb 2026 13:25:11 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1771014306; bh=IAROsKHkBnc/hVqjk6f6RAuz3+UNn1OjsvfQXobPHPk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ne18DLoCejsWYMrG2kUXJdJLLo7Ytli38VnGvV8hI4AcUe0cTSiUGARy+R9UWVtyM FIjfkOkkQBRDtu2AORCazauyP+egjxVi0CyBK5N24cUCNIdUdwsYkFqJamSzZ5LCTO aKl/D4xhDcNrSfwnLYe/Xe+pMisosdptBUlE6RNgmI0+suTqcnPg6XEXj2ijany+n+ r3iDkpfB96OLx2VE8g84AlDZziAmoJHVobKuAFNN5Yu8d2dhrWVX4Ag7LwQ2KtPgku o50FTekI23To+/SY44EC7jn/J2Kg0dUu6tfAPuu8SDnyN1Jruu5jbWdholhtHC56kw 4kOHk7A5dnQOA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 3497369B0E; Fri, 13 Feb 2026 13:25:06 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Fri, 13 Feb 2026 13:24:13 -0700 Message-ID: <20260213202417.223068-9-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260213202417.223068-1-sjg@u-boot.org> References: <20260213202417.223068-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: KSYSARHYB5XQORMK4J7DT3EOEUNJVDII X-Message-ID-Hash: KSYSARHYB5XQORMK4J7DT3EOEUNJVDII X-MailFrom: sjg@u-boot.org 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 CC: Simon Glass , "Claude Opus 4 . 6" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 8/8] doc: bls: Update for FIT and multi-initrd support List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Update the BLS documentation to reflect recent changes: - Document the 'fit' field as a U-Boot extension for specifying FIT images explicitly - Update initrd to note that all paths are now loaded - Add references to the Unified Kernel Image spec for the unsupported EFI/UKI fields - Remove outdated "only first initrd" limitation Co-developed-by: Claude Opus 4.6 Signed-off-by: Simon Glass --- doc/usage/bls.rst | 54 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/doc/usage/bls.rst b/doc/usage/bls.rst index 5f5f0efb8a4..f96652bd242 100644 --- a/doc/usage/bls.rst +++ b/doc/usage/bls.rst @@ -46,8 +46,9 @@ Supported Fields **Required (at least one):** -* ``linux`` - Path to Linux kernel image (Type #1); supports FITs with +* ``linux`` - Path to Linux kernel image; supports FITs with ``path#config`` syntax +* ``fit`` - Path to FIT (U-Boot extension, not in the BLS spec) **Optional:** @@ -55,30 +56,59 @@ Supported Fields * ``version`` - OS version identifier (parsed but not used for sorting) * ``options`` - Kernel command line parameters (may appear multiple times; all occurrences are concatenated) -* ``initrd`` - Initial ramdisk path (may appear multiple times, but only first - is used due to PXE limitation) +* ``initrd`` - Initial ramdisk path (may appear multiple times; all initrds + are loaded) * ``devicetree`` - Device tree blob path * ``devicetree-overlay`` - Device tree overlays (parsed but not yet supported) * ``architecture`` - Target architecture (parsed but not used for filtering) * ``machine-id`` - OS identifier (parsed but not used for filtering) * ``sort-key`` - Primary sorting key (parsed but not used for sorting) -**Not supported (out of scope for Type #1):** +**Not supported:** -* ``efi`` - EFI program path (Type #2/UKI) +These fields relate to `Unified Kernel Images`_ (UKIs), which combine a UEFI +boot stub, kernel, initrd and other resources into a single UEFI PE file. They +are not currently supported by U-Boot: + +* ``efi`` - EFI program path * ``uki`` - Unified Kernel Image path * ``uki-url`` - Remote UKI reference * ``profile`` - Multi-profile UKI selector +.. _Unified Kernel Images: https://uapi-group.org/specifications/specs/unified_kernel_image/ + +U-Boot Extensions +----------------- + +The following fields are U-Boot extensions not defined in the BLS spec: + +* ``fit`` - Specifies a FIT path, as an alternative to ``linux``. When + ``fit`` is present it takes priority over ``linux``. This allows the entry to + explicitly indicate that the image is a FIT, rather than relying on the + ``path#config`` syntax in the ``linux`` field. + +Example:: + + title Ubuntu 24.04 + version 6.8.0 + fit /boot/ubuntu-6.8.0.fit + options root=/dev/sda3 ro quiet + initrd /boot/initrd-6.8.0.img + FIT Support ----------- -U-Boot's BLS implementation works seamlessly with FITs using the standard -``path#config`` syntax in the ``linux`` field:: +FITs can be specified in two ways: + +1. Using the ``linux`` field with ``path#config`` syntax:: linux /boot/image.fit#config-1 -The PXE boot infrastructure handles FIT parsing automatically. +2. Using the ``fit`` field (U-Boot extension):: + + fit /boot/image.fit + +The PXE boot infrastructure handles FIT parsing automatically in both cases. Multiple Values --------------- @@ -86,8 +116,7 @@ Multiple Values Fields that support multiple occurrences: * ``options`` - All values are concatenated with spaces -* ``initrd`` - Multiple paths can be specified, but only the first is used - (limitation of PXE boot infrastructure) +* ``initrd`` - All paths are loaded consecutively in memory Usage ----- @@ -115,11 +144,12 @@ Current Limitations ------------------- * Only single entry file, not multiple entries directory scanning -* Only first initrd used (PXE infrastructure limitation) * No devicetree-overlay support * No architecture/machine-id filtering * No version-based or sort-key sorting -* No UKI/Type #2 support +* No `Unified Kernel Image`_ (UKI) support + +.. _Unified Kernel Image: https://uapi-group.org/specifications/specs/unified_kernel_image/ See Also --------