mirror of
https://xff.cz/git/u-boot/
synced 2025-10-03 08:21:30 +02:00
bootstd: Add the bootstd uclass and core implementation
The 'bootstd' device provides the central information about U-Boot standard boot. Add a uclass for bootstd and the various helpers needed to make it work. Also add a binding file. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -696,6 +696,8 @@ F: tools/binman/
|
|||||||
BOOTDEVICE
|
BOOTDEVICE
|
||||||
M: Simon Glass <sjg@chromium.org>
|
M: Simon Glass <sjg@chromium.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
F: boot/bootstd.c
|
||||||
|
F: include/bootstd.h
|
||||||
F: include/bootflow.h
|
F: include/bootflow.h
|
||||||
|
|
||||||
BTRFS
|
BTRFS
|
||||||
|
34
boot/Kconfig
34
boot/Kconfig
@@ -292,6 +292,40 @@ endif # SPL
|
|||||||
|
|
||||||
endif # FIT
|
endif # FIT
|
||||||
|
|
||||||
|
config BOOTSTD
|
||||||
|
bool "Standard boot support"
|
||||||
|
default y
|
||||||
|
depends on DM && OF_CONTROL && BLK
|
||||||
|
help
|
||||||
|
U-Boot supports a standard way of locating something to boot,
|
||||||
|
typically an Operating System such as Linux, provided by a distro such
|
||||||
|
as Arch Linux or Debian. Enable this to support iterating through
|
||||||
|
available bootdevs and using bootmeths to find bootflows suitable for
|
||||||
|
booting.
|
||||||
|
|
||||||
|
Standard boot is not a standard way of booting, just a framework
|
||||||
|
within U-Boot for supporting all the different ways that exist.
|
||||||
|
|
||||||
|
Terminology:
|
||||||
|
|
||||||
|
- bootdev - a device which can hold a distro (e.g. MMC)
|
||||||
|
- bootmeth - a method to scan a bootdev to find bootflows (owned by
|
||||||
|
U-Boot)
|
||||||
|
- bootflow - a description of how to boot (owned by the distro)
|
||||||
|
|
||||||
|
config BOOTSTD_FULL
|
||||||
|
bool "Enhanced features for standard boot"
|
||||||
|
default y if SANDBOX
|
||||||
|
help
|
||||||
|
This enables various useful features for standard boot, which are not
|
||||||
|
essential for operation:
|
||||||
|
|
||||||
|
- bootdev, bootmeth commands
|
||||||
|
- extra features in the bootflow command
|
||||||
|
- support for selecting the ordering of bootmeths ("bootmeth order")
|
||||||
|
- support for selecting the ordering of bootdevs using the devicetree
|
||||||
|
as well as the "boot_targets" environment variable
|
||||||
|
|
||||||
config LEGACY_IMAGE_FORMAT
|
config LEGACY_IMAGE_FORMAT
|
||||||
bool "Enable support for the legacy image format"
|
bool "Enable support for the legacy image format"
|
||||||
default y if !FIT_SIGNATURE
|
default y if !FIT_SIGNATURE
|
||||||
|
@@ -18,6 +18,9 @@ endif
|
|||||||
obj-y += image.o image-board.o
|
obj-y += image.o image-board.o
|
||||||
obj-$(CONFIG_ANDROID_AB) += android_ab.o
|
obj-$(CONFIG_ANDROID_AB) += android_ab.o
|
||||||
obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o
|
obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootstd-uclass.o
|
||||||
|
|
||||||
obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
|
obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
|
||||||
obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o
|
obj-$(CONFIG_$(SPL_TPL_)FIT_SIGNATURE) += fdt_region.o
|
||||||
obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
|
obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
|
||||||
|
152
boot/bootstd-uclass.c
Normal file
152
boot/bootstd-uclass.c
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Uclass implementation for standard boot
|
||||||
|
*
|
||||||
|
* Copyright 2021 Google LLC
|
||||||
|
* Written by Simon Glass <sjg@chromium.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <bootflow.h>
|
||||||
|
#include <bootstd.h>
|
||||||
|
#include <dm.h>
|
||||||
|
#include <log.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <dm/device-internal.h>
|
||||||
|
#include <dm/lists.h>
|
||||||
|
#include <dm/read.h>
|
||||||
|
#include <dm/uclass-internal.h>
|
||||||
|
|
||||||
|
DECLARE_GLOBAL_DATA_PTR;
|
||||||
|
|
||||||
|
/* These are used if filename-prefixes is not present */
|
||||||
|
const char *const default_prefixes[] = {"/", "/boot/", NULL};
|
||||||
|
|
||||||
|
static int bootstd_of_to_plat(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct bootstd_priv *priv = dev_get_priv(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
|
||||||
|
/* Don't check errors since livetree and flattree are different */
|
||||||
|
ret = dev_read_string_list(dev, "filename-prefixes",
|
||||||
|
&priv->prefixes);
|
||||||
|
dev_read_string_list(dev, "bootdev-order",
|
||||||
|
&priv->bootdev_order);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bootstd_clear_glob_(struct bootstd_priv *priv)
|
||||||
|
{
|
||||||
|
while (!list_empty(&priv->glob_head)) {
|
||||||
|
struct bootflow *bflow;
|
||||||
|
|
||||||
|
bflow = list_first_entry(&priv->glob_head, struct bootflow,
|
||||||
|
glob_node);
|
||||||
|
/* add later bootflow_remove(bflow); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bootstd_clear_glob(void)
|
||||||
|
{
|
||||||
|
struct bootstd_priv *std;
|
||||||
|
|
||||||
|
if (bootstd_get_priv(&std))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bootstd_clear_glob_(std);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bootstd_remove(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct bootstd_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
free(priv->prefixes);
|
||||||
|
free(priv->bootdev_order);
|
||||||
|
bootstd_clear_glob_(priv);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *const *const bootstd_get_bootdev_order(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct bootstd_priv *std = dev_get_priv(dev);
|
||||||
|
|
||||||
|
return std->bootdev_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *const *const bootstd_get_prefixes(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct bootstd_priv *std = dev_get_priv(dev);
|
||||||
|
|
||||||
|
return std->prefixes ? std->prefixes : default_prefixes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bootstd_get_priv(struct bootstd_priv **stdp)
|
||||||
|
{
|
||||||
|
struct udevice *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = uclass_first_device_err(UCLASS_BOOTSTD, &dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
*stdp = dev_get_priv(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int bootstd_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct bootstd_priv *std = dev_get_priv(dev);
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&std->glob_head);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For now, bind the boormethod device if none are found in the devicetree */
|
||||||
|
int dm_scan_other(bool pre_reloc_only)
|
||||||
|
{
|
||||||
|
struct udevice *bootstd;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* These are not needed before relocation */
|
||||||
|
if (!(gd->flags & GD_FLG_RELOC))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Create a bootstd device if needed */
|
||||||
|
uclass_find_first_device(UCLASS_BOOTSTD, &bootstd);
|
||||||
|
if (!bootstd) {
|
||||||
|
ret = device_bind_driver(gd->dm_root, "bootstd_drv", "bootstd",
|
||||||
|
&bootstd);
|
||||||
|
if (ret)
|
||||||
|
return log_msg_ret("bootstd", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct udevice_id bootstd_ids[] = {
|
||||||
|
{ .compatible = "u-boot,boot-std" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(bootstd_drv) = {
|
||||||
|
.id = UCLASS_BOOTSTD,
|
||||||
|
.name = "bootstd_drv",
|
||||||
|
.of_to_plat = bootstd_of_to_plat,
|
||||||
|
.probe = bootstd_probe,
|
||||||
|
.remove = bootstd_remove,
|
||||||
|
.of_match = bootstd_ids,
|
||||||
|
.priv_auto = sizeof(struct bootstd_priv),
|
||||||
|
};
|
||||||
|
|
||||||
|
UCLASS_DRIVER(bootstd) = {
|
||||||
|
.id = UCLASS_BOOTSTD,
|
||||||
|
.name = "bootstd",
|
||||||
|
#if CONFIG_IS_ENABLED(OF_REAL)
|
||||||
|
.post_bind = dm_scan_fdt_dev,
|
||||||
|
#endif
|
||||||
|
};
|
@@ -8,6 +8,7 @@ CONFIG_VENDOR_EFI=y
|
|||||||
CONFIG_TARGET_EFI_APP32=y
|
CONFIG_TARGET_EFI_APP32=y
|
||||||
CONFIG_DEBUG_UART=y
|
CONFIG_DEBUG_UART=y
|
||||||
CONFIG_FIT=y
|
CONFIG_FIT=y
|
||||||
|
# CONFIG_BOOTSTD is not set
|
||||||
CONFIG_SHOW_BOOT_PROGRESS=y
|
CONFIG_SHOW_BOOT_PROGRESS=y
|
||||||
CONFIG_USE_BOOTARGS=y
|
CONFIG_USE_BOOTARGS=y
|
||||||
CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
|
CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
|
||||||
|
@@ -8,6 +8,7 @@ CONFIG_VENDOR_EFI=y
|
|||||||
CONFIG_TARGET_EFI_APP64=y
|
CONFIG_TARGET_EFI_APP64=y
|
||||||
CONFIG_DEBUG_UART=y
|
CONFIG_DEBUG_UART=y
|
||||||
CONFIG_FIT=y
|
CONFIG_FIT=y
|
||||||
|
# CONFIG_BOOTSTD is not set
|
||||||
CONFIG_SHOW_BOOT_PROGRESS=y
|
CONFIG_SHOW_BOOT_PROGRESS=y
|
||||||
CONFIG_USE_BOOTARGS=y
|
CONFIG_USE_BOOTARGS=y
|
||||||
CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
|
CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
|
||||||
|
28
doc/device-tree-bindings/bootstd.txt
Normal file
28
doc/device-tree-bindings/bootstd.txt
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
U-Boot standard boot device (bootstd)
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
This is the controlling device for U-Boot standard boot, providing a way to
|
||||||
|
boot operating systems in a way that can be controlled by distros.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
compatible: "u-boot,boot-std"
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
|
||||||
|
filename-prefixes:
|
||||||
|
List of strings, each a directory to search for bootflow files
|
||||||
|
|
||||||
|
bootdev-order:
|
||||||
|
List of bootdevs to check for bootflows, each a bootdev label (the media
|
||||||
|
uclass followed by the numeric sequence number of the media device)
|
||||||
|
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
bootstd {
|
||||||
|
compatible = "u-boot,boot-std";
|
||||||
|
|
||||||
|
filename-prefixes = "/", "/boot/";
|
||||||
|
bootdev-order = "mmc2", "mmc1";
|
||||||
|
};
|
80
include/bootstd.h
Normal file
80
include/bootstd.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
/*
|
||||||
|
* Standard U-Boot boot framework
|
||||||
|
*
|
||||||
|
* Copyright 2021 Google LLC
|
||||||
|
* Written by Simon Glass <sjg@chromium.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __bootstd_h
|
||||||
|
#define __bootstd_h
|
||||||
|
|
||||||
|
struct udevice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct bootstd_priv - priv data for the bootstd driver
|
||||||
|
*
|
||||||
|
* This is attached to the (only) bootstd device, so there is only one instance
|
||||||
|
* of this struct. It provides overall information about bootdevs and bootflows.
|
||||||
|
*
|
||||||
|
* @prefixes: NULL-terminated list of prefixes to use for bootflow filenames,
|
||||||
|
* e.g. "/", "/boot/"; NULL if none
|
||||||
|
* @bootdev_order: Order to use for bootdevs (or NULL if none), with each item
|
||||||
|
* being a bootdev label, e.g. "mmc2", "mmc1";
|
||||||
|
* @cur_bootdev: Currently selected bootdev (for commands)
|
||||||
|
* @cur_bootflow: Currently selected bootflow (for commands)
|
||||||
|
* @glob_head: Head for the global list of all bootflows across all bootdevs
|
||||||
|
* @bootmeth_count: Number of bootmeth devices in @bootmeth_order
|
||||||
|
* @bootmeth_order: List of bootmeth devices to use, in order, NULL-terminated
|
||||||
|
*/
|
||||||
|
struct bootstd_priv {
|
||||||
|
const char **prefixes;
|
||||||
|
const char **bootdev_order;
|
||||||
|
struct udevice *cur_bootdev;
|
||||||
|
struct bootflow *cur_bootflow;
|
||||||
|
struct list_head glob_head;
|
||||||
|
int bootmeth_count;
|
||||||
|
struct udevice **bootmeth_order;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bootstd_get_bootdev_order() - Get the boot-order list
|
||||||
|
*
|
||||||
|
* This reads the boot order, e.g. {"mmc0", "mmc2", NULL}
|
||||||
|
*
|
||||||
|
* The list is alloced by the bootstd driver so should not be freed. That is the
|
||||||
|
* reason for all the const stuff in the function signature
|
||||||
|
*
|
||||||
|
* Return: list of string points, terminated by NULL; or NULL if no boot order
|
||||||
|
*/
|
||||||
|
const char *const *const bootstd_get_bootdev_order(struct udevice *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bootstd_get_prefixes() - Get the filename-prefixes list
|
||||||
|
*
|
||||||
|
* This reads the prefixes, e.g. {"/", "/bpot", NULL}
|
||||||
|
*
|
||||||
|
* The list is alloced by the bootstd driver so should not be freed. That is the
|
||||||
|
* reason for all the const stuff in the function signature
|
||||||
|
*
|
||||||
|
* Return: list of string points, terminated by NULL; or NULL if no boot order
|
||||||
|
*/
|
||||||
|
const char *const *const bootstd_get_prefixes(struct udevice *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bootstd_get_priv() - Get the (single) state for the bootstd system
|
||||||
|
*
|
||||||
|
* The state holds a global list of all bootflows that have been found.
|
||||||
|
*
|
||||||
|
* Return: 0 if OK, -ve if the uclass does not exist
|
||||||
|
*/
|
||||||
|
int bootstd_get_priv(struct bootstd_priv **stdp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bootstd_clear_glob() - Clear the global list of bootflows
|
||||||
|
*
|
||||||
|
* This removes all bootflows globally and across all bootdevs.
|
||||||
|
*/
|
||||||
|
void bootstd_clear_glob(void);
|
||||||
|
|
||||||
|
#endif
|
@@ -38,6 +38,7 @@ enum uclass_id {
|
|||||||
UCLASS_AXI, /* AXI bus */
|
UCLASS_AXI, /* AXI bus */
|
||||||
UCLASS_BLK, /* Block device */
|
UCLASS_BLK, /* Block device */
|
||||||
UCLASS_BOOTCOUNT, /* Bootcount backing store */
|
UCLASS_BOOTCOUNT, /* Bootcount backing store */
|
||||||
|
UCLASS_BOOTSTD, /* Standard boot driver */
|
||||||
UCLASS_BUTTON, /* Button */
|
UCLASS_BUTTON, /* Button */
|
||||||
UCLASS_CACHE, /* Cache controller */
|
UCLASS_CACHE, /* Cache controller */
|
||||||
UCLASS_CLK, /* Clock source, e.g. used by peripherals */
|
UCLASS_CLK, /* Clock source, e.g. used by peripherals */
|
||||||
|
Reference in New Issue
Block a user