aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorTom Rini2023-01-24 14:04:14 -0500
committerTom Rini2023-01-24 14:04:14 -0500
commit4e1ab2065e21e48a3087144ab826f12cfb797a65 (patch)
tree1dc9e793258c5a4a1be4d5e6d554f7f1a82450f3 /include
parentdd31cd58b02729807934cb699b164b1f8736620f (diff)
parent3891c68ef50eda38d78c95ecd03aed030aa6bb53 (diff)
Merge branch '2023-01-24-bootstd-allow-migration-from-distro_bootcmd-script'
To quote the author: So far, standard boot does not replicate all the of the functionality of the distro_bootcmd scripts. In particular it lacks some bootdevs and some of the bootmeths are incomplete. Also there is currently no internal mechanism to enumerate buses in order to discover bootdevs, e.g. with USB. This series addresses these shortcomings: - Adds the concept of a 'bootdev hunter' to enumerate buses, etc. in an effort to find bootdevs of a certain priority - Adds bootdevs for SCSI, IDE, NVMe, virtio, SPI flash - Handles PXE and DHCP properly - Supports reading the device tree with EFI and reading scripts from the network It also tidies up label processing, so it is possible to use: bootflow scan mmc2 to scan just one MMC device (with BOOTSTD_FULL). As before this implementation still relies on CONFIG_CMDLINE being enabled, mostly for the network stack. Further work would be required to disentangle that. Quite a few tests are added but there are some gaps: - SPI flash bootdev - EFI FDT loading Note that SATA works via SCSI (CONFIG_SCSI_AHCI) and does not use driver model. Only pogo_v4 seems to be affected. Probably all thats is needed is to call bootdev_setup_sibling_blk() in the Marvell SATA driver. Also, while it would be possible to init MMC in a bootdev hunter, there is no point since U-Boot always inits MMC on startup, if present. With this series it should be possible to migrate boards to standard boot by removing the inclusion of config_distro_bootcmd.h and instead adding a suitable value for boot_targets to the environment, e.g.: boot_targets=mmc1 mmc0 nvme scsi usb pxe dhcp spi Thus it is possible to boot automatically without scripts and boards can use a text-based environment instead of the config.h files. To demonstrate this, rockpro64-rk3399 is migrated to standard boot in this series. Full migration could probably be automated using a script, similar in concept to moveconfig: - obtain the board environment via 'make u-boot-initial-env' - get the value of "boot_targets" - drop config_distro_bootcmd.h from the config.h file - rebuild again to get the environment without distro scripts - write the environment (adding boot_targets) to board.env - remove CONFIG_EXTRA_ENV_SETTINGS from the config.h file
Diffstat (limited to 'include')
-rw-r--r--include/bootdev.h206
-rw-r--r--include/bootflow.h134
-rw-r--r--include/bootmeth.h35
-rw-r--r--include/bootstd.h17
-rw-r--r--include/configs/rk3399_common.h5
-rw-r--r--include/configs/rockchip-common.h2
-rw-r--r--include/dm/uclass-id.h4
-rw-r--r--include/dm/util.h8
-rw-r--r--include/net.h31
-rw-r--r--include/part.h8
-rw-r--r--include/test/test.h72
-rw-r--r--include/vsprintf.h24
12 files changed, 476 insertions, 70 deletions
diff --git a/include/bootdev.h b/include/bootdev.h
index 9fc219839fe..b92ff4d4f15 100644
--- a/include/bootdev.h
+++ b/include/bootdev.h
@@ -11,6 +11,7 @@
struct bootflow;
struct bootflow_iter;
+struct bootstd_priv;
struct udevice;
/**
@@ -20,19 +21,87 @@ struct udevice;
*
* Smallest value is the highest priority. By default, bootdevs are scanned from
* highest to lowest priority
+ *
+ * BOOTDEVP_0_NONE: Invalid value, do not use
+ * @BOOTDEVP_6_PRE_SCAN: Scan bootdevs with this priority always, before
+ * starting any bootflow scan
+ * @BOOTDEVP_2_INTERNAL_FAST: Internal devices which don't need scanning and
+ * generally very quick to access, e.g. less than 100ms
+ * @BOOTDEVP_3_INTERNAL_SLOW: Internal devices which don't need scanning but
+ * take a significant fraction of a second to access
+ * @BOOTDEVP_4_SCAN_FAST: Extenal devices which need scanning or bus
+ * enumeration to find, but this enumeration happens quickly, typically under
+ * 100ms
+ * @BOOTDEVP_5_SCAN_SLOW: Extenal devices which need scanning or bus
+ * enumeration to find. The enumeration takes significant fraction of a second
+ * to complete
+ * @BOOTDEVP_6_NET_BASE: Basic network devices which are quickly and easily
+ * available. Typically used for an internal Ethernet device
+ * @BOOTDEVP_7_NET_FALLBACK: Secondary network devices which require extra time
+ * to start up, or are less desirable. Typically used for secondary Ethernet
+ * devices. Note that USB ethernet devices are found during USB enumeration,
+ * so do not use this priority
*/
enum bootdev_prio_t {
- BOOTDEVP_0_INTERNAL_FAST = 10,
- BOOTDEVP_1_INTERNAL_SLOW = 20,
- BOOTDEVP_2_SCAN_FAST = 30,
- BOOTDEVP_3_SCAN_SLOW = 40,
- BOOTDEVP_4_NET_BASE = 50,
- BOOTDEVP_5_NET_FALLBACK = 60,
- BOOTDEVP_6_SYSTEM = 70,
+ BOOTDEVP_0_NONE,
+ BOOTDEVP_1_PRE_SCAN,
+ BOOTDEVP_2_INTERNAL_FAST,
+ BOOTDEVP_3_INTERNAL_SLOW,
+ BOOTDEVP_4_SCAN_FAST,
+ BOOTDEVP_5_SCAN_SLOW,
+ BOOTDEVP_6_NET_BASE,
+ BOOTDEVP_7_NET_FALLBACK,
BOOTDEVP_COUNT,
};
+struct bootdev_hunter;
+
+/**
+ * bootdev_hunter_func - function to probe for bootdevs of a given type
+ *
+ * This should hunt around for bootdevs of the given type, binding them as it
+ * finds them. This may involve bus enumeration, etc.
+ *
+ * @info: Info structure describing this hunter
+ * @show: true to show information from the hunter
+ * Returns: 0 if OK, -ve on error
+ */
+typedef int (*bootdev_hunter_func)(struct bootdev_hunter *info, bool show);
+
+/**
+ * struct bootdev_hunter - information about how to hunt for bootdevs
+ *
+ * @prio: Scanning priority of this hunter
+ * @uclass: Uclass ID for the media associated with this bootdev
+ * @drv: bootdev driver for the things found by this hunter
+ * @hunt: Function to call to hunt for bootdevs of this type (NULL if none)
+ *
+ * Some bootdevs are not visible until other devices are enumerated. For
+ * example, USB bootdevs only appear when the USB bus is enumerated.
+ *
+ * On the other hand, we don't always want to enumerate all the buses just to
+ * find the first valid bootdev. Ideally we want to work through them in
+ * priority order, so that the fastest bootdevs are discovered first.
+ *
+ * This struct holds information about the bootdev so we can determine the probe
+ * order and how to hunt for bootdevs of this type
+ */
+struct bootdev_hunter {
+ enum bootdev_prio_t prio;
+ enum uclass_id uclass;
+ struct driver *drv;
+ bootdev_hunter_func hunt;
+};
+
+/* declare a new bootdev hunter */
+#define BOOTDEV_HUNTER(__name) \
+ ll_entry_declare(struct bootdev_hunter, __name, bootdev_hunter)
+
+/* access a bootdev hunter by name */
+#define BOOTDEV_HUNTER_GET(__name) \
+ ll_entry_get(struct bootdev_hunter, __name, bootdev_hunter)
+
/**
* struct bootdev_uc_plat - uclass information about a bootdev
*
@@ -50,7 +119,10 @@ struct bootdev_uc_plat {
/** struct bootdev_ops - Operations for the bootdev uclass */
struct bootdev_ops {
/**
- * get_bootflow() - get a bootflow
+ * get_bootflow() - get a bootflow (optional)
+ *
+ * If this is NULL then the default implementaton is used, which is
+ * default_get_bootflow()
*
* @dev: Bootflow device to check
* @iter: Provides current dev, part, method to get. Should update
@@ -171,40 +243,136 @@ int bootdev_next_bootflow(struct bootflow **bflowp);
* @label: Label to look up (e.g. "mmc1" or "mmc0")
* @devp: Returns the bootdev device found, or NULL if none (note it does not
* return the media device, but its bootdev child)
+ * @method_flagsp: If non-NULL, returns any flags implied by the label
+ * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
* Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
- * -ENOENT if there is no device with that number
+ * -ENOENT if there is no device with that number
*/
-int bootdev_find_by_label(const char *label, struct udevice **devp);
+int bootdev_find_by_label(const char *label, struct udevice **devp,
+ int *method_flagsp);
/**
* bootdev_find_by_any() - Find a bootdev by name, label or sequence
*
* @name: name (e.g. "mmc2.bootdev"), label ("mmc2"), or sequence ("2") to find
* @devp: returns the device found, on success
- * Return: 0 if OK, -ve on error
+ * @method_flagsp: If non-NULL, returns any flags implied by the label
+ * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
+ * Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
+ * -ENOENT if there is no device with that number
*/
-int bootdev_find_by_any(const char *name, struct udevice **devp);
+int bootdev_find_by_any(const char *name, struct udevice **devp,
+ int *method_flagsp);
/**
- * bootdev_setup_iter_order() - Set up the ordering of bootdevs to scan
- *
- * This sets up the ordering information in @iter, based on the priority of each
- * bootdev and the bootdev-order property in the bootstd node
+ * bootdev_setup_iter() - Set up iteration through bootdevs
*
- * If a single device is requested, no ordering is needed
+ * This sets up the an interation, based on the provided device or label. If
+ * neither is provided, the iteration is based on the priority of each bootdev,
+ * the * bootdev-order property in the bootstd node (or the boot_targets env
+ * var).
*
* @iter: Iterator to update with the order
+ * @label: label to scan, or NULL to scan all
* @devp: On entry, *devp is NULL to scan all, otherwise this is the (single)
* device to scan. Returns the first device to use, which is the passed-in
* @devp if it was non-NULL
+ * @method_flagsp: If non-NULL, returns any flags implied by the label
+ * (enum bootflow_meth_flags_t), 0 if none
* Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve
* on other error
*/
-int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp);
+int bootdev_setup_iter(struct bootflow_iter *iter, const char *label,
+ struct udevice **devp, int *method_flagsp);
+
+/**
+ * bootdev_list_hunters() - List the available bootdev hunters
+ *
+ * These provide a way to find new bootdevs by enumerating buses, etc. This
+ * function lists the available hunters
+ *
+ * @std: Pointer to bootstd private info
+ */
+void bootdev_list_hunters(struct bootstd_priv *std);
+
+/**
+ * bootdev_hunt() - Hunt for bootdevs matching a particular spec
+ *
+ * This runs the selected hunter (or all if @spec is NULL) to try to find new
+ * bootdevs.
+ *
+ * @spec: Spec to match, e.g. "mmc0", or NULL for any. If provided, this must
+ * match a uclass name so that the hunter can be determined. Any trailing number
+ * is ignored
+ * @show: true to show each hunter before using it
+ * Returns: 0 if OK, -ve on error
+ */
+int bootdev_hunt(const char *spec, bool show);
+
+/**
+ * bootdev_hunt_prio() - Hunt for bootdevs of a particular priority
+ *
+ * This runs all hunters which can find bootdevs of the given priority.
+ *
+ * @prio: Priority to use
+ * @show: true to show each hunter as it is used
+ * Returns: 0 if OK, -ve on error
+ */
+int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show);
+
+/**
+ * bootdev_hunt_and_find_by_label() - Hunt for bootdevs by label
+ *
+ * Runs the hunter for the label, then tries to find the bootdev, possible
+ * created by the hunter
+ *
+ * @label: Label to look up (e.g. "mmc1" or "mmc0")
+ * @devp: Returns the bootdev device found, or NULL if none (note it does not
+ * return the media device, but its bootdev child)
+ * @method_flagsp: If non-NULL, returns any flags implied by the label
+ * (enum bootflow_meth_flags_t), 0 if none. Unset if function fails
+ * Return: 0 if OK, -EINVAL if the uclass is not supported by this board,
+ * -ENOENT if there is no device with that number
+ */
+int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp,
+ int *method_flagsp);
+
+/**
+ * bootdev_next_label() - Move to the next bootdev in the label sequence
+ *
+ * Looks through the remaining labels until it finds one that matches a bootdev.
+ * Bootdev scanners are used as needed. For example a label "mmc1" results in
+ * running the "mmc" bootdrv.
+ *
+ * @iter: Interation info, containing iter->cur_label
+ * @devp: New bootdev found, if any was found
+ * @method_flagsp: If non-NULL, returns any flags implied by the label
+ * (enum bootflow_meth_flags_t), 0 if none
+ * Returns 0 if OK, -ENODEV if no bootdev was found
+ */
+int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp,
+ int *method_flagsp);
+
+/**
+ * bootdev_next_prio() - Find the next bootdev in priority order
+ *
+ * This moves @devp to the next bootdev with the current priority. If there is
+ * none, then it moves to the next priority and scans for new bootdevs there.
+ *
+ * @iter: Interation info, containing iter->cur_prio
+ * @devp: On entry this is the previous bootdev that was considered. On exit
+ * this is the new bootdev, if any was found
+ * Returns 0 on success (*devp is updated), -ENODEV if there are no more
+ * bootdevs at any priority
+ */
+int bootdev_next_prio(struct bootflow_iter *iter, struct udevice **devp);
#if CONFIG_IS_ENABLED(BOOTSTD)
/**
- * bootdev_setup_for_dev() - Bind a new bootdev device
+ * bootdev_setup_for_dev() - Bind a new bootdev device (deprecated)
+ *
+ * Please use bootdev_setup_sibling_blk() instead since it supports multiple
+ * (child) block devices for each media device.
*
* Creates a bootdev device as a child of @parent. This should be called from
* the driver's bind() method or its uclass' post_bind() method.
diff --git a/include/bootflow.h b/include/bootflow.h
index c201246c6de..f516bf8dea4 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -7,12 +7,17 @@
#ifndef __bootflow_h
#define __bootflow_h
+#include <bootdev.h>
#include <dm/ofnode_decl.h>
#include <linux/list.h>
struct bootstd_priv;
struct expo;
+enum {
+ BOOTFLOW_MAX_USED_DEVS = 16,
+};
+
/**
* enum bootflow_state_t - states that a particular bootflow can be in
*
@@ -43,7 +48,7 @@ enum bootflow_state_t {
* @glob_node: Points to siblings in the global list (all bootdev)
* @dev: Bootdevice device which produced this bootflow
* @blk: Block device which contains this bootflow, NULL if this is a network
- * device
+ * device or sandbox 'host' device
* @part: Partition number (0 for whole device)
* @fs_type: Filesystem type (FS_TYPE...) if this is fixed by the media, else 0.
* For example, the sandbox host-filesystem bootdev sets this to
@@ -60,6 +65,9 @@ enum bootflow_state_t {
* @err: Error number received (0 if OK)
* @os_name: Name of the OS / distro being booted, or NULL if not known
* (allocated)
+ * @fdt_fname: Filename of FDT file
+ * @fdt_size: Size of FDT file
+ * @fdt_addr: Address of loaded fdt
*/
struct bootflow {
struct list_head bm_node;
@@ -79,23 +87,64 @@ struct bootflow {
int size;
int err;
char *os_name;
+ char *fdt_fname;
+ int fdt_size;
+ ulong fdt_addr;
};
/**
* enum bootflow_flags_t - flags for the bootflow iterator
*
* @BOOTFLOWF_FIXED: Only used fixed/internal media
- * @BOOTFLOWF_SHOW: Show each bootdev before scanning it
+ * @BOOTFLOWF_SHOW: Show each bootdev before scanning it; show each hunter
+ * before using it
* @BOOTFLOWF_ALL: Return bootflows with errors as well
- * @BOOTFLOWF_SINGLE_DEV: Just scan one bootmeth
- * @BOOTFLOWF_SKIP_GLOBAL: Don't scan global bootmeths
+ * @BOOTFLOWF_HUNT: Hunt for new bootdevs using the bootdrv hunters
+ *
+ * Internal flags:
+ * @BOOTFLOWF_SINGLE_DEV: (internal) Just scan one bootdev
+ * @BOOTFLOWF_SKIP_GLOBAL: (internal) Don't scan global bootmeths
+ * @BOOTFLOWF_SINGLE_UCLASS: (internal) Keep scanning through all devices in
+ * this uclass (used with things like "mmc")
+ * @BOOTFLOWF_SINGLE_MEDIA: (internal) Scan one media device in the uclass (used
+ * with things like "mmc1")
*/
enum bootflow_flags_t {
BOOTFLOWF_FIXED = 1 << 0,
BOOTFLOWF_SHOW = 1 << 1,
BOOTFLOWF_ALL = 1 << 2,
- BOOTFLOWF_SINGLE_DEV = 1 << 3,
- BOOTFLOWF_SKIP_GLOBAL = 1 << 4,
+ BOOTFLOWF_HUNT = 1 << 3,
+
+ /*
+ * flags used internally by standard boot - do not set these when
+ * calling bootflow_scan_bootdev() etc.
+ */
+ BOOTFLOWF_SINGLE_DEV = 1 << 16,
+ BOOTFLOWF_SKIP_GLOBAL = 1 << 17,
+ BOOTFLOWF_SINGLE_UCLASS = 1 << 18,
+ BOOTFLOWF_SINGLE_MEDIA = 1 << 19,
+};
+
+/**
+ * enum bootflow_meth_flags_t - flags controlling which bootmeths are used
+ *
+ * Used during iteration, e.g. by bootdev_find_by_label(), to determine which
+ * bootmeths are used for the current bootdev. The flags reset when the bootdev
+ * changes
+ *
+ * @BOOTFLOW_METHF_DHCP_ONLY: Only use dhcp (scripts and EFI)
+ * @BOOTFLOW_METHF_PXE_ONLY: Only use pxe (PXE boot)
+ * @BOOTFLOW_METHF_SINGLE_DEV: Scan only a single bootdev (used for labels like
+ * "3"). This is used if a sequence number is provided instead of a label
+ * @BOOTFLOW_METHF_SINGLE_UCLASS: Scan all bootdevs in this one uclass (used
+ * with things like "mmc"). If this is not set, then the bootdev has an integer
+ * value in the label (like "mmc2")
+ */
+enum bootflow_meth_flags_t {
+ BOOTFLOW_METHF_DHCP_ONLY = 1 << 0,
+ BOOTFLOW_METHF_PXE_ONLY = 1 << 1,
+ BOOTFLOW_METHF_SINGLE_DEV = 1 << 2,
+ BOOTFLOW_METHF_SINGLE_UCLASS = 1 << 3,
};
/**
@@ -118,25 +167,31 @@ enum bootflow_flags_t {
* @flags: Flags to use (see enum bootflow_flags_t). If BOOTFLOWF_GLOBAL_FIRST is
* enabled then the global bootmeths are being scanned, otherwise we have
* moved onto the bootdevs
- * @dev: Current bootdev, NULL if none
+ * @dev: Current bootdev, NULL if none. This is only ever updated in
+ * bootflow_iter_set_dev()
* @part: Current partition number (0 for whole device)
* @method: Current bootmeth
* @max_part: Maximum hardware partition number in @dev, 0 if there is no
* partition table
+ * @first_bootable: First bootable partition, or 0 if none
* @err: Error obtained from checking the last iteration. This is used to skip
* forward (e.g. to skip the current partition because it is not valid)
* -ESHUTDOWN: try next bootdev
- * @num_devs: Number of bootdevs in @dev_order
- * @cur_dev: Current bootdev number, an index into @dev_order[]
- * @dev_order: List of bootdevs to scan, in order of priority. The scan starts
- * with the first one on the list
+ * @num_devs: Number of bootdevs in @dev_used
+ * @max_devs: Maximum number of entries in @dev_used
+ * @dev_used: List of bootdevs used during iteration
+ * @labels: List of labels to scan for bootdevs
+ * @cur_label: Current label being processed
* @num_methods: Number of bootmeth devices in @method_order
* @cur_method: Current method number, an index into @method_order
* @first_glob_method: First global method, if any, else -1
+ * @cur_prio: Current priority being scanned
* @method_order: List of bootmeth devices to use, in order. The normal methods
* appear first, then the global ones, if any
* @doing_global: true if we are iterating through the global bootmeths (which
* happens before the normal ones)
+ * @method_flags: flags controlling which methods should be used for this @dev
+ * (enum bootflow_meth_flags_t)
*/
struct bootflow_iter {
int flags;
@@ -144,15 +199,20 @@ struct bootflow_iter {
int part;
struct udevice *method;
int max_part;
+ int first_bootable;
int err;
int num_devs;
- int cur_dev;
- struct udevice **dev_order;
+ int max_devs;
+ struct udevice *dev_used[BOOTFLOW_MAX_USED_DEVS];
+ const char *const *labels;
+ int cur_label;
int num_methods;
int cur_method;
int first_glob_method;
+ enum bootdev_prio_t cur_prio;
struct udevice **method_order;
bool doing_global;
+ int method_flags;
};
/**
@@ -197,36 +257,23 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter,
const struct udevice *bmeth);
/**
- * bootflow_scan_bootdev() - find the first bootflow in a bootdev
+ * bootflow_scan_first() - find the first bootflow for a device or label
*
* If @flags includes BOOTFLOWF_ALL then bootflows with errors are returned too
*
* @dev: Boot device to scan, NULL to work through all of them until it
* finds one that can supply a bootflow
+ * @label: Label to control the scan, NULL to work through all devices
+ * until it finds one that can supply a bootflow
* @iter: Place to store private info (inited by this call)
- * @flags: Flags for iterator (enum bootflow_flags_t)
+ * @flags: Flags for iterator (enum bootflow_flags_t). Note that if @dev
+ * is NULL, then BOOTFLOWF_SKIP_GLOBAL is set automatically by this function
* @bflow: Place to put the bootflow if found
* Return: 0 if found, -ENODEV if no device, other -ve on other error
* (iteration can continue)
*/
-int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter,
- int flags, struct bootflow *bflow);
-
-/**
- * bootflow_scan_first() - find the first bootflow
- *
- * This works through the available bootdev devices until it finds one that
- * can supply a bootflow. It then returns that
- *
- * If @flags includes BOOTFLOWF_ALL then bootflows with errors are returned too
- *
- * @iter: Place to store private info (inited by this call), with
- * @flags: Flags for bootdev (enum bootflow_flags_t)
- * @bflow: Place to put the bootflow if found
- * Return: 0 if found, -ENODEV if no device, other -ve on other error (iteration
- * can continue)
- */
-int bootflow_scan_first(struct bootflow_iter *iter, int flags,
+int bootflow_scan_first(struct udevice *dev, const char *label,
+ struct bootflow_iter *iter, int flags,
struct bootflow *bflow);
/**
@@ -312,33 +359,42 @@ const char *bootflow_state_get_name(enum bootflow_state_t state);
void bootflow_remove(struct bootflow *bflow);
/**
- * bootflow_iter_uses_blk_dev() - Check that a bootflow uses a block device
+ * bootflow_iter_check_blk() - Check that a bootflow uses a block device
*
* This checks the bootdev in the bootflow to make sure it uses a block device
*
* Return: 0 if OK, -ENOTSUPP if some other device is used (e.g. ethernet)
*/
-int bootflow_iter_uses_blk_dev(const struct bootflow_iter *iter);
+int bootflow_iter_check_blk(const struct bootflow_iter *iter);
+
+/**
+ * bootflow_iter_check_sf() - Check that a bootflow uses SPI FLASH
+ *
+ * This checks the bootdev in the bootflow to make sure it uses SPI flash
+ *
+ * Return: 0 if OK, -ENOTSUPP if some other device is used (e.g. ethernet)
+ */
+int bootflow_iter_check_sf(const struct bootflow_iter *iter);
/**
- * bootflow_iter_uses_network() - Check that a bootflow uses a network device
+ * bootflow_iter_check_net() - Check that a bootflow uses a network device
*
* This checks the bootdev in the bootflow to make sure it uses a network
* device
*
* Return: 0 if OK, -ENOTSUPP if some other device is used (e.g. MMC)
*/
-int bootflow_iter_uses_network(const struct bootflow_iter *iter);
+int bootflow_iter_check_net(const struct bootflow_iter *iter);
/**
- * bootflow_iter_uses_system() - Check that a bootflow uses the bootstd device
+ * bootflow_iter_check_system() - Check that a bootflow uses the bootstd device
*
* This checks the bootdev in the bootflow to make sure it uses the bootstd
* device
*
* Return: 0 if OK, -ENOTSUPP if some other device is used (e.g. MMC)
*/
-int bootflow_iter_uses_system(const struct bootflow_iter *iter);
+int bootflow_iter_check_system(const struct bootflow_iter *iter);
/**
* bootflow_menu_new() - Create a new bootflow menu
diff --git a/include/bootmeth.h b/include/bootmeth.h
index 669b14ce81e..b12dfd42c90 100644
--- a/include/bootmeth.h
+++ b/include/bootmeth.h
@@ -88,6 +88,22 @@ struct bootmeth_ops {
int (*read_bootflow)(struct udevice *dev, struct bootflow *bflow);
/**
+ * set_bootflow() - set the bootflow for a device
+ *
+ * This provides a bootflow file to the bootmeth, to see if it is valid.
+ * If it is, the bootflow is set up accordingly.
+ *
+ * @dev: Bootmethod device to use
+ * @bflow: On entry, provides bootdev.
+ * Returns updated bootflow if found
+ * @buf: Buffer containing the possible bootflow file
+ * @size: Size of file
+ * Return: 0 if OK, -ve on error
+ */
+ int (*set_bootflow)(struct udevice *dev, struct bootflow *bflow,
+ char *buf, int size);
+
+ /**
* read_file() - read a file needed for a bootflow
*
* Read a file from the same place as the bootflow came from
@@ -174,6 +190,23 @@ int bootmeth_check(struct udevice *dev, struct bootflow_iter *iter);
int bootmeth_read_bootflow(struct udevice *dev, struct bootflow *bflow);
/**
+ * bootmeth_set_bootflow() - set the bootflow for a device
+ *
+ * This provides a bootflow file to the bootmeth, to see if it is valid.
+ * If it is, the bootflow is set up accordingly.
+ *
+ * @dev: Bootmethod device to use
+ * @bflow: On entry, provides bootdev.
+ * Returns updated bootflow if found
+ * @buf: Buffer containing the possible bootflow file (must be allocated
+ * by caller to @size + 1 bytes)
+ * @size: Size of file
+ * Return: 0 if OK, -ve on error
+ */
+int bootmeth_set_bootflow(struct udevice *dev, struct bootflow *bflow,
+ char *buf, int size);
+
+/**
* bootmeth_read_file() - read a file needed for a bootflow
*
* Read a file from the same place as the bootflow came from
@@ -240,7 +273,7 @@ int bootmeth_set_order(const char *order_str);
* caller before reading the file.
*
* @bflow: Information about file to try
- * @desc: Block descriptor to read from
+ * @desc: Block descriptor to read from (NULL for sandbox host)
* @prefix: Filename prefix to prepend to @fname (NULL for none)
* @fname: Filename to read
* Return: 0 if OK, -ENOMEM if not enough memory to allocate bflow->fname,
diff --git a/include/bootstd.h b/include/bootstd.h
index 4fa0d531001..dddb3e15384 100644
--- a/include/bootstd.h
+++ b/include/bootstd.h
@@ -22,7 +22,10 @@ struct udevice;
* @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";
+ * being a bootdev label, e.g. "mmc2", "mmc1" (NULL terminated)
+ * @env_order: Order as specified by the boot_targets env var (or NULL if none),
+ * with each item being a bootdev label, e.g. "mmc2", "mmc1" (NULL
+ * terminated)
* @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
@@ -30,10 +33,13 @@ struct udevice;
* @bootmeth_order: List of bootmeth devices to use, in order, NULL-terminated
* @vbe_bootmeth: Currently selected VBE bootmeth, NULL if none
* @theme: Node containing the theme information
+ * @hunters_used: Bitmask of used hunters, indexed by their position in the
+ * linker list. The bit is set if the hunter has been used already
*/
struct bootstd_priv {
const char **prefixes;
const char **bootdev_order;
+ const char **env_order;
struct udevice *cur_bootdev;
struct bootflow *cur_bootflow;
struct list_head glob_head;
@@ -41,6 +47,7 @@ struct bootstd_priv {
struct udevice **bootmeth_order;
struct udevice *vbe_bootmeth;
ofnode theme;
+ uint hunters_used;
};
/**
@@ -51,9 +58,13 @@ struct bootstd_priv {
* 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
+ * @dev: bootstd device
+ * @okp: returns true if OK, false if out of memory
+ * Return: list of string pointers, terminated by NULL; or NULL if no boot
+ * order. Note that this returns NULL in the case of an empty list
*/
-const char *const *const bootstd_get_bootdev_order(struct udevice *dev);
+const char *const *const bootstd_get_bootdev_order(struct udevice *dev,
+ bool *okp);
/**
* bootstd_get_prefixes() - Get the filename-prefixes list
diff --git a/include/configs/rk3399_common.h b/include/configs/rk3399_common.h
index 95cb27c8951..3ef9ffa2e9c 100644
--- a/include/configs/rk3399_common.h
+++ b/include/configs/rk3399_common.h
@@ -48,15 +48,12 @@
#define ROCKCHIP_DEVICE_SETTINGS
#endif
-#include <config_distro_bootcmd.h>
-#include <environment/distro/sf.h>
#define CFG_EXTRA_ENV_SETTINGS \
ENV_MEM_LAYOUT_SETTINGS \
"fdtfile=" CONFIG_DEFAULT_FDT_FILE "\0" \
"partitions=" PARTS_DEFAULT \
ROCKCHIP_DEVICE_SETTINGS \
- BOOTENV \
- BOOTENV_SF \
+ "boot_targets=" BOOT_TARGETS "\0" \
"altbootcmd=" \
"setenv boot_syslinux_conf extlinux/extlinux-rollback.conf;" \
"run distro_bootcmd\0"
diff --git a/include/configs/rockchip-common.h b/include/configs/rockchip-common.h
index 1f6b82f2d02..0b23e4c0433 100644
--- a/include/configs/rockchip-common.h
+++ b/include/configs/rockchip-common.h
@@ -65,12 +65,14 @@
BOOT_TARGET_PXE(func) \
BOOT_TARGET_DHCP(func) \
BOOT_TARGET_SF(func)
+#define BOOT_TARGETS "mmc1 mmc0 nvme scsi usb pxe dhcp spi"
#else
#define BOOT_TARGET_DEVICES(func) \
BOOT_TARGET_MMC(func) \
BOOT_TARGET_USB(func) \
BOOT_TARGET_PXE(func) \
BOOT_TARGET_DHCP(func)
+#define BOOT_TARGETS "mmc1 mmc0 usb pxe dhcp"
#endif
#ifdef CONFIG_ARM64
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 376f741cc2b..33e43c20db6 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -47,9 +47,9 @@ enum uclass_id {
UCLASS_CPU, /* CPU, typically part of an SoC */
UCLASS_CROS_EC, /* Chrome OS EC */
UCLASS_DISPLAY, /* Display (e.g. DisplayPort, HDMI) */
- UCLASS_DSI_HOST, /* Display Serial Interface host */
UCLASS_DMA, /* Direct Memory Access */
UCLASS_DSA, /* Distributed (Ethernet) Switch Architecture */
+ UCLASS_DSI_HOST, /* Display Serial Interface host */
UCLASS_ECDSA, /* Elliptic curve cryptographic device */
UCLASS_EFI_LOADER, /* Devices created by UEFI applications */
UCLASS_EFI_MEDIA, /* Devices provided by UEFI firmware */
@@ -101,6 +101,7 @@ enum uclass_id {
UCLASS_PINCTRL, /* Pinctrl (pin muxing/configuration) device */
UCLASS_PMIC, /* PMIC I/O device */
UCLASS_POWER_DOMAIN, /* (SoC) Power domains */
+ UCLASS_PVBLOCK, /* Xen virtual block device */
UCLASS_PWM, /* Pulse-width modulator */
UCLASS_PWRSEQ, /* Power sequence device */
UCLASS_QFW, /* QEMU firmware config device */
@@ -142,7 +143,6 @@ enum uclass_id {
UCLASS_W1, /* Dallas 1-Wire bus */
UCLASS_W1_EEPROM, /* one-wire EEPROMs */
UCLASS_WDT, /* Watchdog Timer driver */
- UCLASS_PVBLOCK, /* Xen virtual block device */
UCLASS_COUNT,
UCLASS_INVALID = -1,
diff --git a/include/dm/util.h b/include/dm/util.h
index e10c6060ce0..4bb49e9e8c0 100644
--- a/include/dm/util.h
+++ b/include/dm/util.h
@@ -26,8 +26,12 @@ struct list_head;
*/
int list_count_items(struct list_head *head);
-/* Dump out a tree of all devices */
-void dm_dump_tree(void);
+/**
+ * Dump out a tree of all devices
+ *
+ * @sort: Sort by uclass name
+ */
+void dm_dump_tree(bool sort);
/* Dump out a list of uclasses and their devices */
void dm_dump_uclass(void);
diff --git a/include/net.h b/include/net.h
index ee08f3307ec..399af5e0645 100644
--- a/include/net.h
+++ b/include/net.h
@@ -66,6 +66,21 @@ struct in_addr {
int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
/**
+ * dhcp_run() - Run DHCP on the current ethernet device
+ *
+ * This sets the autoload variable, then puts it back to similar to its original
+ * state (y, n or unset).
+ *
+ * @addr: Address to load the file into (0 if @autoload is false)
+ * @fname: Filename of file to load (NULL if @autoload is false or to use the
+ * default filename)
+ * @autoload: true to load the file, false to just get the network IP
+ * @return 0 if OK, -EINVAL if the environment failed, -ENOENT if ant file was
+ * not found
+ */
+int dhcp_run(ulong addr, const char *fname, bool autoload);
+
+/**
* An incoming packet handler.
* @param pkt pointer to the application packet
* @param dport destination UDP port
@@ -886,4 +901,20 @@ static inline struct in_addr env_get_ip(char *var)
*/
void reset_phy(void);
+#if CONFIG_IS_ENABLED(NET)
+/**
+ * eth_set_enable_bootdevs() - Enable or disable binding of Ethernet bootdevs
+ *
+ * These get in the way of bootstd testing, so are normally disabled by tests.
+ * This provide control of this setting. It only affects binding of Ethernet
+ * devices, so if that has already happened, this flag does nothing.
+ *
+ * @enable: true to enable binding of bootdevs when binding new Ethernet
+ * devices, false to disable it
+ */
+void eth_set_enable_bootdevs(bool enable);
+#else
+static inline void eth_set_enable_bootdevs(bool enable) {}
+#endif
+
#endif /* __NET_H__ */
diff --git a/include/part.h b/include/part.h
index 807370d9429..be75c735495 100644
--- a/include/part.h
+++ b/include/part.h
@@ -303,6 +303,14 @@ part_get_info_by_dev_and_name_or_num(const char *dev_iface,
}
#endif
+/**
+ * part_get_bootable() - Find the first bootable partition
+ *
+ * @desc: Block-device descriptor
+ * @return first bootable partition, or 0 if there is none
+ */
+int part_get_bootable(struct blk_desc *desc);
+
struct udevice;
/**
* part_create_block_devices - Create block devices for disk partitions
diff --git a/include/test/test.h b/include/test/test.h
index 4ad74614afc..838e3ce8a8f 100644
--- a/include/test/test.h
+++ b/include/test/test.h
@@ -71,6 +71,8 @@ enum {
* since it cannot access the flags.
*/
UT_TESTF_MANUAL = BIT(8),
+ UT_TESTF_ETH_BOOTDEV = BIT(9), /* enable Ethernet bootdevs */
+ UT_TESTF_SF_BOOTDEV = BIT(10), /* enable SPI flash bootdevs */
};
/**
@@ -169,4 +171,74 @@ static inline int test_load_other_fdt(struct unit_test_state *uts)
return ret;
}
+/**
+ * Control skipping of time delays
+ *
+ * Some tests have unnecessay time delays (e.g. USB). Allow these to be
+ * skipped to speed up testing
+ *
+ * @param skip_delays true to skip delays from now on, false to honour delay
+ * requests
+ */
+static inline void test_set_skip_delays(bool skip_delays)
+{
+#ifdef CONFIG_SANDBOX
+ state_set_skip_delays(skip_delays);
+#endif
+}
+
+/**
+ * test_set_eth_enable() - Enable / disable Ethernet
+ *
+ * Allows control of whether Ethernet packets are actually send/received
+ *
+ * @enable: true to enable Ethernet, false to disable
+ */
+static inline void test_set_eth_enable(bool enable)
+{
+#ifdef CONFIG_SANDBOX
+ sandbox_set_eth_enable(enable);
+#endif
+}
+
+/* Allow ethernet to be disabled for testing purposes */
+static inline bool test_eth_enabled(void)
+{
+ bool enabled = true;
+
+#ifdef CONFIG_SANDBOX
+ enabled = sandbox_eth_enabled();
+#endif
+ return enabled;
+}
+
+/* Allow ethernet bootdev to be ignored for testing purposes */
+static inline bool test_eth_bootdev_enabled(void)
+{
+ bool enabled = true;
+
+#ifdef CONFIG_SANDBOX
+ enabled = sandbox_eth_enabled();
+#endif
+ return enabled;
+}
+
+/* Allow SPI flash bootdev to be ignored for testing purposes */
+static inline bool test_sf_bootdev_enabled(void)
+{
+ bool enabled = true;
+
+#ifdef CONFIG_SANDBOX
+ enabled = sandbox_sf_bootdev_enabled();
+#endif
+ return enabled;
+}
+
+static inline void test_sf_set_enable_bootdevs(bool enable)
+{
+#ifdef CONFIG_SANDBOX
+ sandbox_sf_set_enable_bootdevs(enable);
+#endif
+}
+
#endif /* __TEST_TEST_H */
diff --git a/include/vsprintf.h b/include/vsprintf.h
index e006af200fd..ed8a060ee17 100644
--- a/include/vsprintf.h
+++ b/include/vsprintf.h
@@ -329,6 +329,30 @@ char *strmhz(char *buf, unsigned long hz);
void str_to_upper(const char *in, char *out, size_t len);
/**
+ * str_to_list() - Convert a string to a list of string pointers
+ *
+ * Splits a string containing space-delimited substrings into a number of
+ * separate strings, e.g. "this is" becomes {"this", "is", NULL}. If @instr is
+ * empty then this returns just {NULL}. The string should have only a single
+ * space between items, with no leading or trailing spaces.
+ *
+ * @instr: String to process (this is alloced by this function)
+ * Returns: List of string pointers, terminated by NULL. Each entry points to
+ * a string. If @instr is empty, the list consists just of a single NULL entry.
+ * Note that the first entry points to the alloced string.
+ * Returns NULL if out of memory
+ */
+const char **str_to_list(const char *instr);
+
+/**
+ * str_free_list() - Free a string list
+ *
+ * @ptr: String list to free, as created by str_to_list(). This can also be
+ * NULL, in which case the function does nothing
+ */
+void str_free_list(const char **ptr);
+
+/**
* vsscanf - Unformat a buffer into a list of arguments
* @inp: input buffer
* @fmt0: format of buffer