barebox substituting its own device tree in place of a missing kernel is often not what the user intended. Add a config option to disable this, so users notice right away that they didn't supply a kernel device tree.
Signed-off-by: Ahmad Fatoum <a.fat...@barebox.org> --- arch/arm/lib32/bootm.c | 2 +- arch/arm/lib32/bootu.c | 11 ++++++++--- arch/arm/lib32/bootz.c | 9 ++++++--- arch/powerpc/lib/ppclinux.c | 2 +- common/Kconfig | 18 ++++++++++++++++++ common/bootm.c | 9 +++------ include/of.h | 25 +++++++++++++++++++++++-- 7 files changed, 60 insertions(+), 16 deletions(-) diff --git a/arch/arm/lib32/bootm.c b/arch/arm/lib32/bootm.c index 32af112ae8c8..963c83051de0 100644 --- a/arch/arm/lib32/bootm.c +++ b/arch/arm/lib32/bootm.c @@ -428,7 +428,7 @@ static int do_bootz_linux_fdt(int fd, struct image_data *data, void **outfdt) pr_err("unable to unflatten devicetree\n"); goto err_free; } - *outfdt = of_get_fixed_tree(root); + *outfdt = of_get_fixed_tree_for_boot(root); if (!*outfdt) { pr_err("Unable to get fixed tree\n"); ret = -EINVAL; diff --git a/arch/arm/lib32/bootu.c b/arch/arm/lib32/bootu.c index 31c3c56cc597..4b0f495aea5f 100644 --- a/arch/arm/lib32/bootu.c +++ b/arch/arm/lib32/bootu.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only +#define pr_fmt(fmt) "bootu: " fmt + #include <common.h> #include <command.h> #include <fs.h> @@ -24,9 +26,12 @@ static int do_bootu(int argc, char *argv[]) if (!kernel) kernel = (void *)simple_strtoul(argv[1], NULL, 0); -#ifdef CONFIG_OFTREE - oftree = of_get_fixed_tree(NULL); -#endif + oftree = of_get_fixed_tree_for_boot(NULL); + if (!oftree) { + pr_err("No devicetree given.\n"); + return -EINVAL; + } + ret = of_overlay_load_firmware(); if (ret) return ret; diff --git a/arch/arm/lib32/bootz.c b/arch/arm/lib32/bootz.c index 8e8b0d225ecf..ab275c367711 100644 --- a/arch/arm/lib32/bootz.c +++ b/arch/arm/lib32/bootz.c @@ -110,9 +110,12 @@ static int do_bootz(int argc, char *argv[]) } printf("loaded zImage from %s with size %d\n", argv[1], end); -#ifdef CONFIG_OFTREE - oftree = of_get_fixed_tree(NULL); -#endif + oftree = of_get_fixed_tree_for_boot(NULL); + if (!oftree) { + printf("No devicetree given.\n"); + return -EINVAL; + } + ret = of_overlay_load_firmware(); if (ret) return ret; diff --git a/arch/powerpc/lib/ppclinux.c b/arch/powerpc/lib/ppclinux.c index 6b00c2ee5756..564086482e5f 100644 --- a/arch/powerpc/lib/ppclinux.c +++ b/arch/powerpc/lib/ppclinux.c @@ -60,7 +60,7 @@ static int do_bootm_linux(struct image_data *data) if (ret) return ret; - fdt = of_get_fixed_tree(data->of_root_node); + fdt = of_get_fixed_tree_for_boot(data->of_root_node); if (!fdt) { pr_err("bootm: No devicetree given.\n"); return -EINVAL; diff --git a/common/Kconfig b/common/Kconfig index 0a7d9aee3abe..da19cb8d9980 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -642,6 +642,24 @@ config BOOTM_OFTREE -o DTS specify device tree +config BOOTM_OFTREE_FALLBACK + def_bool y + # We intentionally don't depend on BOOTM_OFTREE, because many boards + # don't enable it and instead rely on OFTREE being selected... + depends on BOOTM && HAVE_ARCH_BOOTM_OFTREE && OFTREE + prompt "pass along barebox' own DT as fallback" + help + Say y here to substitute in the barebox device tree, when no kernel + device tree was supplied. If unsure, say n. + + It's recommended to boot a kernel with the device tree that was + shipped with it as DT binding breakage is not an infrequent + occurrence. + + This especially applies to A/B boot setups, where each kernel + should have its own DT, so fallback restores the system cleanly + to the old state. + config BOOTM_UIMAGE def_bool y prompt "support the legacy uImage format" diff --git a/common/bootm.c b/common/bootm.c index 4aebc8a66abd..b98dc2715914 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -484,14 +484,11 @@ void *bootm_get_devicetree(struct image_data *data) } } else { - struct device_node *root = of_get_root_node(); - - if (!root) + data->of_root_node = of_dup_root_node_for_boot(); + if (!data->of_root_node) return NULL; - data->of_root_node = of_dup(root); - - if (bootm_verbose(data) > 1 && data->of_root_node) + if (bootm_verbose(data) > 1) printf("using internal devicetree\n"); } diff --git a/include/of.h b/include/of.h index e46d410d3651..a9bd37fdca2f 100644 --- a/include/of.h +++ b/include/of.h @@ -80,8 +80,6 @@ int of_add_initrd(struct device_node *root, resource_size_t start, struct fdt_header *fdt_get_tree(void); -struct fdt_header *of_get_fixed_tree(const struct device_node *node); - /* Helper to read a big number; size is in cells (not bytes) */ static inline u64 of_read_number(const __be32 *cell, int size) { @@ -325,6 +323,7 @@ extern const char *of_parse_phandle_and_get_alias_from(struct device_node *root, int index); extern struct device_node *of_get_root_node(void); +extern struct fdt_header *of_get_fixed_tree(const struct device_node *node); extern int of_set_root_node(struct device_node *node); extern int barebox_register_of(struct device_node *root); extern int barebox_register_fdt(const void *dtb); @@ -467,6 +466,11 @@ static inline struct device_node *of_get_root_node(void) return NULL; } +static inline struct fdt_header *of_get_fixed_tree(const struct device_node *node) +{ + return NULL; +} + static inline int of_set_root_node(struct device_node *node) { return -ENOSYS; @@ -1354,6 +1358,23 @@ static inline struct device_node *of_find_root_node(struct device_node *node) return node; } + +static inline struct fdt_header *of_get_fixed_tree_for_boot(const struct device_node *node) +{ + if (!IS_ENABLED(CONFIG_BOOTM_OFTREE_FALLBACK) && !node) + return NULL; + + return of_get_fixed_tree(node); +} + +static inline struct device_node *of_dup_root_node_for_boot(void) +{ + if (!IS_ENABLED(CONFIG_BOOTM_OFTREE_FALLBACK)) + return NULL; + + return of_dup(of_get_root_node()); +} + struct of_overlay_filter { bool (*filter_filename)(struct of_overlay_filter *, const char *filename); bool (*filter_content)(struct of_overlay_filter *, struct device_node *); -- 2.39.5