mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 07:04:28 +00: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:
parent
9d260253e8
commit
ef5e3891f5
9 changed files with 302 additions and 0 deletions
|
@ -696,6 +696,8 @@ F: tools/binman/
|
|||
BOOTDEVICE
|
||||
M: Simon Glass <sjg@chromium.org>
|
||||
S: Maintained
|
||||
F: boot/bootstd.c
|
||||
F: include/bootstd.h
|
||||
F: include/bootflow.h
|
||||
|
||||
BTRFS
|
||||
|
|
34
boot/Kconfig
34
boot/Kconfig
|
@ -292,6 +292,40 @@ endif # SPL
|
|||
|
||||
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
|
||||
bool "Enable support for the legacy image format"
|
||||
default y if !FIT_SIGNATURE
|
||||
|
|
|
@ -18,6 +18,9 @@ endif
|
|||
obj-y += image.o image-board.o
|
||||
obj-$(CONFIG_ANDROID_AB) += android_ab.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_)FIT_SIGNATURE) += fdt_region.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_DEBUG_UART=y
|
||||
CONFIG_FIT=y
|
||||
# CONFIG_BOOTSTD is not set
|
||||
CONFIG_SHOW_BOOT_PROGRESS=y
|
||||
CONFIG_USE_BOOTARGS=y
|
||||
CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro"
|
||||
|
|
|
@ -8,6 +8,7 @@ CONFIG_VENDOR_EFI=y
|
|||
CONFIG_TARGET_EFI_APP64=y
|
||||
CONFIG_DEBUG_UART=y
|
||||
CONFIG_FIT=y
|
||||
# CONFIG_BOOTSTD is not set
|
||||
CONFIG_SHOW_BOOT_PROGRESS=y
|
||||
CONFIG_USE_BOOTARGS=y
|
||||
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_BLK, /* Block device */
|
||||
UCLASS_BOOTCOUNT, /* Bootcount backing store */
|
||||
UCLASS_BOOTSTD, /* Standard boot driver */
|
||||
UCLASS_BUTTON, /* Button */
|
||||
UCLASS_CACHE, /* Cache controller */
|
||||
UCLASS_CLK, /* Clock source, e.g. used by peripherals */
|
||||
|
|
Loading…
Reference in a new issue