summaryrefslogtreecommitdiff
path: root/boot/bootmeth_script.c
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2023-01-24 14:04:14 -0500
committerTom Rini <trini@konsulko.com>2023-01-24 14:04:14 -0500
commit4e1ab2065e21e48a3087144ab826f12cfb797a65 (patch)
tree1dc9e793258c5a4a1be4d5e6d554f7f1a82450f3 /boot/bootmeth_script.c
parentdd31cd58b02729807934cb699b164b1f8736620f (diff)
parent3891c68ef50eda38d78c95ecd03aed030aa6bb53 (diff)
Merge branch '2023-01-24-bootstd-allow-migration-from-distro_bootcmd-script'
To quote the author: So far, standard boot does not replicate all the of the functionality of the distro_bootcmd scripts. In particular it lacks some bootdevs and some of the bootmeths are incomplete. Also there is currently no internal mechanism to enumerate buses in order to discover bootdevs, e.g. with USB. This series addresses these shortcomings: - Adds the concept of a 'bootdev hunter' to enumerate buses, etc. in an effort to find bootdevs of a certain priority - Adds bootdevs for SCSI, IDE, NVMe, virtio, SPI flash - Handles PXE and DHCP properly - Supports reading the device tree with EFI and reading scripts from the network It also tidies up label processing, so it is possible to use: bootflow scan mmc2 to scan just one MMC device (with BOOTSTD_FULL). As before this implementation still relies on CONFIG_CMDLINE being enabled, mostly for the network stack. Further work would be required to disentangle that. Quite a few tests are added but there are some gaps: - SPI flash bootdev - EFI FDT loading Note that SATA works via SCSI (CONFIG_SCSI_AHCI) and does not use driver model. Only pogo_v4 seems to be affected. Probably all thats is needed is to call bootdev_setup_sibling_blk() in the Marvell SATA driver. Also, while it would be possible to init MMC in a bootdev hunter, there is no point since U-Boot always inits MMC on startup, if present. With this series it should be possible to migrate boards to standard boot by removing the inclusion of config_distro_bootcmd.h and instead adding a suitable value for boot_targets to the environment, e.g.: boot_targets=mmc1 mmc0 nvme scsi usb pxe dhcp spi Thus it is possible to boot automatically without scripts and boards can use a text-based environment instead of the config.h files. To demonstrate this, rockpro64-rk3399 is migrated to standard boot in this series. Full migration could probably be automated using a script, similar in concept to moveconfig: - obtain the board environment via 'make u-boot-initial-env' - get the value of "boot_targets" - drop config_distro_bootcmd.h from the config.h file - rebuild again to get the environment without distro scripts - write the environment (adding boot_targets) to board.env - remove CONFIG_EXTRA_ENV_SETTINGS from the config.h file
Diffstat (limited to 'boot/bootmeth_script.c')
-rw-r--r--boot/bootmeth_script.c98
1 files changed, 85 insertions, 13 deletions
diff --git a/boot/bootmeth_script.c b/boot/bootmeth_script.c
index c7061eb998f..225eb18ee6c 100644
--- a/boot/bootmeth_script.c
+++ b/boot/bootmeth_script.c
@@ -19,18 +19,16 @@
#include <image.h>
#include <malloc.h>
#include <mapmem.h>
+#include <net.h>
#define SCRIPT_FNAME1 "boot.scr.uimg"
#define SCRIPT_FNAME2 "boot.scr"
static int script_check(struct udevice *dev, struct bootflow_iter *iter)
{
- int ret;
-
- /* This only works on block devices */
- ret = bootflow_iter_uses_blk_dev(iter);
- if (ret)
- return log_msg_ret("blk", ret);
+ /* This works on block devices, network devices and SPI Flash */
+ if (iter->method_flags & BOOTFLOW_METHF_PXE_ONLY)
+ return log_msg_ret("pxe", -ENOTSUPP);
return 0;
}
@@ -65,11 +63,11 @@ static int script_fill_info(struct bootflow *bflow)
return 0;
}
-static int script_read_bootflow(struct udevice *dev, struct bootflow *bflow)
+static int script_read_bootflow_file(struct udevice *bootstd,
+ struct bootflow *bflow)
{
struct blk_desc *desc = NULL;
const char *const *prefixes;
- struct udevice *bootstd;
const char *prefix;
int ret, i;
@@ -77,12 +75,12 @@ static int script_read_bootflow(struct udevice *dev, struct bootflow *bflow)
if (ret)
return log_msg_ret("std", ret);
- /* We require a partition table */
- if (!bflow->part)
- return -ENOENT;
-
- if (bflow->blk)
+ if (bflow->blk) {
+ /* We require a partition table */
+ if (!bflow->part)
+ return -ENOENT;
desc = dev_get_uclass_plat(bflow->blk);
+ }
prefixes = bootstd_get_prefixes(bootstd);
i = 0;
@@ -116,6 +114,76 @@ static int script_read_bootflow(struct udevice *dev, struct bootflow *bflow)
return 0;
}
+static int script_read_bootflow_net(struct bootflow *bflow)
+{
+ const char *addr_str;
+ int size, ret;
+ char *fname;
+ ulong addr;
+
+ /* figure out the load address */
+ addr_str = env_get("scriptaddr");
+ addr = addr_str ? hextoul(addr_str, NULL) : image_load_addr;
+
+ fname = env_get("boot_script_dhcp");
+ if (!fname)
+ return log_msg_ret("dhc", -EINVAL);
+
+ ret = dhcp_run(addr, fname, true);
+ if (ret)
+ return log_msg_ret("dhc", ret);
+
+ size = env_get_hex("filesize", 0);
+ if (!size)
+ return log_msg_ret("sz", -EINVAL);
+
+ bflow->buf = malloc(size + 1);
+ if (!bflow->buf)
+ return log_msg_ret("buf", -ENOMEM);
+ memcpy(bflow->buf, map_sysmem(addr, size), size);
+ bflow->buf[size] = '\0';
+ bflow->size = size;
+ bflow->state = BOOTFLOWST_READY;
+
+ return 0;
+}
+
+static int script_read_bootflow(struct udevice *dev, struct bootflow *bflow)
+{
+ const struct udevice *media = dev_get_parent(bflow->dev);
+ struct udevice *bootstd;
+ int ret;
+
+ ret = uclass_first_device_err(UCLASS_BOOTSTD, &bootstd);
+ if (ret)
+ return log_msg_ret("std", ret);
+
+ if (IS_ENABLED(CONFIG_CMD_DHCP) &&
+ device_get_uclass_id(media) == UCLASS_ETH) {
+ /* we only support reading from one device, so ignore 'dev' */
+ ret = script_read_bootflow_net(bflow);
+ if (ret)
+ return log_msg_ret("net", ret);
+ } else {
+ ret = script_read_bootflow_file(bootstd, bflow);
+ if (ret)
+ return log_msg_ret("blk", ret);
+ }
+
+ return 0;
+}
+
+static int script_set_bootflow(struct udevice *dev, struct bootflow *bflow,
+ char *buf, int size)
+{
+ buf[size] = '\0';
+ bflow->buf = buf;
+ bflow->size = size;
+ bflow->state = BOOTFLOWST_READY;
+
+ return 0;
+}
+
static int script_boot(struct udevice *dev, struct bootflow *bflow)
{
struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
@@ -126,6 +194,8 @@ static int script_boot(struct udevice *dev, struct bootflow *bflow)
if (!ret)
ret = env_set_hex("devnum", desc->devnum);
if (!ret)
+ ret = env_set_hex("distro_bootpart", bflow->part);
+ if (!ret)
ret = env_set("prefix", bflow->subdir);
if (!ret && IS_ENABLED(CONFIG_ARCH_SUNXI) &&
!strcmp("mmc", blk_get_devtype(bflow->blk)))
@@ -135,6 +205,7 @@ static int script_boot(struct udevice *dev, struct bootflow *bflow)
log_debug("devtype: %s\n", env_get("devtype"));
log_debug("devnum: %s\n", env_get("devnum"));
+ log_debug("distro_bootpart: %s\n", env_get("distro_bootpart"));
log_debug("prefix: %s\n", env_get("prefix"));
log_debug("mmc_bootdev: %s\n", env_get("mmc_bootdev"));
@@ -159,6 +230,7 @@ static int script_bootmeth_bind(struct udevice *dev)
static struct bootmeth_ops script_bootmeth_ops = {
.check = script_check,
.read_bootflow = script_read_bootflow,
+ .set_bootflow = script_set_bootflow,
.read_file = bootmeth_common_read_file,
.boot = script_boot,
};