Files
u-boot/examples/ulib/bootflow.c
Simon Glass 7811a8ae52 ulib: Add a boot example
Add an example of a program which boots an OS by calling into the U-Boot
library.

Series-to: concept
Co-developed-by: Claude <noreply@anthropic.com>
Co-developed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
Series-links: 1:28
2025-09-10 03:37:08 -06:00

142 lines
3.9 KiB
C

// 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 <simon.glass@canonical.com>
*/
/* This file uses U-Boot headers first */
#include <bootflow.h>
#include <bootdev.h>
#include <bootmeth.h>
#include <bootstd.h>
#include <dm/device.h>
#include <sandbox_host.h>
#include <u-boot-api.h>
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;
}