From patchwork Wed Sep 10 09:37:48 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 280 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=1757497090; bh=Cw8EQ9xWY5fca4ckAwbdzXadv4ln9+ZgjHXlgQxLk9g=; 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=bv761EHY2yDNDzEDFZ1VQhRnJR5GhZFiNRm1eBzLEhP+VNfb4QfeqIPZ1RRvEeKG9 y1cXBPUBhUzLw1V2uCZOSufdSXt4DgBzGkw6xqCzWlSPm/r3nWJFkNTL+nUwO9PuNf Akwvuc/4ZNTKvuUlOlOveHCrXoL6zqUy+G2Z517IWeCJKK2hralDhzO7ebzlAkUFxL /Yg6gxGtabCvay8ILMxDZ/Dp+CiKwhRZmjxPXlQiDvXv1esCSKerYX//d04HIxhhS0 b9SYzoDYcjBlqZxIvm2F26mu7PHDUOhNtMGIM5lwO9sTUsdOGKOptkixd5TGjiYF94 u4CCx49gOvk6A== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C44EA67A16 for ; Wed, 10 Sep 2025 03:38:10 -0600 (MDT) 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 ExWPa8Es1K82 for ; Wed, 10 Sep 2025 03:38:10 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757497090; bh=Cw8EQ9xWY5fca4ckAwbdzXadv4ln9+ZgjHXlgQxLk9g=; 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=bv761EHY2yDNDzEDFZ1VQhRnJR5GhZFiNRm1eBzLEhP+VNfb4QfeqIPZ1RRvEeKG9 y1cXBPUBhUzLw1V2uCZOSufdSXt4DgBzGkw6xqCzWlSPm/r3nWJFkNTL+nUwO9PuNf Akwvuc/4ZNTKvuUlOlOveHCrXoL6zqUy+G2Z517IWeCJKK2hralDhzO7ebzlAkUFxL /Yg6gxGtabCvay8ILMxDZ/Dp+CiKwhRZmjxPXlQiDvXv1esCSKerYX//d04HIxhhS0 b9SYzoDYcjBlqZxIvm2F26mu7PHDUOhNtMGIM5lwO9sTUsdOGKOptkixd5TGjiYF94 u4CCx49gOvk6A== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B2E0B6789C for ; Wed, 10 Sep 2025 03:38:10 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757497088; bh=IX+L2r7OU6aJDcrSQi/lMSgzPZY6aBmVMkNqBBgNOcI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LxxcSS2cSumO7hTIKaS989Mo6qIY7/s4/VNYm08KMEmMMPVvvWWc6XbYNM8ARBTb2 IXdIPJHTd+Amgrb1JZnQjKCHQDVj5AMRm3fWfdNB4h4335rJLnzOuQtehrOH5s2qUV hKWqVBQIZo1eg+TEKkJU9+gt4Na3y8JaRjdhtGnf7qoAsycKvUB1ksM6eLvVyYXAg7 DbmhVplIRF3TYeYz6HNDCZVIAt/rgPet8dZoGQCyWlUYDaUeRu8E8g0U1jiCv6WTLd gHTLZrtTCLUi/6x3zEYvLcCFKu+her7q8TFG47rm9E75KzAdAcb7LRElmxpt+YdgPc Qi3GGW/hzZ5gg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 5D13F5FE1B; Wed, 10 Sep 2025 03:38:08 -0600 (MDT) 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 DSdSryOJWjwT; Wed, 10 Sep 2025 03:38:08 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1757497084; bh=r2K5sPJ3hfpy7Rhjy105Zw5+njL+TvwydoY05ud+D/E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UzQScIYIB94K4ULq5VVt4mM6QWx5h6oOlSk4Vx7VdBGQ+FMuIdgl11ECOfP8/wcRT FJWI9ABk+jUwroboNkOLynWAhNqG3U80hqlmi4QTKHLp0A8BWG+vLemWdu/7WPyfz3 9aXKSv5RhdWLf7VLV9cEv+EZJ2Luc8XBrTvlM/dWnPI5Tk6KKgT7BCZ2FupOxqa/s5 g1285Oxin3vdtF7iePhmO9yXfBmgZSA46eyr7U/kj7Ha6cxDkezcbaDD/PLpFziYfK y1GijIbYn6uW7KDYdisjXrk79sk/ZsHRJyZ9RRDvRJ/qUIpzLIqZzO8oENrKn4Uo4N FdYnutXyBKebA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 6C9896789C; Wed, 10 Sep 2025 03:38:04 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Wed, 10 Sep 2025 03:37:48 -0600 Message-ID: <20250910093751.4004211-2-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250910093751.4004211-1-sjg@u-boot.org> References: <20250910093751.4004211-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: OVPGXX4LGCRCPTN7KQPFN2ZISN43RNYM X-Message-ID-Hash: OVPGXX4LGCRCPTN7KQPFN2ZISN43RNYM 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 X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 2/2] ulib: Add a boot example 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 an example of a program which boots an OS by calling into the U-Boot library. Co-developed-by: Claude Co-developed-by: Simon Glass Signed-off-by: Simon Glass --- examples/ulib/.gitignore | 2 + examples/ulib/Makefile | 5 +- examples/ulib/README | 23 +++++-- examples/ulib/boot.c | 64 ++++++++++++++++++ examples/ulib/bootflow.c | 141 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 229 insertions(+), 6 deletions(-) create mode 100644 examples/ulib/boot.c create mode 100644 examples/ulib/bootflow.c diff --git a/examples/ulib/.gitignore b/examples/ulib/.gitignore index d2f0dfa7a93..f275acf9df1 100644 --- a/examples/ulib/.gitignore +++ b/examples/ulib/.gitignore @@ -1,2 +1,4 @@ +/boot +/boot_static /demo /demo_static diff --git a/examples/ulib/Makefile b/examples/ulib/Makefile index a11c5dad9be..36de37daf51 100644 --- a/examples/ulib/Makefile +++ b/examples/ulib/Makefile @@ -29,13 +29,14 @@ include config.mk # Programs to build -progs := demo +progs := demo boot # Program definitions - list of object files for each program demo_objs := demo.o demo_helper.o +boot_objs := boot.o bootflow.o # Objects that need system headers (default is U-Boot headers) -sys-objs := demo_helper.o +sys-objs := boot.o demo_helper.o # Include build rules (must come after variable definitions) include rules.mk diff --git a/examples/ulib/README b/examples/ulib/README index e6f48bf79cd..23fb2a3d097 100644 --- a/examples/ulib/README +++ b/examples/ulib/README @@ -18,8 +18,8 @@ This creates: Example Programs ---------------- -The examples are built automatically as part of the U-Boot build. So far there -is only one. +The examples are built automatically as part of the U-Boot build. Each program +demonstrates different aspects of the U-Boot library. **demo.c** - Demonstrates using U-Boot library functions @@ -28,6 +28,14 @@ is only one. - Reads and displays system information - Shows the U-Boot version +**boot.c** - Demonstrates booting an OS using U-Boot bootflow + +- Shows bootflow scanning and booting functionality +- Uses system headers for main program logic (boot.c) +- Uses U-Boot headers for bootflow internals (bootflow.c) +- Demonstrates attaching disk images and scanning for bootable OS +- Attempts to boot the first discovered bootflow + Building Examples ----------------- @@ -50,14 +58,21 @@ Running Examples # Run the demo (static version) ./demo_static + # Run the boot example (requires disk image at /home/sglass/u/mmc1.img) + LD_LIBRARY_PATH=/tmp/b/sandbox ./boot + + # Run the boot example (static version) + ./boot_static + Key Points ---------- -- Avoid including U-Boot headers that conflict with system headers. This - Makefile gives priority to the system headers +- Files are compiled with U-Boot headers by default, except those listed in + sys-objs which use system headers - Use ulib_init() to init the library - Use ulib_uninit() to clean up - Set LD_LIBRARY_PATH when running dynamically linked programs +- Each program automatically gets both dynamic and static versions built Copying for External Use ------------------------- diff --git a/examples/ulib/boot.c b/examples/ulib/boot.c new file mode 100644 index 00000000000..ad8a52d5bc9 --- /dev/null +++ b/examples/ulib/boot.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Boot test program using U-Boot library + * + * This demonstrates basic initialization and cleanup of the U-Boot library. + * It will be used for testing bootstd functionality using ulib. + * + * Copyright 2025 Canonical Ltd. + * Written by Simon Glass + */ + +/* Use system headers, not U-Boot headers */ +#include +#include + +#include +#include + +/* Forward declaration for bootflow function */ +int bootflow_internal_scan(void); + +/* Forward declaration for host function (simplified) */ +int host_create_attach_file(const char *label, const char *filename, + int removable, unsigned long blksz, + void *devp); + +static void fatal(const char *msg) +{ + fprintf(stderr, "Error: %s\n", msg); + exit(1); +} + +static int try_boot(void) +{ + int ret; + + printf("Scanning for bootflows...\n"); + + /* MMC device attachment will be done in bootflow_internal_scan() */ + + ret = bootflow_internal_scan(); + if (ret) { + printf("Internal scan failed: %d\n", ret); + return ret; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret; + + ret = ulib_init(argv[0]); + if (ret) + fatal("Failed to init U-Boot library"); + + ret = try_boot(); + if (ret) + printf("Boot attempt failed: %d\n", ret); + + ulib_uninit(); + return ret; +} diff --git a/examples/ulib/bootflow.c b/examples/ulib/bootflow.c new file mode 100644 index 00000000000..e100a0ee492 --- /dev/null +++ b/examples/ulib/bootflow.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Bootflow internal functions using U-Boot headers + * + * This demonstrates functions that need direct access to U-Boot internal + * structures and would be compiled with U-Boot headers first. + * + * Copyright 2025 Canonical Ltd. + * Written by Simon Glass + */ + +/* This file uses U-Boot headers first */ +#include +#include +#include +#include +#include +#include +#include + +static void show_bootflow(int num, struct bootflow *bflow) +{ + ub_printf("Bootflow %d:\n", num); + ub_printf(" name: '%s'\n", bflow->name ? bflow->name : "(null)"); + ub_printf(" state: %s\n", bootflow_state_get_name(bflow->state)); + ub_printf(" method: '%s'\n", + bflow->method ? bflow->method->name : "(null)"); + ub_printf(" fname: '%s'\n", bflow->fname ? bflow->fname : "(null)"); + ub_printf(" dev: '%s'\n", bflow->dev ? bflow->dev->name : "(null)"); + ub_printf(" part: %d\n", bflow->part); + ub_printf(" size: %d\n", bflow->size); + ub_printf(" err: %d\n", bflow->err); + if (bflow->os_name) + ub_printf(" os_name: '%s'\n", bflow->os_name); + if (bflow->logo) + ub_printf(" logo: present (%zu bytes)\n", bflow->logo_size); + ub_printf("\n"); +} + +int bootflow_internal_scan(void) +{ + struct bootflow bflow; + struct bootflow_iter iter; + struct bootstd_priv *std; + struct bootflow *first_bflow; + struct udevice *host_dev; + int ret, count = 0; + + ub_printf("Internal bootflow scan using U-Boot headers first\n"); + + /* Get bootstd private data */ + ret = bootstd_get_priv(&std); + if (ret) { + ub_printf("bootstd_get_priv() failed: %d\n", ret); + return ret; + } + + /* Set bootmethod order to only use extlinux and efi */ + ret = bootmeth_set_order("extlinux efi"); + if (ret) { + ub_printf("bootmeth_set_order() failed: %d\n", ret); + return ret; + } + ub_printf("Set bootmethod order to: extlinux efi\n"); + + /* Now we can actually use bootflow.h definitions! */ + ub_printf("BOOTFLOWST_MEDIA = %d\n", BOOTFLOWST_MEDIA); + ub_printf("sizeof(struct bootflow) = %zu\n", sizeof(struct bootflow)); + ub_printf("sizeof(struct bootflow_iter) = %zu\n", + sizeof(struct bootflow_iter)); + + /* Attach the MMC image file to make bootflows available */ + ub_printf("Attaching mmc1.img file...\n"); + ret = host_create_attach_file("mmc1", "/home/sglass/u/mmc1.img", false, + 512, &host_dev); + if (ret) { + ub_printf("host_create_attach_file() failed: %d\n", ret); + + return ret; + } + + /* List all available bootdevs */ + ub_printf("Available bootdevs:\n"); + bootdev_list(true); + + /* Try to scan for the first bootflow */ + ret = bootflow_scan_first(NULL, NULL, &iter, BOOTFLOWIF_SHOW, + &bflow); + if (ret) { + ub_printf("bootflow_scan_first() failed: %d\n", ret); + return ret; + } + + /* Iterate through all bootflows */ + do { + count++; + show_bootflow(count, &bflow); + + /* Add bootflow to the global list */ + ret = bootstd_add_bootflow(&bflow); + if (ret < 0) { + ub_printf("bootstd_add_bootflow() failed: %d\n", ret); + bootflow_free(&bflow); + } + + /* Get next bootflow */ + ret = bootflow_scan_next(&iter, &bflow); + } while (!ret); + + ub_printf("Found %d total bootflows\n", count); + + /* Clean up the iterator */ + bootflow_iter_uninit(&iter); + + /* Return immediately if no bootflows found */ + if (!count) { + ub_printf("No bootflows found to boot\n"); + return 0; + } + + /* Boot the first bootflow */ + /* Get the first bootflow from the global list */ + first_bflow = alist_getw(&std->bootflows, 0, struct bootflow); + if (!first_bflow) { + ub_printf("Failed to get first bootflow from global list\n"); + return -1; + } + + ub_printf("\bBooting: %s\n", + first_bflow->name ? first_bflow->name : "(unnamed)"); + if (first_bflow->os_name) + ub_printf("OS: %s\n", first_bflow->os_name); + + ret = bootflow_boot(first_bflow); + if (ret) + ub_printf("bootflow_boot() failed: %dE\n", ret); + else + ub_printf("bootflow_boot() succeeded (shouldn't reach here!)\n"); + + return 0; +}