This commit introduces a new standard boot method that supports booting via semihosting as provided by ARM FVP platforms.
Semihosting enables the virtual platform to access host-side files as if they were block devices, which is particularly useful in early boot development and simulation environments. It removes the need for physical storage or networking when loading kernel components. This method mirrors the distroboot logic for semihosting, which is the default boot method for vexpress64 platform. The load_file_from_host helper function is implemented to mirror behaviour of "load hostfs" u-boot command, so it similarly sets filesize environment variable after loading a file - this is useful for later commands. This implementation is marked with BOOTMETH_GLOBAL so it is always considered during bootflow scan without requiring a boot device. Signed-off-by: Said Nasibov <said.nasi...@arm.com> --- boot/Kconfig | 10 ++++ boot/Makefile | 1 + boot/bootmeth_smh.c | 113 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 boot/bootmeth_smh.c diff --git a/boot/Kconfig b/boot/Kconfig index 2ff6f003738..fbd3f068908 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -936,6 +936,16 @@ config BOOTMETH_SCRIPT This provides a way to try out standard boot on an existing boot flow. It is not enabled by default to save space. +config BOOTMETH_SMH + bool "Bootdev support for semihosting" + depends on SEMIHOSTING + select CMD_FDT + select BOOTMETH_GLOBAL + help + Enables support for booting via semihosting. This bootmeth reads + files including the kernel, device tree and ramdisk directly from + the host's filesystem. + config UPL bool "upl - Universal Payload Specification" imply CMD_UPL diff --git a/boot/Makefile b/boot/Makefile index 3da6f7a0914..5bed9e66507 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_$(PHASE_)BOOTMETH_SANDBOX) += bootmeth_sandbox.o obj-$(CONFIG_$(PHASE_)BOOTMETH_SCRIPT) += bootmeth_script.o obj-$(CONFIG_$(PHASE_)CEDIT) += cedit.o obj-$(CONFIG_$(PHASE_)BOOTMETH_EFI_BOOTMGR) += bootmeth_efi_mgr.o +obj-$(CONFIG_$(PHASE_)BOOTMETH_SMH) += bootmeth_smh.o obj-$(CONFIG_$(PHASE_)OF_LIBFDT) += fdt_support.o obj-$(CONFIG_$(PHASE_)FDT_SIMPLEFB) += fdt_simplefb.o diff --git a/boot/bootmeth_smh.c b/boot/bootmeth_smh.c new file mode 100644 index 00000000000..2ceb66900ed --- /dev/null +++ b/boot/bootmeth_smh.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Bootmethod for booting using semihosting + * + * Copyright 2025 Arm Ltd. + * Written by Said Nasibov <said.nasi...@arm.com> + */ + +#define LOG_CATEGORY UCLASS_BOOTSTD + +#include <bootmeth.h> +#include <dm.h> +#include <env.h> +#include <fs.h> + +static int script_check(struct udevice *dev, struct bootflow_iter *iter) +{ + return 0; +} + +static int load_file_from_host(const char *name_var, const char *addr_var) +{ + const char *filename = env_get(name_var); + const char *addr_str = env_get(addr_var); + ulong addr; + loff_t len; + int ret; + + /* Mount hostfs (semihosting) */ + ret = fs_set_blk_dev("hostfs", NULL, FS_TYPE_ANY); + if (ret) + return log_msg_ret("hostfs", ret); + + if (!filename || !addr_str) + return log_msg_ret("env missing", -EINVAL); + + addr = hextoul(addr_str, NULL); + if (!addr) + return log_msg_ret("invalid addr", -EINVAL); + + /* Read file into memory */ + ret = fs_read(filename, addr, 0, 0, &len); + if (ret) + return log_msg_ret("fs_read", ret); + + /* Set filesize environment variable in hex */ + char size_str[32]; + sprintf(size_str, "%lx", (unsigned long)len); + env_set("filesize", size_str); + + return 0; +} + +static int smh_read_bootflow(struct udevice *dev, struct bootflow *bflow) +{ + int ret; + + ret = load_file_from_host("kernel_name", "kernel_addr_r"); + if (ret) + return log_msg_ret("kernel", ret); + + env_set("fdt_high", "0xffffffffffffffff"); + env_set("initrd_high", "0xffffffffffffffff"); + + ret = load_file_from_host("fdtfile", "fdt_addr_r"); + if (ret) { + ret = run_command("fdt move $fdtcontroladdr $fdt_addr_r;", 0); + if (ret) + return log_msg_ret("fdt move", ret); + } + + load_file_from_host("ramdisk_name", "ramdisk_addr_r"); + + bflow->state = BOOTFLOWST_READY; + + return 0; +} + +static int smh_boot(struct udevice *dev, struct bootflow *bflow) +{ + int ret = run_command("booti $kernel_addr_r ${ramdisk_addr_r}:${filesize} ${fdt_addr_r};", 0); + + return ret; +} + +static int smh_bootmeth_bind(struct udevice *dev) +{ + struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); + + plat->desc = "semihosting"; + plat->flags = BOOTMETHF_GLOBAL; + + return 0; +} + +static struct bootmeth_ops smh_bootmeth_ops = { + .check = script_check, + .read_bootflow = smh_read_bootflow, + .boot = smh_boot, +}; + +static const struct udevice_id smh_bootmeth_ids[] = { + { .compatible = "u-boot,smh" }, + {} +}; + +U_BOOT_DRIVER(bootmeth_0smh) = { + .name = "bootmeth_smh", + .id = UCLASS_BOOTMETH, + .of_match = smh_bootmeth_ids, + .ops = &smh_bootmeth_ops, + .bind = &smh_bootmeth_bind, +}; -- 2.34.1 IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.