summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/sandbox/dts/sandbox.dtsi13
-rw-r--r--arch/sandbox/dts/test.dts15
-rw-r--r--arch/sandbox/include/asm/test.h11
-rw-r--r--arch/x86/lib/bios.c12
-rw-r--r--arch/x86/lib/coreboot_table.c2
-rw-r--r--arch/x86/lib/fsp/fsp_graphics.c4
-rw-r--r--boot/Kconfig29
-rw-r--r--boot/Makefile5
-rw-r--r--boot/bootdev-uclass.c15
-rw-r--r--boot/bootflow.c63
-rw-r--r--boot/bootmeth-uclass.c105
-rw-r--r--boot/bootmeth_distro.c14
-rw-r--r--boot/bootmeth_efi_mgr.c35
-rw-r--r--boot/bootstd-uclass.c13
-rw-r--r--boot/image-fdt.c11
-rw-r--r--boot/system_bootdev.c66
-rw-r--r--boot/vbe.c119
-rw-r--r--boot/vbe_simple.c315
-rw-r--r--cmd/Kconfig10
-rw-r--r--cmd/Makefile1
-rw-r--r--cmd/bootflow.c12
-rw-r--r--cmd/bootmeth.c4
-rw-r--r--cmd/elf.c2
-rw-r--r--cmd/read.c3
-rw-r--r--cmd/vbe.c87
-rw-r--r--common/event.c3
-rw-r--r--configs/sandbox_flattree_defconfig2
-rw-r--r--doc/develop/bootstd.rst89
-rw-r--r--doc/develop/driver-model/livetree.rst60
-rw-r--r--doc/develop/index.rst1
-rw-r--r--doc/develop/vbe.rst26
-rw-r--r--doc/usage/cmd/bootmeth.rst9
-rw-r--r--drivers/bios_emulator/atibios.c18
-rw-r--r--drivers/core/of_access.c57
-rw-r--r--drivers/core/ofnode.c81
-rw-r--r--drivers/pci/pci_rom.c14
-rw-r--r--drivers/video/broadwell_igd.c4
-rw-r--r--drivers/video/coreboot.c4
-rw-r--r--drivers/video/efi.c4
-rw-r--r--drivers/video/ivybridge_igd.c4
-rw-r--r--drivers/video/vesa.c4
-rw-r--r--include/bios_emul.h6
-rw-r--r--include/bootflow.h20
-rw-r--r--include/bootmeth.h65
-rw-r--r--include/bootstd.h2
-rw-r--r--include/dm/of_access.h22
-rw-r--r--include/dm/ofnode.h122
-rw-r--r--include/dm/ofnode_decl.h85
-rw-r--r--include/event.h21
-rw-r--r--include/of_live.h16
-rw-r--r--include/test/test.h2
-rw-r--r--include/vbe.h147
-rw-r--r--include/vesa.h116
-rw-r--r--lib/efi_loader/Kconfig1
-rw-r--r--lib/elf.c2
-rw-r--r--lib/of_live.c14
-rw-r--r--test/boot/Makefile4
-rw-r--r--test/boot/bootflow.c106
-rw-r--r--test/boot/bootmeth.c55
-rw-r--r--test/boot/vbe_simple.c115
-rw-r--r--test/dm/ofnode.c132
-rw-r--r--test/dm/test-fdt.c53
-rw-r--r--test/py/tests/test_event_dump.py1
-rw-r--r--test/test-main.c7
64 files changed, 1930 insertions, 530 deletions
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index aa22b8765c8..56e6b38bfa7 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -12,6 +12,19 @@
chosen {
stdout-path = "/serial";
+
+ fwupd {
+ compatible = "simple-bus";
+ firmware {
+ compatible = "fwupd,vbe-simple";
+ cur-version = "1.2.3";
+ bootloader-version = "2022.01";
+ storage = "mmc1";
+ area-start = <0x0>;
+ area-size = <0x1000000>;
+ skip-offset = <0x8000>;
+ };
+ };
};
audio: audio-codec {
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index d1a8cc7bfb7..2761588f0da 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1387,6 +1387,21 @@
compatible = "denx,u-boot-fdt-test";
reg = <9 1>;
};
+
+ fwupd {
+ compatible = "simple-bus";
+ firmware0 {
+ compatible = "fwupd,vbe-simple";
+ storage = "mmc1";
+ area-start = <0x400>;
+ area-size = <0x1000>;
+ skip-offset = <0x200>;
+ state-offset = <0x400>;
+ state-size = <0x40>;
+ version-offset = <0x800>;
+ version-size = <0x100>;
+ };
+ };
};
translation-test@8000 {
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 015e96d53f8..53a036b3abf 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -304,4 +304,15 @@ int sandbox_cros_ec_get_pwm_duty(struct udevice *dev, uint index, uint *duty);
*/
int sandbox_sdl_set_bpp(struct udevice *dev, enum video_log2_bpp l2bpp);
+/**
+ * sandbox_set_fake_efi_mgr_dev() - Control EFI bootmgr producing valid bootflow
+ *
+ * This is only used for testing.
+ *
+ * @dev: efi_mgr bootmeth device
+ * @fake_dev: true to produce a valid bootflow when requested, false to produce
+ * an error
+ */
+void sandbox_set_fake_efi_mgr_dev(struct udevice *dev, bool fake_dev);
+
#endif
diff --git a/arch/x86/lib/bios.c b/arch/x86/lib/bios.c
index 98cc05de2eb..94349ba8073 100644
--- a/arch/x86/lib/bios.c
+++ b/arch/x86/lib/bios.c
@@ -10,7 +10,7 @@
#include <bios_emul.h>
#include <irq_func.h>
#include <log.h>
-#include <vbe.h>
+#include <vesa.h>
#include <linux/linkage.h>
#include <asm/cache.h>
#include <asm/processor.h>
@@ -190,7 +190,7 @@ static void setup_realmode_idt(void)
}
#ifdef CONFIG_FRAMEBUFFER_SET_VESA_MODE
-static u8 vbe_get_mode_info(struct vbe_mode_info *mi)
+static u8 vbe_get_mode_info(struct vesa_state *mi)
{
u16 buffer_seg;
u16 buffer_adr;
@@ -204,13 +204,13 @@ static u8 vbe_get_mode_info(struct vbe_mode_info *mi)
realmode_interrupt(0x10, VESA_GET_MODE_INFO, 0x0000, mi->video_mode,
0x0000, buffer_seg, buffer_adr);
- memcpy(mi->mode_info_block, buffer, sizeof(struct vbe_mode_info));
+ memcpy(mi->mode_info_block, buffer, sizeof(struct vesa_state));
mi->valid = true;
return 0;
}
-static u8 vbe_set_mode(struct vbe_mode_info *mi)
+static u8 vbe_set_mode(struct vesa_state *mi)
{
int video_mode = mi->video_mode;
@@ -225,7 +225,7 @@ static u8 vbe_set_mode(struct vbe_mode_info *mi)
return 0;
}
-static void vbe_set_graphics(int vesa_mode, struct vbe_mode_info *mode_info)
+static void vbe_set_graphics(int vesa_mode, struct vesa_state *mode_info)
{
unsigned char *framebuffer;
@@ -249,7 +249,7 @@ static void vbe_set_graphics(int vesa_mode, struct vbe_mode_info *mode_info)
#endif /* CONFIG_FRAMEBUFFER_SET_VESA_MODE */
void bios_run_on_x86(struct udevice *dev, unsigned long addr, int vesa_mode,
- struct vbe_mode_info *mode_info)
+ struct vesa_state *mode_info)
{
pci_dev_t pcidev = dm_pci_get_bdf(dev);
u32 num_dev;
diff --git a/arch/x86/lib/coreboot_table.c b/arch/x86/lib/coreboot_table.c
index 6eab0452fda..05519d851a9 100644
--- a/arch/x86/lib/coreboot_table.c
+++ b/arch/x86/lib/coreboot_table.c
@@ -6,7 +6,7 @@
#include <common.h>
#include <malloc.h>
#include <net.h>
-#include <vbe.h>
+#include <vesa.h>
#include <acpi/acpi_s3.h>
#include <asm/coreboot_tables.h>
#include <asm/e820.h>
diff --git a/arch/x86/lib/fsp/fsp_graphics.c b/arch/x86/lib/fsp/fsp_graphics.c
index 02fd05c9faf..b07c666caf7 100644
--- a/arch/x86/lib/fsp/fsp_graphics.c
+++ b/arch/x86/lib/fsp/fsp_graphics.c
@@ -9,7 +9,7 @@
#include <dm.h>
#include <init.h>
#include <log.h>
-#include <vbe.h>
+#include <vesa.h>
#include <video.h>
#include <acpi/acpi_table.h>
#include <asm/fsp/fsp_support.h>
@@ -106,7 +106,7 @@ static int fsp_video_probe(struct udevice *dev)
vesa->phys_base_ptr = dm_pci_read_bar32(dev, 2);
gd->fb_base = vesa->phys_base_ptr;
- ret = vbe_setup_video_priv(vesa, uc_priv, plat);
+ ret = vesa_setup_video_priv(vesa, uc_priv, plat);
if (ret)
goto err;
diff --git a/boot/Kconfig b/boot/Kconfig
index a294ad769ed..6b3b8f072cb 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -349,6 +349,13 @@ config BOOTSTD_BOOTCOMMAND
standard boot does not support all of the features of distro boot
yet.
+config BOOTMETH_GLOBAL
+ bool
+ help
+ Add support for global bootmeths. This feature is used by VBE and
+ EFI bootmgr, since they take full control over which bootdevs are
+ selected to boot.
+
config BOOTMETH_DISTRO
bool "Bootdev support for distro boot"
select PXE_UTILS
@@ -391,6 +398,28 @@ config BOOTMETH_EFILOADER
This provides a way to try out standard boot on an existing boot flow.
+config BOOTMETH_VBE
+ bool "Bootdev support for Verified Boot for Embedded"
+ depends on FIT
+ default y
+ select BOOTMETH_GLOBAL
+ help
+ Enables support for VBE boot. This is a standard boot method which
+ supports selection of various firmware components, seleciton of an OS to
+ boot as well as updating these using fwupd.
+
+if BOOTMETH_VBE
+
+config BOOTMETH_VBE_SIMPLE
+ bool "Bootdev support for VBE 'simple' method"
+ default y
+ help
+ Enables support for VBE 'simple' boot. This allows updating a single
+ firmware image in boot media such as MMC. It does not support any sort
+ of rollback, recovery or A/B boot.
+
+endif # BOOTMETH_VBE
+
config BOOTMETH_SANDBOX
def_bool y
depends on SANDBOX
diff --git a/boot/Makefile b/boot/Makefile
index 124065a03fa..67e335255f1 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -18,7 +18,7 @@ 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) += bootdev-uclass.o system_bootdev.o
+obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootdev-uclass.o
obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootflow.o
obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootmeth-uclass.o
obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootstd-uclass.o
@@ -46,3 +46,6 @@ obj-$(CONFIG_CMD_ADTIMG) += image-android-dt.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_SPL_LOAD_FIT) += common_fit.o
endif
+
+obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE) += vbe.o
+obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE_SIMPLE) += vbe_simple.o
diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c
index 1ede933c2f2..13ac69eb392 100644
--- a/boot/bootdev-uclass.c
+++ b/boot/bootdev-uclass.c
@@ -36,7 +36,6 @@ enum {
int bootdev_add_bootflow(struct bootflow *bflow)
{
- struct bootdev_uc_plat *ucp = dev_get_uclass_plat(bflow->dev);
struct bootstd_priv *std;
struct bootflow *new;
int ret;
@@ -52,7 +51,11 @@ int bootdev_add_bootflow(struct bootflow *bflow)
memcpy(new, bflow, sizeof(*bflow));
list_add_tail(&new->glob_node, &std->glob_head);
- list_add_tail(&new->bm_node, &ucp->bootflow_head);
+ if (bflow->dev) {
+ struct bootdev_uc_plat *ucp = dev_get_uclass_plat(bflow->dev);
+
+ list_add_tail(&new->bm_node, &ucp->bootflow_head);
+ }
return 0;
}
@@ -604,14 +607,14 @@ int bootdev_setup_iter_order(struct bootflow_iter *iter, struct udevice **devp)
log_debug("Expected %d bootdevs, found %d using aliases\n",
count, upto);
- count = build_order(bootstd, order, upto);
- if (count < 0) {
+ ret = build_order(bootstd, order, upto);
+ if (ret < 0) {
free(order);
- return log_msg_ret("build", count);
+ return log_msg_ret("build", ret);
}
+ iter->num_devs = ret;
iter->dev_order = order;
- iter->num_devs = count;
iter->cur_dev = 0;
dev = *order;
diff --git a/boot/bootflow.c b/boot/bootflow.c
index 24ba3c34660..5d94a27ff84 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -86,6 +86,7 @@ int bootflow_next_glob(struct bootflow **bflowp)
void bootflow_iter_init(struct bootflow_iter *iter, int flags)
{
memset(iter, '\0', sizeof(*iter));
+ iter->first_glob_method = -1;
iter->flags = flags;
}
@@ -115,11 +116,17 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter,
static void bootflow_iter_set_dev(struct bootflow_iter *iter,
struct udevice *dev)
{
+ struct bootmeth_uc_plat *ucp = dev_get_uclass_plat(iter->method);
+
iter->dev = dev;
if ((iter->flags & (BOOTFLOWF_SHOW | BOOTFLOWF_SINGLE_DEV)) ==
BOOTFLOWF_SHOW) {
if (dev)
printf("Scanning bootdev '%s':\n", dev->name);
+ else if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) &&
+ ucp->flags & BOOTMETHF_GLOBAL)
+ printf("Scanning global bootmeth '%s':\n",
+ iter->method->name);
else
printf("No more bootdevs\n");
}
@@ -133,8 +140,12 @@ static void bootflow_iter_set_dev(struct bootflow_iter *iter,
static int iter_incr(struct bootflow_iter *iter)
{
struct udevice *dev;
+ bool inc_dev = true;
+ bool global;
int ret;
+ global = iter->doing_global;
+
if (iter->err == BF_NO_MORE_DEVICES)
return BF_NO_MORE_DEVICES;
@@ -144,6 +155,21 @@ static int iter_incr(struct bootflow_iter *iter)
iter->method = iter->method_order[iter->cur_method];
return 0;
}
+
+ /*
+ * If we have finished scanning the global bootmeths, start the
+ * normal bootdev scan
+ */
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && global) {
+ iter->num_methods = iter->first_glob_method;
+ iter->doing_global = false;
+
+ /*
+ * Don't move to the next dev as we haven't tried this
+ * one yet!
+ */
+ inc_dev = false;
+ }
}
/* No more bootmeths; start at the first one, and... */
@@ -169,14 +195,18 @@ static int iter_incr(struct bootflow_iter *iter)
/* ...select next bootdev */
if (iter->flags & BOOTFLOWF_SINGLE_DEV) {
ret = -ENOENT;
- } else if (++iter->cur_dev == iter->num_devs) {
- ret = -ENOENT;
- bootflow_iter_set_dev(iter, NULL);
} else {
- dev = iter->dev_order[iter->cur_dev];
- ret = device_probe(dev);
- if (!log_msg_ret("probe", ret))
- bootflow_iter_set_dev(iter, dev);
+ if (inc_dev)
+ iter->cur_dev++;
+ if (iter->cur_dev == iter->num_devs) {
+ ret = -ENOENT;
+ bootflow_iter_set_dev(iter, NULL);
+ } else {
+ dev = iter->dev_order[iter->cur_dev];
+ ret = device_probe(dev);
+ if (!log_msg_ret("probe", ret))
+ bootflow_iter_set_dev(iter, dev);
+ }
}
/* if there are no more bootdevs, give up */
@@ -199,6 +229,15 @@ static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow)
struct udevice *dev;
int ret;
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global) {
+ bootflow_iter_set_dev(iter, NULL);
+ ret = bootmeth_get_bootflow(iter->method, bflow);
+ if (ret)
+ return log_msg_ret("glob", ret);
+
+ return 0;
+ }
+
dev = iter->dev;
ret = bootdev_get_bootflow(dev, iter, bflow);
@@ -231,19 +270,22 @@ int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter,
{
int ret;
+ if (dev)
+ flags |= BOOTFLOWF_SKIP_GLOBAL;
bootflow_iter_init(iter, flags);
ret = bootdev_setup_iter_order(iter, &dev);
if (ret)
return log_msg_ret("obdev", -ENODEV);
- bootflow_iter_set_dev(iter, dev);
- ret = bootmeth_setup_iter_order(iter);
+ ret = bootmeth_setup_iter_order(iter, !(flags & BOOTFLOWF_SKIP_GLOBAL));
if (ret)
return log_msg_ret("obmeth", -ENODEV);
/* Find the first bootmeth (there must be at least one!) */
iter->method = iter->method_order[iter->cur_method];
+ if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) || !iter->doing_global)
+ bootflow_iter_set_dev(iter, dev);
ret = bootflow_check(iter, bflow);
if (ret) {
@@ -307,7 +349,8 @@ void bootflow_free(struct bootflow *bflow)
void bootflow_remove(struct bootflow *bflow)
{
- list_del(&bflow->bm_node);
+ if (bflow->dev)
+ list_del(&bflow->bm_node);
list_del(&bflow->glob_node);
bootflow_free(bflow);
diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c
index c040d5f92b2..2d7652edeab 100644
--- a/boot/bootmeth-uclass.c
+++ b/boot/bootmeth-uclass.c
@@ -20,6 +20,16 @@
DECLARE_GLOBAL_DATA_PTR;
+int bootmeth_get_state_desc(struct udevice *dev, char *buf, int maxsize)
+{
+ const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
+
+ if (!ops->get_state_desc)
+ return -ENOSYS;
+
+ return ops->get_state_desc(dev, buf, maxsize);
+}
+
int bootmeth_check(struct udevice *dev, struct bootflow_iter *iter)
{
const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
@@ -61,18 +71,21 @@ int bootmeth_read_file(struct udevice *dev, struct bootflow *bflow,
return ops->read_file(dev, bflow, file_path, addr, sizep);
}
-/**
- * bootmeth_setup_iter_order() - Set up the ordering of bootmeths to scan
- *
- * This sets up the ordering information in @iter, based on the selected
- * ordering of the bootmethds in bootstd_priv->bootmeth_order. If there is no
- * ordering there, then all bootmethods are added
- *
- * @iter: Iterator to update with the order
- * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve
- * on other error
- */
-int bootmeth_setup_iter_order(struct bootflow_iter *iter)
+int bootmeth_get_bootflow(struct udevice *dev, struct bootflow *bflow)
+{
+ const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
+
+ if (!ops->read_bootflow)
+ return -ENOSYS;
+ memset(bflow, '\0', sizeof(*bflow));
+ bflow->dev = NULL;
+ bflow->method = dev;
+ bflow->state = BOOTFLOWST_BASE;
+
+ return ops->read_bootflow(dev, bflow);
+}
+
+int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global)
{
struct bootstd_priv *std;
struct udevice **order;
@@ -95,29 +108,77 @@ int bootmeth_setup_iter_order(struct bootflow_iter *iter)
/* If we have an ordering, copy it */
if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && std->bootmeth_count) {
+ int i;
+
+ /*
+ * We don't support skipping global bootmeths. Instead, the user
+ * should omit them from the ordering
+ */
+ if (!include_global)
+ return log_msg_ret("glob", -EPERM);
memcpy(order, std->bootmeth_order,
count * sizeof(struct bootmeth *));
+
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL)) {
+ for (i = 0; i < count; i++) {
+ struct udevice *dev = order[i];
+ struct bootmeth_uc_plat *ucp;
+ bool is_global;
+
+ ucp = dev_get_uclass_plat(dev);
+ is_global = ucp->flags &
+ BOOTMETHF_GLOBAL;
+ if (is_global) {
+ iter->first_glob_method = i;
+ break;
+ }
+ }
+ }
} else {
struct udevice *dev;
- int i, upto;
+ int i, upto, pass;
/*
- * Get a list of bootmethods, in seq order (i.e. using aliases).
- * There may be gaps so try to count up high enough to find them
- * all.
+ * Do two passes, one to find the normal bootmeths and another
+ * to find the global ones, if required, The global ones go at
+ * the end.
*/
- for (i = 0, upto = 0; upto < count && i < 20 + count * 2; i++) {
- ret = uclass_get_device_by_seq(UCLASS_BOOTMETH, i,
- &dev);
- if (!ret)
- order[upto++] = dev;
+ for (pass = 0, upto = 0; pass < 1 + include_global; pass++) {
+ if (pass)
+ iter->first_glob_method = upto;
+ /*
+ * Get a list of bootmethods, in seq order (i.e. using
+ * aliases). There may be gaps so try to count up high
+ * enough to find them all.
+ */
+ for (i = 0; upto < count && i < 20 + count * 2; i++) {
+ struct bootmeth_uc_plat *ucp;
+ bool is_global;
+
+ ret = uclass_get_device_by_seq(UCLASS_BOOTMETH,
+ i, &dev);
+ if (ret)
+ continue;
+ ucp = dev_get_uclass_plat(dev);
+ is_global =
+ IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) &&
+ (ucp->flags & BOOTMETHF_GLOBAL);
+ if (pass ? is_global : !is_global)
+ order[upto++] = dev;
+ }
}
count = upto;
}
+ if (!count)
+ return log_msg_ret("count2", -ENOENT);
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && include_global &&
+ iter->first_glob_method != -1 && iter->first_glob_method != count) {
+ iter->cur_method = iter->first_glob_method;
+ iter->doing_global = true;
+ }
iter->method_order = order;
iter->num_methods = count;
- iter->cur_method = 0;
return 0;
}
diff --git a/boot/bootmeth_distro.c b/boot/bootmeth_distro.c
index 2b41e654ade..fea09b2c2fb 100644
--- a/boot/bootmeth_distro.c
+++ b/boot/bootmeth_distro.c
@@ -22,6 +22,19 @@
#include <mmc.h>
#include <pxe_utils.h>
+static int distro_get_state_desc(struct udevice *dev, char *buf, int maxsize)
+{
+ if (IS_ENABLED(CONFIG_SANDBOX)) {
+ int len;
+
+ len = snprintf(buf, maxsize, "OK");
+
+ return len + 1 < maxsize ? 0 : -ENOSPC;
+ }
+
+ return 0;
+}
+
static int disto_getfile(struct pxe_context *ctx, const char *file_path,
char *file_addr, ulong *sizep)
{
@@ -123,6 +136,7 @@ static int distro_bootmeth_bind(struct udevice *dev)
}
static struct bootmeth_ops distro_bootmeth_ops = {
+ .get_state_desc = distro_get_state_desc,
.check = distro_check,
.read_bootflow = distro_read_bootflow,
.read_file = bootmeth_common_read_file,
diff --git a/boot/bootmeth_efi_mgr.c b/boot/bootmeth_efi_mgr.c
index a6914466db7..2f327c1f8ce 100644
--- a/boot/bootmeth_efi_mgr.c
+++ b/boot/bootmeth_efi_mgr.c
@@ -15,6 +15,22 @@
#include <command.h>
#include <dm.h>
+/**
+ * struct efi_mgr_priv - private info for the efi-mgr driver
+ *
+ * @fake_bootflow: Fake a valid bootflow for testing
+ */
+struct efi_mgr_priv {
+ bool fake_dev;
+};
+
+void sandbox_set_fake_efi_mgr_dev(struct udevice *dev, bool fake_dev)
+{
+ struct efi_mgr_priv *priv = dev_get_priv(dev);
+
+ priv->fake_dev = fake_dev;
+}
+
static int efi_mgr_check(struct udevice *dev, struct bootflow_iter *iter)
{
int ret;
@@ -29,13 +45,16 @@ static int efi_mgr_check(struct udevice *dev, struct bootflow_iter *iter)
static int efi_mgr_read_bootflow(struct udevice *dev, struct bootflow *bflow)
{
- /*
- * Just assume there is something to boot since we don't have any way
- * of knowing in advance
- */
- bflow->state = BOOTFLOWST_READY;
+ struct efi_mgr_priv *priv = dev_get_priv(dev);
- return 0;
+ if (priv->fake_dev) {
+ bflow->state = BOOTFLOWST_READY;
+ return 0;
+ }
+
+ /* To be implemented */
+
+ return -EINVAL;
}
static int efi_mgr_read_file(struct udevice *dev, struct bootflow *bflow,
@@ -61,6 +80,7 @@ static int bootmeth_efi_mgr_bind(struct udevice *dev)
struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
plat->desc = "EFI bootmgr flow";
+ plat->flags = BOOTMETHF_GLOBAL;
return 0;
}
@@ -77,10 +97,11 @@ static const struct udevice_id efi_mgr_bootmeth_ids[] = {
{ }
};
-U_BOOT_DRIVER(bootmeth_zefi_mgr) = {
+U_BOOT_DRIVER(bootmeth_efi_mgr) = {
.name = "bootmeth_efi_mgr",
.id = UCLASS_BOOTMETH,
.of_match = efi_mgr_bootmeth_ids,
.ops = &efi_mgr_bootmeth_ops,
.bind = bootmeth_efi_mgr_bind,
+ .priv_auto = sizeof(struct efi_mgr_priv),
};
diff --git a/boot/bootstd-uclass.c b/boot/bootstd-uclass.c
index 3c6c32ae604..565c22a36e7 100644
--- a/boot/bootstd-uclass.c
+++ b/boot/bootstd-uclass.c
@@ -133,12 +133,7 @@ int dm_scan_other(bool pre_reloc_only)
return 0;
for (i = 0; i < n_ents; i++, drv++) {
- /*
- * Disable EFI Manager for now as no one uses it so it is
- * confusing
- */
- if (drv->id == UCLASS_BOOTMETH &&
- strcmp("efi_mgr_bootmeth", drv->name)) {
+ if (drv->id == UCLASS_BOOTMETH) {
const char *name = drv->name;
if (!strncmp("bootmeth_", name, 9))
@@ -150,12 +145,6 @@ int dm_scan_other(bool pre_reloc_only)
}
}
- /* Create the system bootdev too */
- ret = device_bind_driver(bootstd, "system_bootdev", "system-bootdev",
- &dev);
- if (ret)
- return log_msg_ret("sys", ret);
-
return 0;
}
diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index 9db2cee9942..5e5b24674d3 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -21,6 +21,7 @@
#include <linux/libfdt.h>
#include <mapmem.h>
#include <asm/io.h>
+#include <dm/ofnode.h>
#include <tee/optee.h>
#ifndef CONFIG_SYS_FDT_PAD
@@ -668,6 +669,16 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob,
goto err;
}
}
+ if (CONFIG_IS_ENABLED(EVENT)) {
+ struct event_ft_fixup fixup;
+
+ fixup.tree = oftree_default();
+ ret = event_notify(EVT_FT_FIXUP, &fixup, sizeof(fixup));
+ if (ret) {
+ printf("ERROR: fdt fixup event failed: %d\n", ret);
+ goto err;
+ }
+ }
/* Delete the old LMB reservation */
if (lmb)
diff --git a/boot/system_bootdev.c b/boot/system_bootdev.c
deleted file mode 100644
index 432d2034780..00000000000
--- a/boot/system_bootdev.c
+++ /dev/null
@@ -1,66 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Bootdevice for system, used for bootmeths not tied to any partition device
- *
- * Copyright 2021 Google LLC
- * Written by Simon Glass <sjg@chromium.org>
- */
-
-#define LOG_CATEGORY UCLASS_BOOTSTD
-
-#include <common.h>
-#include <bootdev.h>
-#include <bootflow.h>
-#include <bootmeth.h>
-#include <command.h>
-#include <distro.h>
-#include <dm.h>
-#include <log.h>
-#include <net.h>
-
-static int system_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
- struct bootflow *bflow)
-{
- int ret;
-
- /* Must be an bootstd device */
- ret = bootflow_iter_uses_system(iter);
- if (ret)
- return log_msg_ret("net", ret);
-
- ret = bootmeth_check(bflow->method, iter);
- if (ret)
- return log_msg_ret("check", ret);
-
- ret = bootmeth_read_bootflow(bflow->method, bflow);
- if (ret)
- return log_msg_ret("method", ret);
-
- return 0;
-}
-
-static int system_bootdev_bind(struct udevice *dev)
-{
- struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
-
- ucp->prio = BOOTDEVP_6_SYSTEM;
-
- return 0;
-}
-
-struct bootdev_ops system_bootdev_ops = {
- .get_bootflow = system_get_bootflow,
-};
-
-static const struct udevice_id system_bootdev_ids[] = {
- { .compatible = "u-boot,bootdev-system" },
- { }
-};
-
-U_BOOT_DRIVER(system_bootdev) = {
- .name = "system_bootdev",
- .id = UCLASS_BOOTDEV,
- .ops = &system_bootdev_ops,
- .bind = system_bootdev_bind,
- .of_match = system_bootdev_ids,
-};
diff --git a/boot/vbe.c b/boot/vbe.c
new file mode 100644
index 00000000000..e6ee087dc24
--- /dev/null
+++ b/boot/vbe.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Verified Boot for Embedded (VBE) access functions
+ *
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <bootmeth.h>
+#include <bootstd.h>
+#include <dm.h>
+#include <image.h>
+#include <vbe.h>
+#include <dm/uclass-internal.h>
+
+/**
+ * is_vbe() - Check if a device is a VBE method
+ *
+ * @dev: Device to check
+ * @return true if this is a VBE bootmth device, else false
+ */
+static bool is_vbe(struct udevice *dev)
+{
+ return !strncmp("vbe", dev->driver->name, 3);
+}
+
+int vbe_find_next_device(struct udevice **devp)
+{
+ for (uclass_find_next_device(devp);
+ *devp;
+ uclass_find_next_device(devp)) {
+ if (is_vbe(*devp))
+ return 0;
+ }
+
+ return 0;
+}
+
+int vbe_find_first_device(struct udevice **devp)
+{
+ uclass_find_first_device(UCLASS_BOOTMETH, devp);
+ if (*devp && is_vbe(*devp))
+ return 0;
+
+ return vbe_find_next_device(devp);
+}
+
+int vbe_list(void)
+{
+ struct bootstd_priv *std;
+ struct udevice *dev;
+ int ret;
+
+ ret = bootstd_get_priv(&std);
+ if (ret)
+ return ret;
+
+ printf("%3s %-3s %-15s %-15s %s\n", "#", "Sel", "Device", "Driver",
+ "Description");
+ printf("%3s %-3s %-15s %-15s %s\n", "---", "---", "--------------",
+ "--------------", "-----------");
+ for (ret = vbe_find_first_device(&dev); dev;
+ ret = vbe_find_next_device(&dev)) {
+ const struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
+
+ printf("%3d %-3s %-15s %-15s %s\n", dev_seq(dev),
+ std->vbe_bootmeth == dev ? "*" : "", dev->name,
+ dev->driver->name, plat->desc);
+ }
+ printf("%3s %-3s %-15s %-15s %s\n", "---", "---", "--------------",
+ "--------------", "-----------");
+
+ return 0;
+}
+
+int vbe_select(struct udevice *dev)
+{
+ struct bootstd_priv *std;
+ int ret;
+
+ ret = bootstd_get_priv(&std);
+ if (ret)
+ return ret;
+ std->vbe_bootmeth = dev;
+
+ return 0;
+}
+
+int vbe_find_by_any(const char *name, struct udevice **devp)
+{
+ struct udevice *dev;
+ int ret, seq;
+ char *endp;
+
+ seq = simple_strtol(name, &endp, 16);
+
+ /* Select by name */
+ if (*endp) {
+ ret = uclass_get_device_by_name(UCLASS_BOOTMETH, name, &dev);
+ if (ret) {
+ printf("Cannot probe VBE bootmeth '%s' (err=%d)\n", name,
+ ret);
+ return ret;
+ }
+
+ /* select by number */
+ } else {
+ ret = uclass_get_device_by_seq(UCLASS_BOOTMETH, seq, &dev);
+ if (ret) {
+ printf("Cannot find '%s' (err=%d)\n", name, ret);
+ return ret;
+ }
+ }
+
+ *devp = dev;
+
+ return 0;
+}
diff --git a/boot/vbe_simple.c b/boot/vbe_simple.c
new file mode 100644
index 00000000000..a395bc20a60
--- /dev/null
+++ b/boot/vbe_simple.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Verified Boot for Embedded (VBE) 'simple' method
+ *
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <log.h>
+#include <memalign.h>
+#include <part.h>
+#include <bootflow.h>
+#include <bootmeth.h>
+#include <dm.h>
+#include <mmc.h>
+#include <vbe.h>
+#include <version_string.h>
+#include <dm/device-internal.h>
+#include <dm/ofnode.h>
+#include <u-boot/crc.h>
+
+enum {
+ MAX_VERSION_LEN = 256,
+
+ NVD_HDR_VER_SHIFT = 0,
+ NVD_HDR_VER_MASK = 0xf,
+ NVD_HDR_SIZE_SHIFT = 4,
+ NVD_HDR_SIZE_MASK = 0xf << NVD_HDR_SIZE_SHIFT,
+
+ /* Firmware key-version is in the top 16 bits of fw_ver */
+ FWVER_KEY_SHIFT = 16,
+ FWVER_FW_MASK = 0xffff,
+
+ NVD_HDR_VER_CUR = 1, /* current version */
+};
+
+/** struct simple_priv - information read from the device tree */
+struct simple_priv {
+ u32 area_start;
+ u32 area_size;
+ u32 skip_offset;
+ u32 state_offset;
+ u32 state_size;
+ u32 version_offset;
+ u32 version_size;
+ const char *storage;
+};
+
+/** struct simple_state - state information read from media
+ *
+ * @fw_version: Firmware version string
+ * @fw_vernum: Firmware version number
+ */
+struct simple_state {
+ char fw_version[MAX_VERSION_LEN];
+ u32 fw_vernum;
+};
+
+/** struct simple_nvdata - storage format for non-volatile data */
+struct simple_nvdata {
+ u8 crc8;
+ u8 hdr;
+ u16 spare1;
+ u32 fw_vernum;
+ u8 spare2[0x38];
+};
+
+static int simple_read_version(struct udevice *dev, struct blk_desc *desc,
+ u8 *buf, struct simple_state *state)
+{
+ struct simple_priv *priv = dev_get_priv(dev);
+ int start;
+
+ if (priv->version_size > MMC_MAX_BLOCK_LEN)
+ return log_msg_ret("ver", -E2BIG);
+
+ start = priv->area_start + priv->version_offset;
+ if (start & (MMC_MAX_BLOCK_LEN - 1))
+ return log_msg_ret("get", -EBADF);
+ start /= MMC_MAX_BLOCK_LEN;
+
+ if (blk_dread(desc, start, 1, buf) != 1)
+ return log_msg_ret("read", -EIO);
+ strlcpy(state->fw_version, buf, MAX_VERSION_LEN);
+ log_debug("version=%s\n", state->fw_version);
+
+ return 0;
+}
+
+static int simple_read_nvdata(struct udevice *dev, struct blk_desc *desc,
+ u8 *buf, struct simple_state *state)
+{
+ struct simple_priv *priv = dev_get_priv(dev);
+ uint hdr_ver, hdr_size, size, crc;
+ const struct simple_nvdata *nvd;
+ int start;
+
+ if (priv->state_size > MMC_MAX_BLOCK_LEN)
+ return log_msg_ret("state", -E2BIG);
+
+ start = priv->area_start + priv->state_offset;
+ if (start & (MMC_MAX_BLOCK_LEN - 1))
+ return log_msg_ret("get", -EBADF);
+ start /= MMC_MAX_BLOCK_LEN;
+
+ if (blk_dread(desc, start, 1, buf) != 1)
+ return log_msg_ret("read", -EIO);
+ nvd = (struct simple_nvdata *)buf;
+ hdr_ver = (nvd->hdr & NVD_HDR_VER_MASK) >> NVD_HDR_VER_SHIFT;
+ hdr_size = (nvd->hdr & NVD_HDR_SIZE_MASK) >> NVD_HDR_SIZE_SHIFT;
+ if (hdr_ver != NVD_HDR_VER_CUR)
+ return log_msg_ret("hdr", -EPERM);
+ size = 1 << hdr_size;
+ if (size > sizeof(*nvd))
+ return log_msg_ret("sz", -ENOEXEC);
+
+ crc = crc8(0, buf + 1, size - 1);
+ if (crc != nvd->crc8)
+ return log_msg_ret("crc", -EPERM);
+ state->fw_vernum = nvd->fw_vernum;
+
+ log_debug("version=%s\n", state->fw_version);
+
+ return 0;
+}
+
+static int simple_read_state(struct udevice *dev, struct simple_state *state)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
+ struct simple_priv *priv = dev_get_priv(dev);
+ struct blk_desc *desc;
+ char devname[16];
+ const char *end;
+ int devnum;
+ int ret;
+
+ /* First figure out the block device */
+ log_debug("storage=%s\n", priv->storage);
+ devnum = trailing_strtoln_end(priv->storage, NULL, &end);
+ if (devnum == -1)
+ return log_msg_ret("num", -ENODEV);
+ if (end - priv->storage >= sizeof(devname))
+ return log_msg_ret("end", -E2BIG);
+ strlcpy(devname, priv->storage, end - priv->storage + 1);
+ log_debug("dev=%s, %x\n", devname, devnum);
+
+ desc = blk_get_dev(devname, devnum);
+ if (!desc)
+ return log_msg_ret("get", -ENXIO);
+
+ ret = simple_read_version(dev, desc, buf, state);
+ if (ret)
+ return log_msg_ret("ver", ret);
+
+ ret = simple_read_nvdata(dev, desc, buf, state);
+ if (ret)
+ return log_msg_ret("nvd", ret);
+
+ return 0;
+}
+
+static int vbe_simple_get_state_desc(struct udevice *dev, char *buf,
+ int maxsize)
+{
+ struct simple_state state;
+ int ret;
+
+ ret = simple_read_state(dev, &state);
+ if (ret)
+ return log_msg_ret("read", ret);
+
+ if (maxsize < 30)
+ return -ENOSPC;
+ snprintf(buf, maxsize, "Version: %s\nVernum: %x/%x", state.fw_version,
+ state.fw_vernum >> FWVER_KEY_SHIFT,
+ state.fw_vernum & FWVER_FW_MASK);
+
+ return 0;
+}
+
+static int vbe_simple_read_bootflow(struct udevice *dev, struct bootflow *bflow)
+{
+ /* To be implemented */
+
+ return -EINVAL;
+}
+
+static struct bootmeth_ops bootmeth_vbe_simple_ops = {
+ .get_state_desc = vbe_simple_get_state_desc,
+ .read_bootflow = vbe_simple_read_bootflow,
+ .read_file = bootmeth_common_read_file,
+};
+
+int vbe_simple_fixup_node(ofnode node, struct simple_state *state)
+{
+ char *version;
+ int ret;
+
+ version = strdup(state->fw_version);
+ if (!version)
+ return log_msg_ret("ver", -ENOMEM);
+
+ ret = ofnode_write_string(node, "cur-version", version);
+ if (ret)
+ return log_msg_ret("ver", ret);
+ ret = ofnode_write_u32(node, "cur-vernum", state->fw_vernum);
+ if (ret)
+ return log_msg_ret("ver", ret);
+ ret = ofnode_write_string(node, "bootloader-version", version_string);
+ if (ret)
+ return log_msg_ret("fix", ret);
+
+ return 0;
+}
+
+/**
+ * bootmeth_vbe_simple_ft_fixup() - Write out all VBE simple data to the DT
+ *
+ * @ctx: Context for event
+ * @event: Event to process
+ * @return 0 if OK, -ve on error
+ */
+static int bootmeth_vbe_simple_ft_fixup(void *ctx, struct event *event)
+{
+ oftree tree = event->data.ft_fixup.tree;
+ struct udevice *dev;
+ ofnode node;
+ int ret;
+
+ /*
+ * Ideally we would have driver model support for fixups, but that does
+ * not exist yet. It is a step too far to try to do this before VBE is
+ * in place.
+ */
+ for (ret = vbe_find_first_device(&dev); dev;
+ ret = vbe_find_next_device(&dev)) {
+ struct simple_state state;
+
+ if (strcmp("vbe_simple", dev->driver->name))
+ continue;
+
+ /* Check if there is a node to fix up */
+ node = ofnode_path_root(tree, "/chosen/fwupd");
+ if (!ofnode_valid(node))
+ continue;
+ node = ofnode_find_subnode(node, dev->name);
+ if (!ofnode_valid(node))
+ continue;
+
+ log_debug("Fixing up: %s\n", dev->name);
+ ret = device_probe(dev);
+ if (ret)
+ return log_msg_ret("probe", ret);
+ ret = simple_read_state(dev, &state);
+ if (ret)
+ return log_msg_ret("read", ret);
+
+ ret = vbe_simple_fixup_node(node, &state);
+ if (ret)
+ return log_msg_ret("fix", ret);
+ }
+
+ return 0;
+}
+EVENT_SPY(EVT_FT_FIXUP, bootmeth_vbe_simple_ft_fixup);
+
+static int bootmeth_vbe_simple_probe(struct udevice *dev)
+{
+ struct simple_priv *priv = dev_get_priv(dev);
+
+ memset(priv, '\0', sizeof(*priv));
+ if (dev_read_u32(dev, "area-start", &priv->area_start) ||
+ dev_read_u32(dev, "area-size", &priv->area_size) ||
+ dev_read_u32(dev, "version-offset", &priv->version_offset) ||
+ dev_read_u32(dev, "version-size", &priv->version_size) ||
+ dev_read_u32(dev, "state-offset", &priv->state_offset) ||
+ dev_read_u32(dev, "state-size", &priv->state_size))
+ return log_msg_ret("read", -EINVAL);
+ dev_read_u32(dev, "skip-offset", &priv->skip_offset);
+ priv->storage = strdup(dev_read_string(dev, "storage"));
+ if (!priv->storage)
+ return log_msg_ret("str", -EINVAL);
+
+ return 0;
+}
+
+static int bootmeth_vbe_simple_bind(struct udevice *dev)
+{
+ struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
+
+ plat->desc = IS_ENABLED(CONFIG_BOOTSTD_FULL) ?
+ "VBE simple" : "vbe-simple";
+ plat->flags = BOOTMETHF_GLOBAL;
+
+ return 0;
+}
+
+#if CONFIG_IS_ENABLED(OF_REAL)
+static const struct udevice_id generic_simple_vbe_simple_ids[] = {
+ { .compatible = "fwupd,vbe-simple" },
+ { }
+};
+#endif
+
+U_BOOT_DRIVER(vbe_simple) = {
+ .name = "vbe_simple",
+ .id = UCLASS_BOOTMETH,
+ .of_match = of_match_ptr(generic_simple_vbe_simple_ids),
+ .ops = &bootmeth_vbe_simple_ops,
+ .bind = bootmeth_vbe_simple_bind,
+ .probe = bootmeth_vbe_simple_probe,
+ .flags = DM_FLAG_PRE_RELOC,
+ .priv_auto = sizeof(struct simple_priv),
+};
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 7d19706a8ec..211ebe9c878 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -330,6 +330,16 @@ config BOOTM_RTEMS
help
Support booting RTEMS images via the bootm command.
+config CMD_VBE
+ bool "vbe - Verified Boot for Embedded"
+ depends on BOOTMETH_VBE
+ default y
+ help
+ Provides various subcommands related to VBE, such as listing the
+ available methods, looking at the state and changing which method
+ is used to boot. Updating the parameters is not currently
+ supported.
+
config BOOTM_VXWORKS
bool "Support booting VxWorks OS images"
depends on CMD_BOOTM
diff --git a/cmd/Makefile b/cmd/Makefile
index 5e43a1e022e..6e87522b62e 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -179,6 +179,7 @@ obj-$(CONFIG_CMD_FS_UUID) += fs_uuid.o
obj-$(CONFIG_CMD_USB_MASS_STORAGE) += usb_mass_storage.o
obj-$(CONFIG_CMD_USB_SDP) += usb_gadget_sdp.o
obj-$(CONFIG_CMD_THOR_DOWNLOAD) += thordown.o
+obj-$(CONFIG_CMD_VBE) += vbe.o
obj-$(CONFIG_CMD_XIMG) += ximg.o
obj-$(CONFIG_CMD_YAFFS2) += yaffs2.o
obj-$(CONFIG_CMD_SPL) += spl.o
diff --git a/cmd/bootflow.c b/cmd/bootflow.c
index af4b9c37323..313103d2775 100644
--- a/cmd/bootflow.c
+++ b/cmd/bootflow.c
@@ -69,8 +69,8 @@ static void show_bootflow(int index, struct bootflow *bflow, bool errors)
{
printf("%3x %-11s %-6s %-9.9s %4x %-25.25s %s\n", index,
bflow->method->name, bootflow_state_get_name(bflow->state),
- dev_get_uclass_name(dev_get_parent(bflow->dev)), bflow->part,
- bflow->name, bflow->fname);
+ bflow->dev ? dev_get_uclass_name(dev_get_parent(bflow->dev)) :
+ "(none)", bflow->part, bflow->name, bflow->fname);
if (errors)
report_bootflow_err(bflow, bflow->err);
}
@@ -95,7 +95,8 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
struct bootflow_iter iter;
struct udevice *dev;
struct bootflow bflow;
- bool all = false, boot = false, errors = false, list = false;
+ bool all = false, boot = false, errors = false, no_global = false;
+ bool list = false;
int num_valid = 0;
bool has_args;
int ret, i;
@@ -112,6 +113,7 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
all = strchr(argv[1], 'a');
boot = strchr(argv[1], 'b');
errors = strchr(argv[1], 'e');
+ no_global = strchr(argv[1], 'G');
list = strchr(argv[1], 'l');
argc--;
argv++;
@@ -137,6 +139,8 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
flags |= BOOTFLOWF_SHOW;
if (all)
flags |= BOOTFLOWF_ALL;
+ if (no_global)
+ flags |= BOOTFLOWF_SKIP_GLOBAL;
/*
* If we have a device, just scan for bootflows attached to that device
@@ -383,7 +387,7 @@ static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc,
#ifdef CONFIG_SYS_LONGHELP
static char bootflow_help_text[] =
#ifdef CONFIG_CMD_BOOTFLOW_FULL
- "scan [-abel] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot)\n"
+ "scan [-abeGl] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot, -G no global)\n"
"bootflow list [-e] - list scanned bootflows (-e errors)\n"
"bootflow select [<num>|<name>] - select a bootflow\n"
"bootflow info [-d] - show info on current bootflow (-d dump bootflow)\n"
diff --git a/cmd/bootmeth.c b/cmd/bootmeth.c
index c9a27fe8ac6..9fbcccdba7e 100644
--- a/cmd/bootmeth.c
+++ b/cmd/bootmeth.c
@@ -69,7 +69,9 @@ static int do_bootmeth_list(struct cmd_tbl *cmdtp, int flag, int argc,
}
}
- if (order == -1)
+ if (ucp->flags & BOOTMETHF_GLOBAL)
+ printf("%5s", "glob");
+ else if (order == -1)
printf("%5s", "-");
else
printf("%5x", order);
diff --git a/cmd/elf.c b/cmd/elf.c
index 2b33c50bd02..ce40d3f72a7 100644
--- a/cmd/elf.c
+++ b/cmd/elf.c
@@ -14,7 +14,7 @@
#include <net.h>
#include <vxworks.h>
#ifdef CONFIG_X86
-#include <vbe.h>
+#include <vesa.h>
#include <asm/cache.h>
#include <asm/e820.h>
#include <linux/linkage.h>
diff --git a/cmd/read.c b/cmd/read.c
index 99c7e3854e1..fecfadaa1fa 100644
--- a/cmd/read.c
+++ b/cmd/read.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <command.h>
+#include <mapmem.h>
#include <part.h>
int do_read(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
@@ -45,7 +46,7 @@ int do_read(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
return 1;
}
- addr = (void *)hextoul(argv[3], NULL);
+ addr = map_sysmem(hextoul(argv[3], NULL), 0);
blk = hextoul(argv[4], NULL);
cnt = hextoul(argv[5], NULL);
diff --git a/cmd/vbe.c b/cmd/vbe.c
new file mode 100644
index 00000000000..a5737edc047
--- /dev/null
+++ b/cmd/vbe.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Verified Boot for Embedded (VBE) command
+ *
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <bootmeth.h>
+#include <bootstd.h>
+#include <command.h>
+#include <vbe.h>
+
+static int do_vbe_list(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ vbe_list();
+
+ return 0;
+}
+
+static int do_vbe_select(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct bootstd_priv *std;
+ struct udevice *dev;
+ int ret;
+
+ ret = bootstd_get_priv(&std);
+ if (ret)
+ return CMD_RET_FAILURE;
+ if (argc < 2) {
+ std->vbe_bootmeth = NULL;
+ return 0;
+ }
+ if (vbe_find_by_any(argv[1], &dev))
+ return CMD_RET_FAILURE;
+
+ std->vbe_bootmeth = dev;
+
+ return 0;
+}
+
+static int do_vbe_info(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct bootstd_priv *std;
+ char buf[256];
+ int ret, len;
+
+ ret = bootstd_get_priv(&std);
+ if (ret)
+ return CMD_RET_FAILURE;
+ if (!std->vbe_bootmeth) {
+ printf("No VBE bootmeth selected\n");
+ return CMD_RET_FAILURE;
+ }
+ ret = bootmeth_get_state_desc(std->vbe_bootmeth, buf, sizeof(buf));
+ if (ret) {
+ printf("Failed (err=%d)\n", ret);
+ return CMD_RET_FAILURE;
+ }
+ len = strnlen(buf, sizeof(buf));
+ if (len >= sizeof(buf)) {
+ printf("Buffer overflow\n");
+ return CMD_RET_FAILURE;
+ }
+
+ puts(buf);
+ if (buf[len] != '\n')
+ putc('\n');
+
+ return 0;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char vbe_help_text[] =
+ "list - list VBE bootmeths\n"
+ "vbe select - select a VBE bootmeth by sequence or name\n"
+ "vbe info - show information about a VBE bootmeth";
+#endif
+
+U_BOOT_CMD_WITH_SUBCMDS(vbe, "Verified Boot for Embedded", vbe_help_text,
+ U_BOOT_SUBCMD_MKENT(list, 1, 1, do_vbe_list),
+ U_BOOT_SUBCMD_MKENT(select, 2, 1, do_vbe_select),
+ U_BOOT_SUBCMD_MKENT(info, 2, 1, do_vbe_info));
diff --git a/common/event.c b/common/event.c
index af1ed4121d8..3e345509783 100644
--- a/common/event.c
+++ b/common/event.c
@@ -35,6 +35,9 @@ const char *const type_name[] = {
/* init hooks */
"misc_init_f",
+
+ /* fdt hooks */
+ "ft_fixup",
};
_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index a71ce77c403..6d62feeb08a 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -11,6 +11,7 @@ CONFIG_DISTRO_DEFAULTS=y
CONFIG_FIT=y
CONFIG_FIT_SIGNATURE=y
CONFIG_FIT_VERBOSE=y
+# CONFIG_BOOTMETH_VBE is not set
CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y
CONFIG_BOOTSTAGE_FDT=y
@@ -206,6 +207,7 @@ CONFIG_RSA_VERIFY_WITH_PKEY=y
CONFIG_TPM=y
CONFIG_LZ4=y
CONFIG_ERRNO_STR=y
+# CONFIG_CMD_BOOTEFI_BOOTMGR is not set
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
CONFIG_EFI_CAPSULE_ON_DISK=y
CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y
diff --git a/doc/develop/bootstd.rst b/doc/develop/bootstd.rst
index 5e9c0d282bb..b8773f8339d 100644
--- a/doc/develop/bootstd.rst
+++ b/doc/develop/bootstd.rst
@@ -32,6 +32,7 @@ way to boot with U-Boot. The feature is extensible to different Operating
Systems (such as Chromium OS) and devices (beyond just block and network
devices). It supports EFI boot and EFI bootmgr too.
+Finally, standard boot supports the operation of :doc:`vbe`.
Bootflow
--------
@@ -89,6 +90,12 @@ bootflows.
Note: it is possible to have a bootmeth that uses a partition or a whole device
directly, but it is more common to use a filesystem.
+Note that some bootmeths are 'global', meaning that they select the bootdev
+themselves. Examples include VBE and EFI boot manager. In this case, they
+provide a `read_bootflow()` method which checks whatever bootdevs it likes, then
+returns the bootflow, if found. Some of these bootmeths may be very slow, if
+they scan a lot of devices.
+
Boot process
------------
@@ -112,6 +119,9 @@ the following command::
which scans for available bootflows, optionally listing each find it finds (-l)
and trying to boot it (-b).
+When global bootmeths are available, these are typically checked before the
+above bootdev scanning.
+
Controlling ordering
--------------------
@@ -269,18 +279,8 @@ Standard boot requires a single instance of the bootstd device to make things
work. This includes global information about the state of standard boot. See
`struct bootstd_priv` for this structure, accessed with `bootstd_get_priv()`.
-Within the devicetree, if you add bootmeth devices or a system bootdev, they
-should be children of the bootstd device. See `arch/sandbox/dts/test.dts` for
-an example of this.
-
-
-The system bootdev
-------------------
-
-Some bootmeths don't operate on individual bootdevs, but on the whole system.
-For example, the EFI boot manager does its own device scanning and does not
-make use of the bootdev devices. Such bootmeths can make use of the system
-bootdev, typically considered last, after everything else has been tried.
+Within the devicetree, if you add bootmeth devices, they should be children of
+the bootstd device. See `arch/sandbox/dts/test.dts` for an example of this.
.. _`Automatic Devices`:
@@ -291,12 +291,11 @@ Automatic devices
It is possible to define all the required devices in the devicetree manually,
but it is not necessary. The bootstd uclass includes a `dm_scan_other()`
function which creates the bootstd device if not found. If no bootmeth devices
-are found at all, it creates one for each available bootmeth driver as well as a
-system bootdev.
+are found at all, it creates one for each available bootmeth driver.
If your devicetree has any bootmeth device it must have all of them that you
-want to use, as well as the system bootdev if needed, since no bootmeth devices
-will be created automatically in that case.
+want to use, since no bootmeth devices will be created automatically in that
+case.
Using devicetree
@@ -347,6 +346,7 @@ Bootmeth drivers are provided for:
- distro boot from a disk (syslinux)
- distro boot from a network (PXE)
- EFI boot using bootefi
+ - VBE
- EFI boot using boot manager
@@ -433,18 +433,23 @@ case, the iterator ends up with a `dev_order` array containing the bootdevs that
are going to be used, with `num_devs` set to the number of bootdevs and
`cur_dev` starting at 0.
-Next, the ordering of bootdevs is determined, by `bootmeth_setup_iter_order()`.
+Next, the ordering of bootmeths is determined, by `bootmeth_setup_iter_order()`.
By default the ordering is again by sequence number, i.e. the `/aliases` node,
or failing that the order in the devicetree. But the `bootmeth order` command
or `bootmeths` environment variable can be used to set up an ordering. If that
has been done, the ordering is in `struct bootstd_priv`, so that ordering is
simply copied into the iterator. Either way, the `method_order` array it set up,
-along with `num_methods`. Then `cur_method` is set to 0.
+along with `num_methods`.
+
+Note that global bootmeths are always put at the end of the ordering. If any are
+present, `cur_method` is set to the first one, so that global bootmeths are done
+first. Once all have been used, these bootmeths are dropped from the iteration.
+When there are no global bootmeths, `cur_method` is set to 0.
At this point the iterator is ready to use, with the first bootdev and bootmeth
-selected. All the other fields are 0. This means that the current partition is
-0, which is taken to mean the whole device, since partition numbers start at 1.
-It also means that `max_part` is 0, i.e. the maximum partition number we know
+selected. Most of the other fields are 0. This means that the current partition
+is 0, which is taken to mean the whole device, since partition numbers start at
+1. It also means that `max_part` is 0, i.e. the maximum partition number we know
about is 0, meaning that, as far as we know, there is no partition table on this
bootdev.
@@ -455,6 +460,10 @@ If the `BOOTFLOWF_ALL` iterator flag is set, even errors are returned as
incomplete bootflows, but normally an error results in moving onto the next
iteration.
+Note that `bootflow_check()` handles global bootmeths explicitly, but calling
+`bootmeth_get_bootflow()` on each one. The `doing_global` flag indicates when
+the iterator is in that state.
+
The `bootflow_scan_next()` function handles moving onto the next iteration and
checking it. In fact it sits in a loop doing that repeatedly until it finds
something it wants to return.
@@ -473,9 +482,10 @@ the least-sigificant digit on the right, counting like this:
0 0 2
0 1 0
0 1 1
- 0 1 1
+ 0 1 2
1 0 0
1 0 1
+ ...
======== ======= =======
The maximum value for `method` is `num_methods - 1` so when it exceeds that, it
@@ -487,6 +497,31 @@ exceeds its maximum, then the next bootdev is used. In this way, iter_incr()
works its way through all possibilities, moving forward one each time it is
called.
+Note that global bootmeths introduce a subtlety into the above description.
+When `doing_global` is true, the iteration takes place only among the bootmeths,
+i.e. the last column above. The global bootmeths are at the end of the list.
+Assuming that they are entries 3 and 4 in the list, the iteration then looks
+like this:
+
+ ======== ======= ======= =======================================
+ bootdev part method notes
+ ======== ======= ======= =======================================
+ . . 3 doing_global = true, method_count = 5
+ . . 4
+ 0 0 0 doing_global = false, method_count = 3
+ 0 0 1
+ 0 0 2
+ 0 1 0
+ 0 1 1
+ 0 1 2
+ 1 0 0
+ 1 0 1
+ ...
+ ======== ======= ======= =======================================
+
+The changeover of the value of `doing_global` from true to false is handled in
+`iter_incr()` as well.
+
There is no expectation that iteration will actually finish. Quite often a
valid bootflow is found early on. With `bootflow scan -b`, that causes the
bootflow to be immediately booted. Assuming it is successful, the iteration never
@@ -516,17 +551,19 @@ method `bootdev_get_bootflow()` to ask the bootdev to return a bootflow. It
passes the iterator to the bootdev method, so that function knows what we are
talking about. At first, the bootflow is set up in the state `BOOTFLOWST_BASE`,
with just the `method` and `dev` intiialised. But the bootdev may fill in more,
-e.g. updating the state, depending on what it finds.
+e.g. updating the state, depending on what it finds. For global bootmeths the
+`bootmeth_get_bootflow()` function is called instead of
+`bootdev_get_bootflow()`.
-Based on what the bootdev responds with, `bootflow_check()` either
+Based on what the bootdev or bootmeth responds with, `bootflow_check()` either
returns a valid bootflow, or a partial one with an error. A partial bootflow
is one that has some fields set up, but did not reach the `BOOTFLOWST_READY`
state. As noted before, if the `BOOTFLOWF_ALL` iterator flag is set, then all
bootflows are returned, even partial ones. This can help with debugging.
So at this point you can see that total control over whether a bootflow can
-be generated from a particular iteration, or not, rests with the bootdev.
-Each one can adopt its own approach.
+be generated from a particular iteration, or not, rests with the bootdev (or
+global bootmeth). Each one can adopt its own approach.
Going down a level, what does the bootdev do in its `get_bootflow()` method?
Let us consider the MMC bootdev. In that case the call to
diff --git a/doc/develop/driver-model/livetree.rst b/doc/develop/driver-model/livetree.rst
index 9f654f3b894..faf3eb5b5f0 100644
--- a/doc/develop/driver-model/livetree.rst
+++ b/doc/develop/driver-model/livetree.rst
@@ -211,9 +211,61 @@ using it in new code.
Modifying the livetree
----------------------
-This is not currently supported. Once implemented it should provide a much
-more efficient implementation for modification of the device tree than using
-the flat tree.
+This is supported in a limited way, with ofnode_write_prop() and related
+functions.
+
+The unflattening algorithm results in a single block of memory being
+allocated for the whole tree. When writing new properties, these are
+allocated new memory outside that block. When the block is freed, the
+allocated properties remain. This can result in a memory leak.
+
+The solution to this leak would be to add a flag for properties (and nodes when
+support is provided for adding those) that indicates that they should be
+freed. Then the tree can be scanned for these 'separately allocated' nodes and
+properties before freeing the memory block.
+
+The ofnode_write\_...() functions also support writing to the flat tree. Care
+should be taken however, since this can change the position of node names and
+properties in the flat tree, thus affecting the live tree. Generally this does
+not matter, since when we fire up the live tree we don't ever use the flat tree
+again. But in the case of tests, this can cause a problem.
+
+The sandbox tests typically run with OF_LIVE enabled but with the actual live
+tree either present or absent. This is to make sure that the flat tree functions
+work correctly even with OF_LIVE is enabled. But if a test modifies the flat
+device tree, then the live tree can become invalid. Any live tree tests that run
+after that point will use a corrupted tree, e.g. with an incorrect property name
+or worse. To deal with this we use a flag UT_TESTF_LIVE_OR_FLAT then ensures
+that tests which write to the flat tree are not run if OF_LIVE is enabled. Only
+the live tree version of the test is run, when OF_LIVE is enabled, with
+sandbox_flattree running the flat tree version.
+
+This is of course a work-around, even if a reasonable one. One solution to this
+problem would be to make a copy of the flat tree before the test and restore it
+afterwards, in the same memory location, so that the live tree pointers work
+again. Another would be to regenerate the live tree if a test modified the flat
+tree.
+
+Neither of these solutions is currently implemented, since the situation that
+causes the problem can only occur in sandbox tests, is somewhat esoteric and
+the UT_TESTF_LIVE_OR_FLAT flag deals with it in a reasonable way.
+
+
+Multiple livetrees
+------------------
+
+The livetree implementation was originally designed for use with the control
+FDT. This means that the FDT fix-ups (ft_board_setup() and the like, must use
+a flat tree.
+
+It would be helpful to use livetree for fixups, since adding a lot of nodes and
+properties would involve less memory copying and be more efficient. As a step
+towards this, an `oftree` type has been introduced. It is normally set to
+oftree_default() but can be set to other values. Eventually this should allow
+the use of FDT fixups using the ofnode interface, instead of the low-level
+libfdt one.
+
+See dm_test_ofnode_root() for some examples.
Internal implementation
@@ -281,6 +333,6 @@ Live tree support was introduced in U-Boot 2017.07. There is still quite a bit
of work to do to flesh this out:
- tests for all access functions
-- support for livetree modification
+- more support for livetree modification
- addition of more access functions as needed
- support for livetree in SPL and before relocation (if desired)
diff --git a/doc/develop/index.rst b/doc/develop/index.rst
index 7c41e3f1b6e..c94c7fe0efa 100644
--- a/doc/develop/index.rst
+++ b/doc/develop/index.rst
@@ -39,6 +39,7 @@ Implementation
smbios
spl
uefi/index
+ vbe
version
Debugging
diff --git a/doc/develop/vbe.rst b/doc/develop/vbe.rst
new file mode 100644
index 00000000000..8f147fd9360
--- /dev/null
+++ b/doc/develop/vbe.rst
@@ -0,0 +1,26 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Verified Boot for Embedded (VBE)
+================================
+
+Introduction
+------------
+
+VBE provides a standard boot mechanism for embedded systems. If defines
+how firmware and Operating Systems are located, updated and verified.
+
+Within U-Boot, one or more VBE bootmeths implement the boot logic. For example,
+the vbe-simple bootmeth handles finding the firmware (e.g. in MMC) and starting
+it. Typically the bootmeth is started up in VPL and controls which SPL and
+U-Boot binaries are loaded.
+
+A 'vbe' command provides access to various aspects of VBE's operation, including
+listing methods and getting the status for a method.
+
+For a detailed overview of VBE, see vbe-intro_. A fuller description of
+bootflows is at vbe-bootflows_ and the firmware-update mechanism is described at
+vbe-fwupdate_.
+
+.. _vbe-intro: https://docs.google.com/document/d/e/2PACX-1vQjXLPWMIyVktaTMf8edHZYDrEvMYD_iNzIj1FgPmKF37fpglAC47Tt5cvPBC5fvTdoK-GA5Zv1wifo/pub
+.. _vbe-bootflows: https://docs.google.com/document/d/e/2PACX-1vR0OzhuyRJQ8kdeOibS3xB1rVFy3J4M_QKTM5-3vPIBNcdvR0W8EXu9ymG-yWfqthzWoM4JUNhqwydN/pub
+.. _vbe-fwupdate: https://docs.google.com/document/d/e/2PACX-1vTnlIL17vVbl6TVoTHWYMED0bme7oHHNk-g5VGxblbPiKIdGDALE1HKId8Go5f0g1eziLsv4h9bocbk/pub
diff --git a/doc/usage/cmd/bootmeth.rst b/doc/usage/cmd/bootmeth.rst
index 9fc7ebf0abf..29d8215a0c0 100644
--- a/doc/usage/cmd/bootmeth.rst
+++ b/doc/usage/cmd/bootmeth.rst
@@ -31,7 +31,9 @@ scanning bootdevs, each bootmeth is tried in turn to see if it can find a valid
bootflow. You can use this command to adjust the order or even to omit some
boomeths.
-The argument is a quoted list of bootmeths to use, by name.
+The argument is a quoted list of bootmeths to use, by name. If global bootmeths
+are included, they must be at the end, otherwise the scanning mechanism will not
+work correctly.
bootmeth list
@@ -47,14 +49,15 @@ Order Seq Name Description
1 1 efi EFI boot from an .efi file
2 2 pxe PXE boot from a network device
3 3 sandbox Sandbox boot for testing
- 4 4 efi_mgr EFI bootmgr flow
+ glob 4 efi_mgr EFI bootmgr flow
===== === ================== =================================
The fields are as follows:
Order:
The order in which these bootmeths are invoked for each bootdev. If this
- shows as a hyphen, then the bootmeth is not in the current ordering.
+ shows as a hyphen, then the bootmeth is not in the current ordering. If it
+ shows as 'glob', then this is a global bootmeth and should be at the end.
Seq:
The sequence number of the bootmeth, i.e. the normal ordering if none is set
diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c
index cdc5ba6ad90..7ebead6bfad 100644
--- a/drivers/bios_emulator/atibios.c
+++ b/drivers/bios_emulator/atibios.c
@@ -51,7 +51,7 @@
#include <errno.h>
#include <log.h>
#include <malloc.h>
-#include <vbe.h>
+#include <vesa.h>
#include <linux/delay.h>
#include "biosemui.h"
@@ -83,13 +83,13 @@ static const void *bios_ptr(const void *buf, BE_VGAInfo *vga_info,
}
static int atibios_debug_mode(BE_VGAInfo *vga_info, RMREGS *regs,
- int vesa_mode, struct vbe_mode_info *mode_info)
+ int vesa_mode, struct vesa_state *mode_info)
{
void *buffer = (void *)(M.mem_base + vbe_offset);
u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
u16 buffer_adr = ((unsigned long)vbe_offset) & 0xffff;
struct vesa_mode_info *vm;
- struct vbe_info *info;
+ struct vesa_bios_ext_info *info;
const u16 *modes_bios, *ptr;
u16 *modes;
int size;
@@ -140,7 +140,7 @@ static int atibios_debug_mode(BE_VGAInfo *vga_info, RMREGS *regs,
int attr;
debug("Mode %x: ", mode);
- memset(buffer, '\0', sizeof(struct vbe_mode_info));
+ memset(buffer, '\0', sizeof(struct vesa_state));
regs->e.eax = VESA_GET_MODE_INFO;
regs->e.ebx = 0;
regs->e.ecx = mode;
@@ -174,7 +174,7 @@ static int atibios_debug_mode(BE_VGAInfo *vga_info, RMREGS *regs,
}
static int atibios_set_vesa_mode(RMREGS *regs, int vesa_mode,
- struct vbe_mode_info *mode_info)
+ struct vesa_state *mode_info)
{
void *buffer = (void *)(M.mem_base + vbe_offset);
u16 buffer_seg = (((unsigned long)vbe_offset) >> 4) & 0xff00;
@@ -192,7 +192,7 @@ static int atibios_set_vesa_mode(RMREGS *regs, int vesa_mode,
return -ENOSYS;
}
- memset(buffer, '\0', sizeof(struct vbe_mode_info));
+ memset(buffer, '\0', sizeof(struct vesa_state));
debug("VBE: Geting info for VESA mode %#04x\n", vesa_mode);
regs->e.eax = VESA_GET_MODE_INFO;
regs->e.ecx = vesa_mode;
@@ -231,7 +231,7 @@ at this stage the controller has its I/O and memory space enabled and
that all other controllers are in a disabled state.
****************************************************************************/
static void PCI_doBIOSPOST(struct udevice *pcidev, BE_VGAInfo *vga_info,
- int vesa_mode, struct vbe_mode_info *mode_info)
+ int vesa_mode, struct vesa_state *mode_info)
{
RMREGS regs;
RMSREGS sregs;
@@ -416,7 +416,7 @@ image we can extract over the PCI bus.
****************************************************************************/
static int PCI_postController(struct udevice *pcidev, uchar *bios_rom,
int bios_len, BE_VGAInfo *vga_info,
- int vesa_mode, struct vbe_mode_info *mode_info)
+ int vesa_mode, struct vesa_state *mode_info)
{
u32 bios_image_len;
uchar *mapped_bios;
@@ -496,7 +496,7 @@ void biosemu_set_interrupt_handler(int intnum, int (*int_func)(void))
int biosemu_run(struct udevice *pcidev, uchar *bios_rom, int bios_len,
BE_VGAInfo *vga_info, int clean_up, int vesa_mode,
- struct vbe_mode_info *mode_info)
+ struct vesa_state *mode_info)
{
/*Post all the display controller BIOS'es*/
if (!PCI_postController(pcidev, bios_rom, bios_len, vga_info,
diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c
index c20b19cb50f..a52f5a6b18b 100644
--- a/drivers/core/of_access.c
+++ b/drivers/core/of_access.c
@@ -343,24 +343,30 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent,
#define for_each_property_of_node(dn, pp) \
for (pp = dn->properties; pp != NULL; pp = pp->next)
-struct device_node *of_find_node_opts_by_path(const char *path,
+struct device_node *of_find_node_opts_by_path(struct device_node *root,
+ const char *path,
const char **opts)
{
struct device_node *np = NULL;
struct property *pp;
const char *separator = strchr(path, ':');
+ if (!root)
+ root = gd->of_root;
if (opts)
*opts = separator ? separator + 1 : NULL;
if (strcmp(path, "/") == 0)
- return of_node_get(gd->of_root);
+ return of_node_get(root);
/* The path could begin with an alias */
if (*path != '/') {
int len;
const char *p = separator;
+ /* Only allow alias processing on the control FDT */
+ if (root != gd->of_root)
+ return NULL;
if (!p)
p = strchrnul(path, '/');
len = p - path;
@@ -383,7 +389,7 @@ struct device_node *of_find_node_opts_by_path(const char *path,
/* Step down the tree matching path components */
if (!np)
- np = of_node_get(gd->of_root);
+ np = of_node_get(root);
while (np && *path == '/') {
struct device_node *tmp = np;
@@ -791,7 +797,7 @@ int of_alias_scan(void)
name = of_get_property(of_chosen, "stdout-path", NULL);
if (name)
- of_stdout = of_find_node_opts_by_path(name,
+ of_stdout = of_find_node_opts_by_path(NULL, name,
&of_stdout_options);
}
@@ -881,3 +887,46 @@ struct device_node *of_get_stdout(void)
{
return of_stdout;
}
+
+int of_write_prop(struct device_node *np, const char *propname, int len,
+ const void *value)
+{
+ struct property *pp;
+ struct property *pp_last = NULL;
+ struct property *new;
+
+ if (!np)
+ return -EINVAL;
+
+ for (pp = np->properties; pp; pp = pp->next) {
+ if (strcmp(pp->name, propname) == 0) {
+ /* Property exists -> change value */
+ pp->value = (void *)value;
+ pp->length = len;
+ return 0;
+ }
+ pp_last = pp;
+ }
+
+ if (!pp_last)
+ return -ENOENT;
+
+ /* Property does not exist -> append new property */
+ new = malloc(sizeof(struct property));
+ if (!new)
+ return -ENOMEM;
+
+ new->name = strdup(propname);
+ if (!new->name) {
+ free(new);
+ return -ENOMEM;
+ }
+
+ new->value = (void *)value;
+ new->length = len;
+ new->next = NULL;
+
+ pp_last->next = new;
+
+ return 0;
+}
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index a59832ebbfb..45ea84e9fb8 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -552,6 +552,17 @@ ofnode ofnode_path(const char *path)
return offset_to_ofnode(fdt_path_offset(gd->fdt_blob, path));
}
+ofnode ofnode_path_root(oftree tree, const char *path)
+{
+ if (of_live_active())
+ return np_to_ofnode(of_find_node_opts_by_path(tree.np, path,
+ NULL));
+ else if (*path != '/' && tree.fdt != gd->fdt_blob)
+ return ofnode_null(); /* Aliases only on control FDT */
+ else
+ return offset_to_ofnode(fdt_path_offset(tree.fdt, path));
+}
+
const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
{
ofnode chosen_node;
@@ -1094,70 +1105,44 @@ ofnode ofnode_by_prop_value(ofnode from, const char *propname,
}
}
-int ofnode_write_prop(ofnode node, const char *propname, int len,
- const void *value)
+int ofnode_write_prop(ofnode node, const char *propname, const void *value,
+ int len)
{
- const struct device_node *np = ofnode_to_np(node);
- struct property *pp;
- struct property *pp_last = NULL;
- struct property *new;
-
- if (!of_live_active())
- return -ENOSYS;
-
- if (!np)
- return -EINVAL;
-
- for (pp = np->properties; pp; pp = pp->next) {
- if (strcmp(pp->name, propname) == 0) {
- /* Property exists -> change value */
- pp->value = (void *)value;
- pp->length = len;
- return 0;
- }
- pp_last = pp;
- }
-
- if (!pp_last)
- return -ENOENT;
-
- /* Property does not exist -> append new property */
- new = malloc(sizeof(struct property));
- if (!new)
- return -ENOMEM;
+ if (of_live_active())
+ return of_write_prop(ofnode_to_npw(node), propname, len, value);
+ else
+ return fdt_setprop((void *)gd->fdt_blob, ofnode_to_offset(node),
+ propname, value, len);
- new->name = strdup(propname);
- if (!new->name) {
- free(new);
- return -ENOMEM;
- }
+ return 0;
+}
- new->value = (void *)value;
- new->length = len;
- new->next = NULL;
+int ofnode_write_string(ofnode node, const char *propname, const char *value)
+{
+ assert(ofnode_valid(node));
- pp_last->next = new;
+ debug("%s: %s = %s", __func__, propname, value);
- return 0;
+ return ofnode_write_prop(node, propname, value, strlen(value) + 1);
}
-int ofnode_write_string(ofnode node, const char *propname, const char *value)
+int ofnode_write_u32(ofnode node, const char *propname, u32 value)
{
- if (!of_live_active())
- return -ENOSYS;
+ fdt32_t *val;
assert(ofnode_valid(node));
- debug("%s: %s = %s", __func__, propname, value);
+ log_debug("%s = %x", propname, value);
+ val = malloc(sizeof(*val));
+ if (!val)
+ return -ENOMEM;
+ *val = cpu_to_fdt32(value);
- return ofnode_write_prop(node, propname, strlen(value) + 1, value);
+ return ofnode_write_prop(node, propname, val, sizeof(value));
}
int ofnode_set_enabled(ofnode node, bool value)
{
- if (!of_live_active())
- return -ENOSYS;
-
assert(ofnode_valid(node));
if (value)
diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c
index 73d15e797fc..27a24daa12a 100644
--- a/drivers/pci/pci_rom.c
+++ b/drivers/pci/pci_rom.c
@@ -34,7 +34,7 @@
#include <malloc.h>
#include <pci.h>
#include <pci_rom.h>
-#include <vbe.h>
+#include <vesa.h>
#include <video.h>
#include <acpi/acpi_s3.h>
#include <asm/global_data.h>
@@ -202,7 +202,7 @@ static int pci_rom_load(struct pci_rom_header *rom_header,
return 0;
}
-struct vbe_mode_info mode_info;
+struct vesa_state mode_info;
void setup_video(struct screen_info *screen_info)
{
@@ -326,9 +326,9 @@ err:
}
#ifdef CONFIG_DM_VIDEO
-int vbe_setup_video_priv(struct vesa_mode_info *vesa,
- struct video_priv *uc_priv,
- struct video_uc_plat *plat)
+int vesa_setup_video_priv(struct vesa_mode_info *vesa,
+ struct video_priv *uc_priv,
+ struct video_uc_plat *plat)
{
if (!vesa->x_resolution)
return log_msg_ret("No x resolution", -ENXIO);
@@ -358,7 +358,7 @@ int vbe_setup_video_priv(struct vesa_mode_info *vesa,
return 0;
}
-int vbe_setup_video(struct udevice *dev, int (*int15_handler)(void))
+int vesa_setup_video(struct udevice *dev, int (*int15_handler)(void))
{
struct video_uc_plat *plat = dev_get_uclass_plat(dev);
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
@@ -378,7 +378,7 @@ int vbe_setup_video(struct udevice *dev, int (*int15_handler)(void))
return ret;
}
- ret = vbe_setup_video_priv(&mode_info.vesa, uc_priv, plat);
+ ret = vesa_setup_video_priv(&mode_info.vesa, uc_priv, plat);
if (ret) {
if (ret == -ENFILE) {
/*
diff --git a/drivers/video/broadwell_igd.c b/drivers/video/broadwell_igd.c
index 2551f162e8f..6aa4e27071d 100644
--- a/drivers/video/broadwell_igd.c
+++ b/drivers/video/broadwell_igd.c
@@ -11,7 +11,7 @@
#include <dm.h>
#include <init.h>
#include <log.h>
-#include <vbe.h>
+#include <vesa.h>
#include <video.h>
#include <asm/cpu.h>
#include <asm/global_data.h>
@@ -681,7 +681,7 @@ static int broadwell_igd_probe(struct udevice *dev)
debug("%s: is_broadwell=%d\n", __func__, is_broadwell);
ret = igd_pre_init(dev, is_broadwell);
if (!ret) {
- ret = vbe_setup_video(dev, broadwell_igd_int15_handler);
+ ret = vesa_setup_video(dev, broadwell_igd_int15_handler);
if (ret)
debug("failed to run video BIOS: %d\n", ret);
}
diff --git a/drivers/video/coreboot.c b/drivers/video/coreboot.c
index 7237542c076..d2d87c75c89 100644
--- a/drivers/video/coreboot.c
+++ b/drivers/video/coreboot.c
@@ -6,7 +6,7 @@
#include <common.h>
#include <dm.h>
#include <init.h>
-#include <vbe.h>
+#include <vesa.h>
#include <video.h>
#include <asm/cb_sysinfo.h>
@@ -57,7 +57,7 @@ static int coreboot_video_probe(struct udevice *dev)
goto err;
}
- ret = vbe_setup_video_priv(vesa, uc_priv, plat);
+ ret = vesa_setup_video_priv(vesa, uc_priv, plat);
if (ret) {
ret = log_msg_ret("setup", ret);
goto err;
diff --git a/drivers/video/efi.c b/drivers/video/efi.c
index 5f9031f2ec5..b11e42c0ebf 100644
--- a/drivers/video/efi.c
+++ b/drivers/video/efi.c
@@ -9,7 +9,7 @@
#include <dm.h>
#include <efi_api.h>
#include <log.h>
-#include <vbe.h>
+#include <vesa.h>
#include <video.h>
struct pixel {
@@ -149,7 +149,7 @@ static int efi_video_probe(struct udevice *dev)
if (ret)
goto err;
- ret = vbe_setup_video_priv(vesa, uc_priv, plat);
+ ret = vesa_setup_video_priv(vesa, uc_priv, plat);
if (ret)
goto err;
diff --git a/drivers/video/ivybridge_igd.c b/drivers/video/ivybridge_igd.c
index 1aa5317dd5f..9264dd6770d 100644
--- a/drivers/video/ivybridge_igd.c
+++ b/drivers/video/ivybridge_igd.c
@@ -10,7 +10,7 @@
#include <fdtdec.h>
#include <log.h>
#include <pci_rom.h>
-#include <vbe.h>
+#include <vesa.h>
#include <video.h>
#include <asm/global_data.h>
#include <asm/intel_regs.h>
@@ -762,7 +762,7 @@ static int bd82x6x_video_probe(struct udevice *dev)
rev = gma_func0_init(dev);
if (rev < 0)
return rev;
- ret = vbe_setup_video(dev, int15_handler);
+ ret = vesa_setup_video(dev, int15_handler);
if (ret)
return ret;
diff --git a/drivers/video/vesa.c b/drivers/video/vesa.c
index 869e5469732..cac3bb0c331 100644
--- a/drivers/video/vesa.c
+++ b/drivers/video/vesa.c
@@ -7,7 +7,7 @@
#include <dm.h>
#include <log.h>
#include <pci.h>
-#include <vbe.h>
+#include <vesa.h>
#include <video.h>
#include <asm/mtrr.h>
@@ -17,7 +17,7 @@ static int vesa_video_probe(struct udevice *dev)
ulong fbbase;
int ret;
- ret = vbe_setup_video(dev, NULL);
+ ret = vesa_setup_video(dev, NULL);
if (ret)
return log_ret(ret);
diff --git a/include/bios_emul.h b/include/bios_emul.h
index 72410dc7948..a7e6d73972c 100644
--- a/include/bios_emul.h
+++ b/include/bios_emul.h
@@ -36,14 +36,14 @@ typedef struct {
u8 LowMem[1536];
} BE_VGAInfo;
-struct vbe_mode_info;
+struct vesa_state;
int BootVideoCardBIOS(struct udevice *pcidev, BE_VGAInfo **pVGAInfo,
int clean_up);
/* Run a BIOS ROM natively (only supported on x86 machines) */
void bios_run_on_x86(struct udevice *dev, unsigned long addr, int vesa_mode,
- struct vbe_mode_info *mode_info);
+ struct vesa_state *mode_info);
/**
* bios_set_interrupt_handler() - Install an interrupt handler for the BIOS
@@ -61,6 +61,6 @@ int biosemu_setup(struct udevice *pcidev, BE_VGAInfo **pVGAInfo);
int biosemu_run(struct udevice *dev, uchar *bios_rom, int bios_len,
BE_VGAInfo *vga_info, int clean_up, int vesa_mode,
- struct vbe_mode_info *mode_info);
+ struct vesa_state *mode_info);
#endif
diff --git a/include/bootflow.h b/include/bootflow.h
index c30ba042a48..6aa3d1fff8d 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -77,12 +77,14 @@ struct bootflow {
* @BOOTFLOWF_SHOW: Show each bootdev before scanning it
* @BOOTFLOWF_ALL: Return bootflows with errors as well
* @BOOTFLOWF_SINGLE_DEV: Just scan one bootmeth
+ * @BOOTFLOWF_SKIP_GLOBAL: Don't scan global bootmeths
*/
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,
};
/**
@@ -102,8 +104,10 @@ enum bootflow_flags_t {
* updated to a larger value, no less than the number of available partitions.
* This ensures that iteration works through all partitions on the bootdev.
*
- * @flags: Flags to use (see enum bootflow_flags_t)
- * @dev: Current bootdev
+ * @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
* @part: Current partition number (0 for whole device)
* @method: Current bootmeth
* @max_part: Maximum hardware partition number in @dev, 0 if there is no
@@ -117,7 +121,11 @@ enum bootflow_flags_t {
* with the first one on the list
* @num_methods: Number of bootmeth devices in @method_order
* @cur_method: Current method number, an index into @method_order
- * @method_order: List of bootmeth devices to use, in order
+ * @first_glob_method: First global method, if any, else -1
+ * @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)
*/
struct bootflow_iter {
int flags;
@@ -131,7 +139,9 @@ struct bootflow_iter {
struct udevice **dev_order;
int num_methods;
int cur_method;
+ int first_glob_method;
struct udevice **method_order;
+ bool doing_global;
};
/**
@@ -169,9 +179,9 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter,
* 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
+ * finds one that can supply a bootflow
* @iter: Place to store private info (inited by this call)
- * @flags: Flags for bootdev (enum bootflow_flags_t)
+ * @flags: Flags for iterator (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)
diff --git a/include/bootmeth.h b/include/bootmeth.h
index 484e503e338..50ded055f3f 100644
--- a/include/bootmeth.h
+++ b/include/bootmeth.h
@@ -13,18 +13,47 @@ struct bootflow_iter;
struct udevice;
/**
+ * enum bootmeth_flags - Flags for bootmeths
+ *
+ * @BOOTMETHF_GLOBAL: bootmeth handles bootdev selection automatically
+ */
+enum bootmeth_flags {
+ BOOTMETHF_GLOBAL = BIT(0),
+};
+
+/**
* struct bootmeth_uc_plat - information the uclass keeps about each bootmeth
*
* @desc: A long description of the bootmeth
+ * @flags: Flags for this bootmeth (enum bootmeth_flags)
*/
struct bootmeth_uc_plat {
const char *desc;
+ int flags;
};
/** struct bootmeth_ops - Operations for boot methods */
struct bootmeth_ops {
/**
- * check_supported() - check if a bootmeth supports this bootflow
+ * get_state_desc() - get detailed state information
+ *
+ * Prodecues a textual description of the state of the bootmeth. This
+ * can include newline characters if it extends to multiple lines. It
+ * must be a nul-terminated string.
+ *
+ * This may involve reading state from the system, e.g. some data in
+ * the firmware area.
+ *
+ * @dev: Bootmethod device to check
+ * @buf: Buffer to place the info in (terminator must fit)
+ * @maxsize: Size of buffer
+ * Returns: 0 if OK, -ENOSPC is buffer is too small, other -ve error if
+ * something else went wrong
+ */
+ int (*get_state_desc)(struct udevice *dev, char *buf, int maxsize);
+
+ /**
+ * check_supported() - check if a bootmeth supports this bootdev
*
* This is optional. If not provided, the bootdev is assumed to be
* supported
@@ -92,6 +121,24 @@ struct bootmeth_ops {
#define bootmeth_get_ops(dev) ((struct bootmeth_ops *)(dev)->driver->ops)
/**
+ * bootmeth_get_state_desc() - get detailed state information
+ *
+ * Prodecues a textual description of the state of the bootmeth. This
+ * can include newline characters if it extends to multiple lines. It
+ * must be a nul-terminated string.
+ *
+ * This may involve reading state from the system, e.g. some data in
+ * the firmware area.
+ *
+ * @dev: Bootmethod device to check
+ * @buf: Buffer to place the info in (terminator must fit)
+ * @maxsize: Size of buffer
+ * Returns: 0 if OK, -ENOSPC is buffer is too small, other -ve error if
+ * something else went wrong
+ */
+int bootmeth_get_state_desc(struct udevice *dev, char *buf, int maxsize);
+
+/**
* bootmeth_check() - check if a bootmeth supports this bootflow
*
* This is optional. If not provided, the bootdev is assumed to be
@@ -162,10 +209,12 @@ int bootmeth_boot(struct udevice *dev, struct bootflow *bflow);
* ordering there, then all bootmethods are added
*
* @iter: Iterator to update with the order
+ * @include_global: true to add the global bootmeths, in which case they appear
+ * first
* Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve
* on other error
*/
-int bootmeth_setup_iter_order(struct bootflow_iter *iter);
+int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global);
/**
* bootmeth_set_order() - Set the bootmeth order
@@ -231,4 +280,16 @@ int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align);
int bootmeth_common_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep);
+/**
+ * bootmeth_get_bootflow() - Get a bootflow from a global bootmeth
+ *
+ * Check the bootmeth for a bootflow which can be used. In this case the
+ * bootmeth handles all bootdev selection, etc.
+ *
+ * @dev: bootmeth device to read from
+ * @bflow: Bootflow information
+ * @return 0 on success, -ve if a bootflow could not be found or had an error
+ */
+int bootmeth_get_bootflow(struct udevice *dev, struct bootflow *bflow);
+
#endif
diff --git a/include/bootstd.h b/include/bootstd.h
index b002365f4f0..01be249d16e 100644
--- a/include/bootstd.h
+++ b/include/bootstd.h
@@ -26,6 +26,7 @@ struct udevice;
* @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
+ * @vbe_bootmeth: Currently selected VBE bootmeth, NULL if none
*/
struct bootstd_priv {
const char **prefixes;
@@ -35,6 +36,7 @@ struct bootstd_priv {
struct list_head glob_head;
int bootmeth_count;
struct udevice **bootmeth_order;
+ struct udevice *vbe_bootmeth;
};
/**
diff --git a/include/dm/of_access.h b/include/dm/of_access.h
index ec6e6e2c7c0..5b7821d0a1b 100644
--- a/include/dm/of_access.h
+++ b/include/dm/of_access.h
@@ -197,6 +197,11 @@ struct device_node *of_get_parent(const struct device_node *np);
/**
* of_find_node_opts_by_path() - Find a node matching a full OF path
*
+ * Note that alias processing is only available on the control FDT (gd->of_root).
+ * For other trees it is skipped, so any attempt to obtain an alias will result
+ * in returning NULL.
+ *
+ * @root: Root node of the tree to use. If this is NULL, then gd->of_root is used
* @path: Either the full path to match, or if the path does not start with
* '/', the name of a property of the /aliases node (an alias). In the
* case of an alias, the node matching the alias' value will be returned.
@@ -210,12 +215,13 @@ struct device_node *of_get_parent(const struct device_node *np);
*
* Return: a node pointer or NULL if not found
*/
-struct device_node *of_find_node_opts_by_path(const char *path,
+struct device_node *of_find_node_opts_by_path(struct device_node *root,
+ const char *path,
const char **opts);
static inline struct device_node *of_find_node_by_path(const char *path)
{
- return of_find_node_opts_by_path(path, NULL);
+ return of_find_node_opts_by_path(NULL, path, NULL);
}
/**
@@ -513,4 +519,16 @@ int of_alias_get_highest_id(const char *stem);
*/
struct device_node *of_get_stdout(void);
+/**
+ * of_write_prop() - Write a property to the device tree
+ *
+ * @np: device node to which the property value is to be written
+ * @propname: name of the property to write
+ * @value: value of the property
+ * @len: length of the property in bytes
+ * Returns: 0 if OK, -ve on error
+ */
+int of_write_prop(struct device_node *np, const char *propname, int len,
+ const void *value);
+
#endif
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index bb60433124b..7ce1e4c6d91 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -19,41 +19,7 @@
struct resource;
-/**
- * typedef union ofnode_union ofnode - reference to a device tree node
- *
- * This union can hold either a straightforward pointer to a struct device_node
- * in the live device tree, or an offset within the flat device tree. In the
- * latter case, the pointer value is just the integer offset within the flat DT.
- *
- * Thus we can reference nodes in both the live tree (once available) and the
- * flat tree (until then). Functions are available to translate between an
- * ofnode and either an offset or a `struct device_node *`.
- *
- * The reference can also hold a null offset, in which case the pointer value
- * here is NULL. This corresponds to a struct device_node * value of
- * NULL, or an offset of -1.
- *
- * There is no ambiguity as to whether ofnode holds an offset or a node
- * pointer: when the live tree is active it holds a node pointer, otherwise it
- * holds an offset. The value itself does not need to be unique and in theory
- * the same value could point to a valid device node or a valid offset. We
- * could arrange for a unique value to be used (e.g. by making the pointer
- * point to an offset within the flat device tree in the case of an offset) but
- * this increases code size slightly due to the subtraction. Since it offers no
- * real benefit, the approach described here seems best.
- *
- * For now these points use constant types, since we don't allow writing
- * the DT.
- *
- * @np: Pointer to device node, used for live tree
- * @of_offset: Pointer into flat device tree, used for flat tree. Note that this
- * is not a really a pointer to a node: it is an offset value. See above.
- */
-typedef union ofnode_union {
- const struct device_node *np;
- long of_offset;
-} ofnode;
+#include <dm/ofnode_decl.h>
struct ofnode_phandle_args {
ofnode node;
@@ -62,45 +28,38 @@ struct ofnode_phandle_args {
};
/**
- * struct ofprop - reference to a property of a device tree node
- *
- * This struct hold the reference on one property of one node,
- * using struct ofnode and an offset within the flat device tree or either
- * a pointer to a struct property in the live device tree.
- *
- * Thus we can reference arguments in both the live tree and the flat tree.
+ * ofnode_to_np() - convert an ofnode to a live DT node pointer
*
- * The property reference can also hold a null reference. This corresponds to
- * a struct property NULL pointer or an offset of -1.
+ * This cannot be called if the reference contains an offset.
*
- * @node: Pointer to device node
- * @offset: Pointer into flat device tree, used for flat tree.
- * @prop: Pointer to property, used for live treee.
+ * @node: Reference containing struct device_node * (possibly invalid)
+ * Return: pointer to device node (can be NULL)
*/
-
-struct ofprop {
- ofnode node;
- union {
- int offset;
- const struct property *prop;
- };
-};
+static inline const struct device_node *ofnode_to_np(ofnode node)
+{
+#ifdef OF_CHECKS
+ if (!of_live_active())
+ return NULL;
+#endif
+ return node.np;
+}
/**
- * ofnode_to_np() - convert an ofnode to a live DT node pointer
+ * ofnode_to_npw() - convert an ofnode to a writeable live DT node pointer
*
* This cannot be called if the reference contains an offset.
*
* @node: Reference containing struct device_node * (possibly invalid)
* Return: pointer to device node (can be NULL)
*/
-static inline const struct device_node *ofnode_to_np(ofnode node)
+static inline struct device_node *ofnode_to_npw(ofnode node)
{
#ifdef OF_CHECKS
if (!of_live_active())
return NULL;
#endif
- return node.np;
+ /* Drop constant */
+ return (struct device_node *)node.np;
}
/**
@@ -236,6 +195,23 @@ static inline ofnode ofnode_root(void)
}
/**
+ * oftree_default() - Returns the default device tree (U-Boot's control FDT)
+ *
+ * Returns: reference to the control FDT
+ */
+static inline oftree oftree_default(void)
+{
+ oftree tree;
+
+ if (of_live_active())
+ tree.np = gd_of_root();
+ else
+ tree.fdt = (void *)gd->fdt_blob;
+
+ return tree;
+}
+
+/**
* ofnode_name_eq() - Check if the node name is equivalent to a given name
* ignoring the unit address
*
@@ -699,12 +675,23 @@ int ofnode_count_phandle_with_args(ofnode node, const char *list_name,
/**
* ofnode_path() - find a node by full path
*
+ * This uses the control FDT.
+ *
* @path: Full path to node, e.g. "/bus/spi@1"
* Return: reference to the node found. Use ofnode_valid() to check if it exists
*/
ofnode ofnode_path(const char *path);
/**
+ * ofnode_path_root() - find a node by full path from a root node
+ *
+ * @tree: Device tree to use
+ * @path: Full path to node, e.g. "/bus/spi@1"
+ * Return: reference to the node found. Use ofnode_valid() to check if it exists
+ */
+ofnode ofnode_path_root(oftree tree, const char *path);
+
+/**
* ofnode_read_chosen_prop() - get the value of a chosen property
*
* This looks for a property within the /chosen node and returns its value
@@ -1140,17 +1127,18 @@ int ofnode_device_is_compatible(ofnode node, const char *compat);
* ofnode_write_prop() - Set a property of a ofnode
*
* Note that the value passed to the function is *not* allocated by the
- * function itself, but must be allocated by the caller if necessary.
+ * function itself, but must be allocated by the caller if necessary. However
+ * it does allocate memory for the property struct and name.
*
* @node: The node for whose property should be set
* @propname: The name of the property to set
- * @len: The length of the new value of the property
* @value: The new value of the property (must be valid prior to calling
* the function)
+ * @len: The length of the new value of the property
* Return: 0 if successful, -ve on error
*/
-int ofnode_write_prop(ofnode node, const char *propname, int len,
- const void *value);
+int ofnode_write_prop(ofnode node, const char *propname, const void *value,
+ int len);
/**
* ofnode_write_string() - Set a string property of a ofnode
@@ -1167,6 +1155,16 @@ int ofnode_write_prop(ofnode node, const char *propname, int len,
int ofnode_write_string(ofnode node, const char *propname, const char *value);
/**
+ * ofnode_write_u32() - Set an integer property of an ofnode
+ *
+ * @node: The node for whose string property should be set
+ * @propname: The name of the string property to set
+ * @value: The new value of the 32-bit integer property
+ * Return: 0 if successful, -ve on error
+ */
+int ofnode_write_u32(ofnode node, const char *propname, u32 value);
+
+/**
* ofnode_set_enabled() - Enable or disable a device tree node given by its
* ofnode
*
diff --git a/include/dm/ofnode_decl.h b/include/dm/ofnode_decl.h
new file mode 100644
index 00000000000..266253d5e33
--- /dev/null
+++ b/include/dm/ofnode_decl.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef _DM_OFNODE_DECL_H
+#define _DM_OFNODE_DECL_H
+
+/**
+ * typedef union ofnode_union ofnode - reference to a device tree node
+ *
+ * This union can hold either a straightforward pointer to a struct device_node
+ * in the live device tree, or an offset within the flat device tree. In the
+ * latter case, the pointer value is just the integer offset within the flat DT.
+ *
+ * Thus we can reference nodes in both the live tree (once available) and the
+ * flat tree (until then). Functions are available to translate between an
+ * ofnode and either an offset or a `struct device_node *`.
+ *
+ * The reference can also hold a null offset, in which case the pointer value
+ * here is NULL. This corresponds to a struct device_node * value of
+ * NULL, or an offset of -1.
+ *
+ * There is no ambiguity as to whether ofnode holds an offset or a node
+ * pointer: when the live tree is active it holds a node pointer, otherwise it
+ * holds an offset. The value itself does not need to be unique and in theory
+ * the same value could point to a valid device node or a valid offset. We
+ * could arrange for a unique value to be used (e.g. by making the pointer
+ * point to an offset within the flat device tree in the case of an offset) but
+ * this increases code size slightly due to the subtraction. Since it offers no
+ * real benefit, the approach described here seems best.
+ *
+ * For now these points use constant types, since we don't allow writing
+ * the DT.
+ *
+ * @np: Pointer to device node, used for live tree
+ * @of_offset: Pointer into flat device tree, used for flat tree. Note that this
+ * is not a really a pointer to a node: it is an offset value. See above.
+ */
+typedef union ofnode_union {
+ const struct device_node *np;
+ long of_offset;
+} ofnode;
+
+/**
+ * struct ofprop - reference to a property of a device tree node
+ *
+ * This struct hold the reference on one property of one node,
+ * using struct ofnode and an offset within the flat device tree or either
+ * a pointer to a struct property in the live device tree.
+ *
+ * Thus we can reference arguments in both the live tree and the flat tree.
+ *
+ * The property reference can also hold a null reference. This corresponds to
+ * a struct property NULL pointer or an offset of -1.
+ *
+ * @node: Pointer to device node
+ * @offset: Pointer into flat device tree, used for flat tree.
+ * @prop: Pointer to property, used for live treee.
+ */
+
+struct ofprop {
+ ofnode node;
+ union {
+ int offset;
+ const struct property *prop;
+ };
+};
+
+/**
+ * union oftree_union - reference to a tree of device tree nodes
+ *
+ * One or other of the members is used, depending on of_live_active()
+ *
+ * @np: Pointer to roott device node, used for live tree
+ * @fdt: Pointer to the flat device tree, used for flat tree
+ */
+typedef union oftree_union {
+ struct device_node *np;
+ void *fdt;
+} oftree;
+
+#endif
+
diff --git a/include/event.h b/include/event.h
index c00c4fb68dc..e8f2f55c63d 100644
--- a/include/event.h
+++ b/include/event.h
@@ -10,6 +10,8 @@
#ifndef __event_h
#define __event_h
+#include <dm/ofnode_decl.h>
+
/**
* enum event_t - Types of events supported by U-Boot
*
@@ -29,6 +31,9 @@ enum event_t {
/* Init hooks */
EVT_MISC_INIT_F,
+ /* Device tree fixups before booting */
+ EVT_FT_FIXUP,
+
EVT_COUNT
};
@@ -50,6 +55,15 @@ union event_data {
struct event_dm {
struct udevice *dev;
} dm;
+
+ /**
+ * struct event_ft_fixup - FDT fixup before booting
+ *
+ * @tree: tree to update
+ */
+ struct event_ft_fixup {
+ oftree tree;
+ } ft_fixup;
};
/**
@@ -123,10 +137,13 @@ static inline const char *event_spy_id(struct evspy_info *spy)
* The only solution I can think of is to mark linker-list entries as 'used'
* using an attribute. This should be safe, since we don't actually want to drop
* any of these. However this does slightly limit LTO's optimisation choices.
+ *
+ * Another issue has come up, only with clang: using 'static' makes it throw
+ * away the linker-list entry sometimes, e.g. with the EVT_FT_FIXUP entry in
+ * vbe_simple.c - so for now, make it global.
*/
#define EVENT_SPY(_type, _func) \
- static __attribute__((used)) ll_entry_declare(struct evspy_info, \
- _type, evspy_info) = \
+ __used ll_entry_declare(struct evspy_info, _type, evspy_info) = \
_ESPY_REC(_type, _func)
/**
diff --git a/include/of_live.h b/include/of_live.h
index b2b9679ae84..f59d6af3350 100644
--- a/include/of_live.h
+++ b/include/of_live.h
@@ -20,4 +20,20 @@ struct device_node;
*/
int of_live_build(const void *fdt_blob, struct device_node **rootp);
+/**
+ * unflatten_device_tree() - create tree of device_nodes from flat blob
+ *
+ * Note that this allocates a single block of memory, pointed to by *mynodes.
+ * To free the tree, use free(*mynodes)
+ *
+ * unflattens a device-tree, creating the
+ * tree of struct device_node. It also fills the "name" and "type"
+ * pointers of the nodes so the normal device-tree walking functions
+ * can be used.
+ * @blob: The blob to expand
+ * @mynodes: The device_node tree created by the call
+ * Return: 0 if OK, -ve on error
+ */
+int unflatten_device_tree(const void *blob, struct device_node **mynodes);
+
#endif
diff --git a/include/test/test.h b/include/test/test.h
index 0104e189f63..c888d68b1ed 100644
--- a/include/test/test.h
+++ b/include/test/test.h
@@ -46,6 +46,8 @@ enum {
UT_TESTF_CONSOLE_REC = BIT(5), /* needs console recording */
/* do extra driver model init and uninit */
UT_TESTF_DM = BIT(6),
+ /* live or flat device tree, but not both in the same executable */
+ UT_TESTF_LIVE_OR_FLAT = BIT(4),
};
/**
diff --git a/include/vbe.h b/include/vbe.h
index 1631260eb73..b83f6f0c519 100644
--- a/include/vbe.h
+++ b/include/vbe.h
@@ -1,113 +1,48 @@
-/* SPDX-License-Identifier: BSD-2-Clause */
-/******************************************************************************
- * Copyright (c) 2004, 2008 IBM Corporation
- * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
- * All rights reserved.
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Verified Boot for Embedded (VBE) support
+ * See doc/develop/vbe.rst
*
- * Contributors:
- * IBM Corporation - initial implementation
- *****************************************************************************/
-#ifndef _VBE_H
-#define _VBE_H
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
-/* these structs are for input from and output to OF */
-struct __packed vbe_screen_info {
- u8 display_type; /* 0=NONE, 1= analog, 2=digital */
- u16 screen_width;
- u16 screen_height;
- /* bytes per line in framebuffer, may be more than screen_width */
- u16 screen_linebytes;
- u8 color_depth; /* color depth in bits per pixel */
- u32 framebuffer_address;
- u8 edid_block_zero[128];
-};
+#ifndef __VBE_H
+#define __VBE_H
-struct __packed vbe_screen_info_input {
- u8 signature[4];
- u16 size_reserved;
- u8 monitor_number;
- u16 max_screen_width;
- u8 color_depth;
-};
-
-/* these structs only store the required a subset of the VBE-defined fields */
-struct __packed vbe_info {
- char signature[4];
- u16 version;
- u32 oem_string_ptr;
- u32 capabilities;
- u32 modes_ptr;
- u16 total_memory;
- u16 oem_version;
- u32 vendor_name_ptr;
- u32 product_name_ptr;
- u32 product_rev_ptr;
-};
-
-struct __packed vesa_mode_info {
- u16 mode_attributes; /* 00 */
- u8 win_a_attributes; /* 02 */
- u8 win_b_attributes; /* 03 */
- u16 win_granularity; /* 04 */
- u16 win_size; /* 06 */
- u16 win_a_segment; /* 08 */
- u16 win_b_segment; /* 0a */
- u32 win_func_ptr; /* 0c */
- u16 bytes_per_scanline; /* 10 */
- u16 x_resolution; /* 12 */
- u16 y_resolution; /* 14 */
- u8 x_charsize; /* 16 */
- u8 y_charsize; /* 17 */
- u8 number_of_planes; /* 18 */
- u8 bits_per_pixel; /* 19 */
- u8 number_of_banks; /* 20 */
- u8 memory_model; /* 21 */
- u8 bank_size; /* 22 */
- u8 number_of_image_pages; /* 23 */
- u8 reserved_page;
- u8 red_mask_size;
- u8 red_mask_pos;
- u8 green_mask_size;
- u8 green_mask_pos;
- u8 blue_mask_size;
- u8 blue_mask_pos;
- u8 reserved_mask_size;
- u8 reserved_mask_pos;
- u8 direct_color_mode_info;
- u32 phys_base_ptr;
- u32 offscreen_mem_offset;
- u16 offscreen_mem_size;
- u8 reserved[206];
-};
-
-struct vbe_mode_info {
- u16 video_mode;
- bool valid;
- union {
- struct vesa_mode_info vesa;
- u8 mode_info_block[256];
- };
-};
-
-struct vbe_ddc_info {
- u8 port_number; /* i.e. monitor number */
- u8 edid_transfer_time;
- u8 ddc_level;
- u8 edid_block_zero[128];
-};
-
-#define VESA_GET_INFO 0x4f00
-#define VESA_GET_MODE_INFO 0x4f01
-#define VESA_SET_MODE 0x4f02
-#define VESA_GET_CUR_MODE 0x4f03
+/**
+ * vbe_list() - List the VBE bootmeths
+ *
+ * This shows a list of the VBE bootmeth devices
+ *
+ * @return 0 (always)
+ */
+int vbe_list(void);
-extern struct vbe_mode_info mode_info;
+/**
+ * vbe_find_by_any() - Find a VBE bootmeth by name or sequence
+ *
+ * @name: name (e.g. "vbe-simple"), or sequence ("2") to find
+ * @devp: returns the device found, on success
+ * Return: 0 if OK, -ve on error
+ */
+int vbe_find_by_any(const char *name, struct udevice **devp);
+
+/**
+ * vbe_find_first_device() - Find the first VBE bootmeth
+ *
+ * @devp: Returns first available VBE bootmeth, or NULL if none
+ * Returns: 0 (always)
+ */
+int vbe_find_first_device(struct udevice **devp);
-struct video_priv;
-struct video_uc_plat;
-int vbe_setup_video_priv(struct vesa_mode_info *vesa,
- struct video_priv *uc_priv,
- struct video_uc_plat *plat);
-int vbe_setup_video(struct udevice *dev, int (*int15_handler)(void));
+/**
+ * vbe_find_next_device() - Find the next available VBE bootmeth
+ *
+ * @devp: Previous device to start from. Returns next available VBE bootmeth,
+ * or NULL if none
+ * Returns: 0 (always)
+ */
+int vbe_find_next_device(struct udevice **devp);
#endif
diff --git a/include/vesa.h b/include/vesa.h
new file mode 100644
index 00000000000..a42c1796863
--- /dev/null
+++ b/include/vesa.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/******************************************************************************
+ * Copyright (c) 2004, 2008 IBM Corporation
+ * Copyright (c) 2009 Pattrick Hueper <phueper@hueper.net>
+ * All rights reserved.
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+#ifndef _VESA_H
+#define _VESA_H
+
+/* these structs are for input from and output to OF */
+struct __packed vesa_screen_info {
+ u8 display_type; /* 0=NONE, 1= analog, 2=digital */
+ u16 screen_width;
+ u16 screen_height;
+ /* bytes per line in framebuffer, may be more than screen_width */
+ u16 screen_linebytes;
+ u8 color_depth; /* color depth in bits per pixel */
+ u32 framebuffer_address;
+ u8 edid_block_zero[128];
+};
+
+struct __packed vesa_screen_info_input {
+ u8 signature[4];
+ u16 size_reserved;
+ u8 monitor_number;
+ u16 max_screen_width;
+ u8 color_depth;
+};
+
+/*
+ * These structs only store the required subset of fields in Vesa BIOS
+ * Extensions
+ */
+struct __packed vesa_bios_ext_info {
+ char signature[4];
+ u16 version;
+ u32 oem_string_ptr;
+ u32 capabilities;
+ u32 modes_ptr;
+ u16 total_memory;
+ u16 oem_version;
+ u32 vendor_name_ptr;
+ u32 product_name_ptr;
+ u32 product_rev_ptr;
+};
+
+struct __packed vesa_mode_info {
+ u16 mode_attributes; /* 00 */
+ u8 win_a_attributes; /* 02 */
+ u8 win_b_attributes; /* 03 */
+ u16 win_granularity; /* 04 */
+ u16 win_size; /* 06 */
+ u16 win_a_segment; /* 08 */
+ u16 win_b_segment; /* 0a */
+ u32 win_func_ptr; /* 0c */
+ u16 bytes_per_scanline; /* 10 */
+ u16 x_resolution; /* 12 */
+ u16 y_resolution; /* 14 */
+ u8 x_charsize; /* 16 */
+ u8 y_charsize; /* 17 */
+ u8 number_of_planes; /* 18 */
+ u8 bits_per_pixel; /* 19 */
+ u8 number_of_banks; /* 20 */
+ u8 memory_model; /* 21 */
+ u8 bank_size; /* 22 */
+ u8 number_of_image_pages; /* 23 */
+ u8 reserved_page;
+ u8 red_mask_size;
+ u8 red_mask_pos;
+ u8 green_mask_size;
+ u8 green_mask_pos;
+ u8 blue_mask_size;
+ u8 blue_mask_pos;
+ u8 reserved_mask_size;
+ u8 reserved_mask_pos;
+ u8 direct_color_mode_info;
+ u32 phys_base_ptr;
+ u32 offscreen_mem_offset;
+ u16 offscreen_mem_size;
+ u8 reserved[206];
+};
+
+struct vesa_state {
+ u16 video_mode;
+ bool valid;
+ union {
+ struct vesa_mode_info vesa;
+ u8 mode_info_block[256];
+ };
+};
+
+struct vesa_ddc_info {
+ u8 port_number; /* i.e. monitor number */
+ u8 edid_transfer_time;
+ u8 ddc_level;
+ u8 edid_block_zero[128];
+};
+
+#define VESA_GET_INFO 0x4f00
+#define VESA_GET_MODE_INFO 0x4f01
+#define VESA_SET_MODE 0x4f02
+#define VESA_GET_CUR_MODE 0x4f03
+
+extern struct vesa_state mode_info;
+
+struct video_priv;
+struct video_uc_plat;
+int vesa_setup_video_priv(struct vesa_mode_info *vesa,
+ struct video_priv *uc_priv,
+ struct video_uc_plat *plat);
+int vesa_setup_video(struct udevice *dev, int (*int15_handler)(void));
+
+#endif
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index e3f2402d0e8..5cfff8c56bc 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -37,6 +37,7 @@ if EFI_LOADER
config CMD_BOOTEFI_BOOTMGR
bool "UEFI Boot Manager"
default y
+ select BOOTMETH_GLOBAL if BOOTSTD
help
Select this option if you want to select the UEFI binary to be booted
via UEFI variables Boot####, BootOrder, and BootNext. This enables the
diff --git a/lib/elf.c b/lib/elf.c
index d074e4e0a7d..0476b2614c3 100644
--- a/lib/elf.c
+++ b/lib/elf.c
@@ -11,7 +11,7 @@
#include <net.h>
#include <vxworks.h>
#ifdef CONFIG_X86
-#include <vbe.h>
+#include <vesa.h>
#include <asm/e820.h>
#include <linux/linkage.h>
#endif
diff --git a/lib/of_live.c b/lib/of_live.c
index 2cb0dd9c073..30cae9ab881 100644
--- a/lib/of_live.c
+++ b/lib/of_live.c
@@ -248,19 +248,7 @@ static void *unflatten_dt_node(const void *blob, void *mem, int *poffset,
return mem;
}
-/**
- * unflatten_device_tree() - create tree of device_nodes from flat blob
- *
- * unflattens a device-tree, creating the
- * tree of struct device_node. It also fills the "name" and "type"
- * pointers of the nodes so the normal device-tree walking functions
- * can be used.
- * @blob: The blob to expand
- * @mynodes: The device_node tree created by the call
- * Return: 0 if OK, -ve on error
- */
-static int unflatten_device_tree(const void *blob,
- struct device_node **mynodes)
+int unflatten_device_tree(const void *blob, struct device_node **mynodes)
{
unsigned long size;
int start;
diff --git a/test/boot/Makefile b/test/boot/Makefile
index 1730792b5fa..9e9d5ae21f3 100644
--- a/test/boot/Makefile
+++ b/test/boot/Makefile
@@ -3,3 +3,7 @@
# Copyright 2021 Google LLC
obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o
+
+ifdef CONFIG_OF_LIVE
+obj-$(CONFIG_BOOTMETH_VBE_SIMPLE) += vbe_simple.o
+endif
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 1ebb789e97b..85305234e01 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -9,13 +9,33 @@
#include <common.h>
#include <bootdev.h>
#include <bootflow.h>
+#include <bootmeth.h>
#include <bootstd.h>
#include <dm.h>
+#ifdef CONFIG_SANDBOX
+#include <asm/test.h>
+#endif
#include <dm/lists.h>
#include <test/suites.h>
#include <test/ut.h>
#include "bootstd_common.h"
+static int inject_response(struct unit_test_state *uts)
+{
+ /*
+ * The image being booted presents a menu of options:
+ *
+ * Fedora-Workstation-armhfp-31-1.9 Boot Options.
+ * 1: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
+ * Enter choice:
+ *
+ * Provide input for this, to avoid waiting two seconds for a timeout.
+ */
+ ut_asserteq(2, console_in_puts("1\n"));
+
+ return 0;
+}
+
/* Check 'bootflow scan/list' commands */
static int bootflow_cmd(struct unit_test_state *uts)
{
@@ -73,7 +93,7 @@ static int bootflow_cmd_glob(struct unit_test_state *uts)
ut_assertok(bootstd_test_drop_bootdev_order(uts));
console_record_reset_enable();
- ut_assertok(run_command("bootflow scan -l", 0));
+ ut_assertok(run_command("bootflow scan -lG", 0));
ut_assert_nextline("Scanning for bootflows in all bootdevs");
ut_assert_nextline("Seq Method State Uclass Part Name Filename");
ut_assert_nextlinen("---");
@@ -105,7 +125,7 @@ static int bootflow_cmd_scan_e(struct unit_test_state *uts)
ut_assertok(bootstd_test_drop_bootdev_order(uts));
console_record_reset_enable();
- ut_assertok(run_command("bootflow scan -ale", 0));
+ ut_assertok(run_command("bootflow scan -aleG", 0));
ut_assert_nextline("Scanning for bootflows in all bootdevs");
ut_assert_nextline("Seq Method State Uclass Part Name Filename");
ut_assert_nextlinen("---");
@@ -188,6 +208,7 @@ BOOTSTD_TEST(bootflow_cmd_info, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
static int bootflow_scan_boot(struct unit_test_state *uts)
{
console_record_reset_enable();
+ ut_assertok(inject_response(uts));
ut_assertok(run_command("bootflow scan -b", 0));
ut_assert_nextline(
"** Booting bootflow 'mmc1.bootdev.part_1' with syslinux");
@@ -215,7 +236,7 @@ static int bootflow_iter(struct unit_test_state *uts)
/* The first device is mmc2.bootdev which has no media */
ut_asserteq(-EPROTONOSUPPORT,
- bootflow_scan_first(&iter, BOOTFLOWF_ALL, &bflow));
+ bootflow_scan_first(&iter, BOOTFLOWF_ALL | BOOTFLOWF_SKIP_GLOBAL, &bflow));
ut_asserteq(2, iter.num_methods);
ut_asserteq(0, iter.cur_method);
ut_asserteq(0, iter.part);
@@ -224,7 +245,7 @@ static int bootflow_iter(struct unit_test_state *uts)
ut_asserteq(0, bflow.err);
/*
- * This shows MEDIA even though there is none, since int
+ * This shows MEDIA even though there is none, since in
* bootdev_find_in_blk() we call part_get_info() which returns
* -EPROTONOSUPPORT. Ideally it would return -EEOPNOTSUPP and we would
* know.
@@ -302,34 +323,31 @@ static int bootflow_iter(struct unit_test_state *uts)
}
BOOTSTD_TEST(bootflow_iter, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+#if defined(CONFIG_SANDBOX) && defined(CONFIG_BOOTMETH_GLOBAL)
/* Check using the system bootdev */
static int bootflow_system(struct unit_test_state *uts)
{
- struct udevice *bootstd, *dev;
+ struct udevice *dev;
- /* Add the EFI bootmgr driver */
- ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
- ut_assertok(device_bind_driver(bootstd, "bootmeth_efi_mgr", "bootmgr",
- &dev));
-
- /* Add the system bootdev that it uses */
- ut_assertok(device_bind_driver(bootstd, "system_bootdev",
- "system-bootdev", &dev));
-
- ut_assertok(bootstd_test_drop_bootdev_order(uts));
+ ut_assertok(uclass_get_device_by_name(UCLASS_BOOTMETH, "efi_mgr",
+ &dev));
+ sandbox_set_fake_efi_mgr_dev(dev, true);
/* We should get a single 'bootmgr' method right at the end */
bootstd_clear_glob();
console_record_reset_enable();
ut_assertok(run_command("bootflow scan -l", 0));
- ut_assert_skip_to_line(" 1 bootmgr ready bootstd 0 <NULL> <NULL>");
- ut_assert_nextline("No more bootdevs");
- ut_assert_skip_to_line("(2 bootflows, 2 valid)");
+ ut_assert_skip_to_line(
+ " 0 efi_mgr ready (none) 0 <NULL> <NULL>");
+ ut_assert_skip_to_line("No more bootdevs");
+ ut_assert_skip_to_line("(5 bootflows, 5 valid)");
ut_assert_console_end();
return 0;
}
-BOOTSTD_TEST(bootflow_system, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+BOOTSTD_TEST(bootflow_system, UT_TESTF_DM | UT_TESTF_SCAN_PDATA |
+ UT_TESTF_SCAN_FDT);
+#endif
/* Check disabling a bootmethod if it requests it */
static int bootflow_iter_disable(struct unit_test_state *uts)
@@ -344,13 +362,11 @@ static int bootflow_iter_disable(struct unit_test_state *uts)
ut_assertok(device_bind_driver(bootstd, "bootmeth_sandbox", "sandbox",
&dev));
- /* Add the system bootdev that it uses */
- ut_assertok(device_bind_driver(bootstd, "system_bootdev",
- "system-bootdev", &dev));
-
ut_assertok(bootstd_test_drop_bootdev_order(uts));
bootstd_clear_glob();
+ console_record_reset_enable();
+ ut_assertok(inject_response(uts));
ut_assertok(run_command("bootflow scan -lb", 0));
/* Try to boot the bootmgr flow, which will fail */
@@ -358,6 +374,7 @@ static int bootflow_iter_disable(struct unit_test_state *uts)
ut_assertok(bootflow_scan_first(&iter, 0, &bflow));
ut_asserteq(3, iter.num_methods);
ut_asserteq_str("sandbox", iter.method->name);
+ ut_assertok(inject_response(uts));
ut_asserteq(-ENOTSUPP, bootflow_run_boot(&iter, &bflow));
ut_assert_skip_to_line("Boot method 'sandbox' failed and will not be retried");
@@ -372,6 +389,47 @@ static int bootflow_iter_disable(struct unit_test_state *uts)
}
BOOTSTD_TEST(bootflow_iter_disable, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+/* Check 'bootflow scan' with a bootmeth ordering including a global bootmeth */
+static int bootflow_scan_glob_bootmeth(struct unit_test_state *uts)
+{
+ if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL))
+ return 0;
+
+ ut_assertok(bootstd_test_drop_bootdev_order(uts));
+
+ /*
+ * Make sure that the -G flag makes the scan fail, since this is not
+ * supported when an ordering is provided
+ */
+ console_record_reset_enable();
+ ut_assertok(bootmeth_set_order("efi firmware0"));
+ ut_assertok(run_command("bootflow scan -lG", 0));
+ ut_assert_nextline("Scanning for bootflows in all bootdevs");
+ ut_assert_nextline(
+ "Seq Method State Uclass Part Name Filename");
+ ut_assert_nextlinen("---");
+ ut_assert_nextlinen("---");
+ ut_assert_nextline("(0 bootflows, 0 valid)");
+ ut_assert_console_end();
+
+ ut_assertok(run_command("bootflow scan -l", 0));
+ ut_assert_nextline("Scanning for bootflows in all bootdevs");
+ ut_assert_nextline(
+ "Seq Method State Uclass Part Name Filename");
+ ut_assert_nextlinen("---");
+ ut_assert_nextline("Scanning global bootmeth 'firmware0':");
+ ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':");
+ ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':");
+ ut_assert_nextline("Scanning bootdev 'mmc0.bootdev':");
+ ut_assert_nextline("No more bootdevs");
+ ut_assert_nextlinen("---");
+ ut_assert_nextline("(0 bootflows, 0 valid)");
+ ut_assert_console_end();
+
+ return 0;
+}
+BOOTSTD_TEST(bootflow_scan_glob_bootmeth, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+
/* Check 'bootflow boot' to boot a selected bootflow */
static int bootflow_cmd_boot(struct unit_test_state *uts)
{
@@ -382,6 +440,8 @@ static int bootflow_cmd_boot(struct unit_test_state *uts)
ut_assert_console_end();
ut_assertok(run_command("bootflow select 0", 0));
ut_assert_console_end();
+
+ ut_assertok(inject_response(uts));
ut_asserteq(1, run_command("bootflow boot", 0));
ut_assert_nextline(
"** Booting bootflow 'mmc1.bootdev.part_1' with syslinux");
diff --git a/test/boot/bootmeth.c b/test/boot/bootmeth.c
index 07776c5368d..fb627313396 100644
--- a/test/boot/bootmeth.c
+++ b/test/boot/bootmeth.c
@@ -1,13 +1,15 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Test for bootdev functions. All start with 'bootdev'
+ * Test for bootdev functions. All start with 'bootmeth'
*
* Copyright 2021 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
+#include <bootmeth.h>
#include <bootstd.h>
+#include <dm.h>
#include <test/suites.h>
#include <test/ut.h>
#include "bootstd_common.h"
@@ -21,8 +23,11 @@ static int bootmeth_cmd_list(struct unit_test_state *uts)
ut_assert_nextlinen("---");
ut_assert_nextline(" 0 0 syslinux Syslinux boot from a block device");
ut_assert_nextline(" 1 1 efi EFI boot from an .efi file");
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL))
+ ut_assert_nextline(" glob 2 firmware0 VBE simple");
ut_assert_nextlinen("---");
- ut_assert_nextline("(2 bootmeths)");
+ ut_assert_nextline(IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) ?
+ "(3 bootmeths)" : "(2 bootmeths)");
ut_assert_console_end();
return 0;
@@ -54,8 +59,11 @@ static int bootmeth_cmd_order(struct unit_test_state *uts)
ut_assert_nextlinen("---");
ut_assert_nextline(" 0 0 syslinux Syslinux boot from a block device");
ut_assert_nextline(" - 1 efi EFI boot from an .efi file");
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL))
+ ut_assert_nextline(" glob 2 firmware0 VBE simple");
ut_assert_nextlinen("---");
- ut_assert_nextline("(2 bootmeths)");
+ ut_assert_nextline(IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) ?
+ "(3 bootmeths)" : "(2 bootmeths)");
ut_assert_console_end();
/* Check the -a flag with the reverse order */
@@ -66,8 +74,11 @@ static int bootmeth_cmd_order(struct unit_test_state *uts)
ut_assert_nextlinen("---");
ut_assert_nextline(" 1 0 syslinux Syslinux boot from a block device");
ut_assert_nextline(" 0 1 efi EFI boot from an .efi file");
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL))
+ ut_assert_nextline(" glob 2 firmware0 VBE simple");
ut_assert_nextlinen("---");
- ut_assert_nextline("(2 bootmeths)");
+ ut_assert_nextline(IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) ?
+ "(3 bootmeths)" : "(2 bootmeths)");
ut_assert_console_end();
/* Now reset the order to empty, which should show all of them again */
@@ -75,7 +86,8 @@ static int bootmeth_cmd_order(struct unit_test_state *uts)
ut_assert_console_end();
ut_assertnull(env_get("bootmeths"));
ut_assertok(run_command("bootmeth list", 0));
- ut_assert_skip_to_line("(2 bootmeths)");
+ ut_assert_skip_to_line(IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) ?
+ "(3 bootmeths)" : "(2 bootmeths)");
/* Try reverse order */
ut_assertok(run_command("bootmeth order \"efi syslinux\"", 0));
@@ -91,6 +103,23 @@ static int bootmeth_cmd_order(struct unit_test_state *uts)
ut_asserteq_str("efi syslinux", env_get("bootmeths"));
ut_assert_console_end();
+ /* Try with global bootmeths */
+ if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL))
+ return 0;
+
+ ut_assertok(run_command("bootmeth order \"efi firmware0\"", 0));
+ ut_assert_console_end();
+ ut_assertok(run_command("bootmeth list", 0));
+ ut_assert_nextline("Order Seq Name Description");
+ ut_assert_nextlinen("---");
+ ut_assert_nextline(" 0 1 efi EFI boot from an .efi file");
+ ut_assert_nextline(" glob 2 firmware0 VBE simple");
+ ut_assert_nextlinen("---");
+ ut_assert_nextline("(2 bootmeths)");
+ ut_assertnonnull(env_get("bootmeths"));
+ ut_asserteq_str("efi firmware0", env_get("bootmeths"));
+ ut_assert_console_end();
+
return 0;
}
BOOTSTD_TEST(bootmeth_cmd_order, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
@@ -120,3 +149,19 @@ static int bootmeth_env(struct unit_test_state *uts)
return 0;
}
BOOTSTD_TEST(bootmeth_env, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+
+/* Check the get_state_desc() method */
+static int bootmeth_state(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ char buf[50];
+
+ ut_assertok(uclass_first_device(UCLASS_BOOTMETH, &dev));
+ ut_assertnonnull(dev);
+
+ ut_assertok(bootmeth_get_state_desc(dev, buf, sizeof(buf)));
+ ut_asserteq_str("OK", buf);
+
+ return 0;
+}
+BOOTSTD_TEST(bootmeth_state, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
diff --git a/test/boot/vbe_simple.c b/test/boot/vbe_simple.c
new file mode 100644
index 00000000000..2f6979cafcf
--- /dev/null
+++ b/test/boot/vbe_simple.c
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Test for vbe-simple bootmeth. All start with 'vbe_simple'
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <bootmeth.h>
+#include <dm.h>
+#include <image.h>
+#include <memalign.h>
+#include <mmc.h>
+#include <of_live.h>
+#include <vbe.h>
+#include <version_string.h>
+#include <linux/log2.h>
+#include <test/suites.h>
+#include <test/ut.h>
+#include <u-boot/crc.h>
+#include "bootstd_common.h"
+
+#define NVDATA_START_BLK ((0x400 + 0x400) / MMC_MAX_BLOCK_LEN)
+#define VERSION_START_BLK ((0x400 + 0x800) / MMC_MAX_BLOCK_LEN)
+#define TEST_VERSION "U-Boot v2022.04-local2"
+#define TEST_VERNUM 0x00010002
+
+/* Basic test of reading nvdata and updating a fwupd node in the device tree */
+static int vbe_simple_test_base(struct unit_test_state *uts)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
+ const char *version, *bl_version;
+ struct event_ft_fixup fixup;
+ struct udevice *dev, *mmc;
+ struct device_node *np;
+ struct blk_desc *desc;
+ char fdt_buf[0x400];
+ char info[100];
+ int node_ofs;
+ ofnode node;
+ u32 vernum;
+
+ /* Set up the version string */
+ ut_assertok(uclass_get_device(UCLASS_MMC, 1, &mmc));
+ desc = blk_get_by_device(mmc);
+ ut_assertnonnull(desc);
+
+ memset(buf, '\0', MMC_MAX_BLOCK_LEN);
+ strcpy(buf, TEST_VERSION);
+ if (blk_dwrite(desc, VERSION_START_BLK, 1, buf) != 1)
+ return log_msg_ret("write", -EIO);
+
+ /* Set up the nvdata */
+ memset(buf, '\0', MMC_MAX_BLOCK_LEN);
+ buf[1] = ilog2(0x40) << 4 | 1;
+ *(u32 *)(buf + 4) = TEST_VERNUM;
+ buf[0] = crc8(0, buf + 1, 0x3f);
+ if (blk_dwrite(desc, NVDATA_START_BLK, 1, buf) != 1)
+ return log_msg_ret("write", -EIO);
+
+ /* Read the version back */
+ ut_assertok(vbe_find_by_any("firmware0", &dev));
+ ut_assertok(bootmeth_get_state_desc(dev, info, sizeof(info)));
+ ut_asserteq_str("Version: " TEST_VERSION "\nVernum: 1/2", info);
+
+ ut_assertok(fdt_create_empty_tree(fdt_buf, sizeof(fdt_buf)));
+ node_ofs = fdt_add_subnode(fdt_buf, 0, "chosen");
+ ut_assert(node_ofs > 0);
+
+ node_ofs = fdt_add_subnode(fdt_buf, node_ofs, "fwupd");
+ ut_assert(node_ofs > 0);
+
+ node_ofs = fdt_add_subnode(fdt_buf, node_ofs, "firmware0");
+ ut_assert(node_ofs > 0);
+
+ /*
+ * This can only work on the live tree, since the ofnode interface for
+ * flat tree assumes that ofnode points to the control FDT
+ */
+ ut_assertok(unflatten_device_tree(fdt_buf, &np));
+
+ /*
+ * It would be better to call image_setup_libfdt() here, but that
+ * function does not allow passing an ofnode. We can pass fdt_buf but
+ * when it comes to send the evenr, it creates an ofnode that uses the
+ * control FDT, since it has no way of accessing the live tree created
+ * here.
+ *
+ * Two fix this we need:
+ * - image_setup_libfdt() is updated to use ofnode
+ * - ofnode updated to support access to an FDT other than the control
+ * FDT. This is partially implemented with live tree, but not with
+ * flat tree
+ */
+ fixup.tree.np = np;
+ ut_assertok(event_notify(EVT_FT_FIXUP, &fixup, sizeof(fixup)));
+
+ node = ofnode_path_root(fixup.tree, "/chosen/fwupd/firmware0");
+
+ version = ofnode_read_string(node, "cur-version");
+ ut_assertnonnull(version);
+ ut_asserteq_str(TEST_VERSION, version);
+
+ ut_assertok(ofnode_read_u32(node, "cur-vernum", &vernum));
+ ut_asserteq(TEST_VERNUM, vernum);
+
+ bl_version = ofnode_read_string(node, "bootloader-version");
+ ut_assertnonnull(bl_version);
+ ut_asserteq_str(version_string, bl_version);
+
+ return 0;
+}
+BOOTSTD_TEST(vbe_simple_test_base, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
+ UT_TESTF_LIVE_TREE);
diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c
index 61ae1db62d7..f80993f8927 100644
--- a/test/dm/ofnode.c
+++ b/test/dm/ofnode.c
@@ -3,8 +3,13 @@
#include <common.h>
#include <dm.h>
#include <log.h>
+#include <of_live.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
#include <dm/of_extra.h>
+#include <dm/root.h>
#include <dm/test.h>
+#include <dm/uclass-internal.h>
#include <test/test.h>
#include <test/ut.h>
@@ -469,3 +474,130 @@ static int dm_test_ofnode_get_phy(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_ofnode_get_phy, 0);
+
+/**
+ * make_ofnode_fdt() - Create an FDT for testing with ofnode
+ *
+ * The size is set to the minimum needed
+ *
+ * @uts: Test state
+ * @fdt: Place to write FDT
+ * @size: Maximum size of space for fdt
+ */
+static int make_ofnode_fdt(struct unit_test_state *uts, void *fdt, int size)
+{
+ ut_assertok(fdt_create(fdt, size));
+ ut_assertok(fdt_finish_reservemap(fdt));
+ ut_assert(fdt_begin_node(fdt, "") >= 0);
+
+ ut_assert(fdt_begin_node(fdt, "aliases") >= 0);
+ ut_assertok(fdt_property_string(fdt, "mmc0", "/new-mmc"));
+ ut_assertok(fdt_end_node(fdt));
+
+ ut_assert(fdt_begin_node(fdt, "new-mmc") >= 0);
+ ut_assertok(fdt_end_node(fdt));
+
+ ut_assertok(fdt_end_node(fdt));
+ ut_assertok(fdt_finish(fdt));
+
+ return 0;
+}
+
+static int dm_test_ofnode_root(struct unit_test_state *uts)
+{
+ struct device_node *root = NULL;
+ char fdt[256];
+ oftree tree;
+ ofnode node;
+
+ /* Check that aliases work on the control FDT */
+ node = ofnode_get_aliases_node("ethernet3");
+ ut_assert(ofnode_valid(node));
+ ut_asserteq_str("sbe5", ofnode_get_name(node));
+
+ ut_assertok(make_ofnode_fdt(uts, fdt, sizeof(fdt)));
+ if (of_live_active()) {
+ ut_assertok(unflatten_device_tree(fdt, &root));
+ tree.np = root;
+ } else {
+ tree.fdt = fdt;
+ }
+
+ /* Make sure they don't work on this new tree */
+ node = ofnode_path_root(tree, "mmc0");
+ ut_assert(!ofnode_valid(node));
+
+ /* It should appear in the new tree */
+ node = ofnode_path_root(tree, "/new-mmc");
+ ut_assert(ofnode_valid(node));
+
+ /* ...and not in the control FDT */
+ node = ofnode_path_root(oftree_default(), "/new-mmc");
+ ut_assert(!ofnode_valid(node));
+
+ free(root);
+
+ return 0;
+}
+DM_TEST(dm_test_ofnode_root, UT_TESTF_SCAN_FDT);
+
+static int dm_test_ofnode_livetree_writing(struct unit_test_state *uts)
+{
+ struct udevice *dev;
+ ofnode node;
+
+ /* Test enabling devices */
+ node = ofnode_path("/usb@2");
+
+ ut_assert(!ofnode_is_enabled(node));
+ ut_assertok(ofnode_set_enabled(node, true));
+ ut_asserteq(true, ofnode_is_enabled(node));
+
+ device_bind_driver_to_node(dm_root(), "usb_sandbox", "usb@2", node,
+ &dev);
+ ut_assertok(uclass_find_device_by_seq(UCLASS_USB, 2, &dev));
+
+ /* Test string property setting */
+ ut_assert(device_is_compatible(dev, "sandbox,usb"));
+ ofnode_write_string(node, "compatible", "gdsys,super-usb");
+ ut_assert(device_is_compatible(dev, "gdsys,super-usb"));
+ ofnode_write_string(node, "compatible", "sandbox,usb");
+ ut_assert(device_is_compatible(dev, "sandbox,usb"));
+
+ /* Test setting generic properties */
+
+ /* Non-existent in DTB */
+ ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr(dev));
+ /* reg = 0x42, size = 0x100 */
+ ut_assertok(ofnode_write_prop(node, "reg",
+ "\x00\x00\x00\x42\x00\x00\x01\x00", 8));
+ ut_asserteq(0x42, dev_read_addr(dev));
+
+ /* Test disabling devices */
+ device_remove(dev, DM_REMOVE_NORMAL);
+ device_unbind(dev);
+
+ ut_assert(ofnode_is_enabled(node));
+ ut_assertok(ofnode_set_enabled(node, false));
+ ut_assert(!ofnode_is_enabled(node));
+
+ return 0;
+}
+DM_TEST(dm_test_ofnode_livetree_writing,
+ UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT | UT_TESTF_LIVE_OR_FLAT);
+
+static int dm_test_ofnode_u32(struct unit_test_state *uts)
+{
+ ofnode node;
+
+ node = ofnode_path("/lcd");
+ ut_assert(ofnode_valid(node));
+ ut_asserteq(1366, ofnode_read_u32_default(node, "xres", 123));
+ ut_assertok(ofnode_write_u32(node, "xres", 1367));
+ ut_asserteq(1367, ofnode_read_u32_default(node, "xres", 123));
+ ut_assertok(ofnode_write_u32(node, "xres", 1366));
+
+ return 0;
+}
+DM_TEST(dm_test_ofnode_u32,
+ UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT | UT_TESTF_LIVE_OR_FLAT);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index f9e81747595..6118ad42ca8 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -17,7 +17,6 @@
#include <dm/devres.h>
#include <dm/uclass-internal.h>
#include <dm/util.h>
-#include <dm/lists.h>
#include <dm/of_access.h>
#include <linux/ioport.h>
#include <test/test.h>
@@ -735,58 +734,6 @@ static int dm_test_fdt_remap_addr_name_live(struct unit_test_state *uts)
DM_TEST(dm_test_fdt_remap_addr_name_live,
UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
-static int dm_test_fdt_livetree_writing(struct unit_test_state *uts)
-{
- struct udevice *dev;
- ofnode node;
-
- if (!of_live_active()) {
- printf("Live tree not active; ignore test\n");
- return 0;
- }
-
- /* Test enabling devices */
-
- node = ofnode_path("/usb@2");
-
- ut_assert(!of_device_is_available(ofnode_to_np(node)));
- ofnode_set_enabled(node, true);
- ut_assert(of_device_is_available(ofnode_to_np(node)));
-
- device_bind_driver_to_node(dm_root(), "usb_sandbox", "usb@2", node,
- &dev);
- ut_assertok(uclass_find_device_by_seq(UCLASS_USB, 2, &dev));
-
- /* Test string property setting */
-
- ut_assert(device_is_compatible(dev, "sandbox,usb"));
- ofnode_write_string(node, "compatible", "gdsys,super-usb");
- ut_assert(device_is_compatible(dev, "gdsys,super-usb"));
- ofnode_write_string(node, "compatible", "sandbox,usb");
- ut_assert(device_is_compatible(dev, "sandbox,usb"));
-
- /* Test setting generic properties */
-
- /* Non-existent in DTB */
- ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr(dev));
- /* reg = 0x42, size = 0x100 */
- ut_assertok(ofnode_write_prop(node, "reg", 8,
- "\x00\x00\x00\x42\x00\x00\x01\x00"));
- ut_asserteq(0x42, dev_read_addr(dev));
-
- /* Test disabling devices */
-
- device_remove(dev, DM_REMOVE_NORMAL);
- device_unbind(dev);
-
- ut_assert(of_device_is_available(ofnode_to_np(node)));
- ofnode_set_enabled(node, false);
- ut_assert(!of_device_is_available(ofnode_to_np(node)));
-
- return 0;
-}
-DM_TEST(dm_test_fdt_livetree_writing, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
-
static int dm_test_fdt_disable_enable_by_path(struct unit_test_state *uts)
{
ofnode node;
diff --git a/test/py/tests/test_event_dump.py b/test/py/tests/test_event_dump.py
index b753e804ac3..bc54149e8f2 100644
--- a/test/py/tests/test_event_dump.py
+++ b/test/py/tests/test_event_dump.py
@@ -16,5 +16,6 @@ def test_event_dump(u_boot_console):
out = util.run_and_log(cons, ['scripts/event_dump.py', sandbox])
expect = '''.*Event type Id Source location
-------------------- ------------------------------ ------------------------------
+EVT_FT_FIXUP bootmeth_vbe_simple_ft_fixup .*boot/vbe_simple.c:.*
EVT_MISC_INIT_F sandbox_misc_init_f .*arch/sandbox/cpu/start.c:'''
assert re.match(expect, out, re.MULTILINE) is not None
diff --git a/test/test-main.c b/test/test-main.c
index ee38d1faea8..31837e57a8f 100644
--- a/test/test-main.c
+++ b/test/test-main.c
@@ -228,8 +228,10 @@ static int test_pre_run(struct unit_test_state *uts, struct unit_test *test)
uts->start = mallinfo();
- if (test->flags & UT_TESTF_SCAN_PDATA)
+ if (test->flags & UT_TESTF_SCAN_PDATA) {
ut_assertok(dm_scan_plat(false));
+ ut_assertok(dm_scan_other(false));
+ }
if (test->flags & UT_TESTF_PROBE_TEST)
ut_assertok(do_autoprobe(uts));
@@ -338,7 +340,8 @@ static int ut_run_test_live_flat(struct unit_test_state *uts,
/* Run with the live tree if possible */
runs = 0;
if (CONFIG_IS_ENABLED(OF_LIVE)) {
- if (!(test->flags & UT_TESTF_FLAT_TREE)) {
+ if (!(test->flags &
+ (UT_TESTF_FLAT_TREE | UT_TESTF_LIVE_OR_FLAT))) {
uts->of_live = true;
ut_assertok(ut_run_test(uts, test, test->name));
runs++;