[PATCH v5] cmd: move ELF load and boot to lib/elf.c
Heinrich Schuchardt
xypron.glpk at gmx.de
Thu Jun 6 09:02:43 CEST 2024
On 6/5/24 20:43, Maxim Moskalets wrote:
> From: Maxim Moskalets <maximmosk4 at gmail.com>
>
> Loading and running the ELF image is the responsibility of the
> library and should not be associated with the command line interface.
>
> It is also required to run ELF images from FIT with the bootm command
> so as not to depend on the command line interface.
>
> Signed-off-by: Maxim Moskalets <maximmosk4 at gmail.com>
In future versions please, include a change log separated from the
commit message by ---, e.g.
---
v6:
foo changed to bar
v5:
xxx removed
---
Best regards
Heinrich
> ---
> cmd/elf.c | 58 +++++++++++++++++++--------------------------------
> include/elf.h | 10 +++++++++
> lib/elf.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 86 insertions(+), 36 deletions(-)
>
> diff --git a/cmd/elf.c b/cmd/elf.c
> index a02361f9f5..32b7462f92 100644
> --- a/cmd/elf.c
> +++ b/cmd/elf.c
> @@ -19,21 +19,6 @@
> #include <linux/linkage.h>
> #endif
>
> -/* Allow ports to override the default behavior */
> -static unsigned long do_bootelf_exec(ulong (*entry)(int, char * const[]),
> - int argc, char *const argv[])
> -{
> - unsigned long ret;
> -
> - /*
> - * pass address parameter as argv[0] (aka command name),
> - * and all remaining args
> - */
> - ret = entry(argc, argv);
> -
> - return ret;
> -}
> -
> /* Interpreter command to boot an arbitrary ELF image from memory */
> int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> {
> @@ -43,8 +28,8 @@ int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> #endif
> unsigned long addr; /* Address of the ELF image */
> unsigned long rc; /* Return value from user code */
> - char *sload = NULL;
> - int rcode = 0;
> + int rcode = CMD_RET_SUCCESS;
> + Bootelf_flags flags = {0};
>
> /* Consume 'bootelf' */
> argc--; argv++;
> @@ -52,7 +37,10 @@ int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> /* Check for [-p|-s] flag. */
> if (argc >= 1 && (argv[0][0] == '-' && \
> (argv[0][1] == 'p' || argv[0][1] == 's'))) {
> - sload = argv[0];
> + if (argv[0][1] == 'p')
> + flags.phdr = 1;
> + log_debug("Using ELF header format %s\n",
> + flags.phdr ? "phdr" : "shdr");
> /* Consume flag. */
> argc--; argv++;
> }
> @@ -75,17 +63,9 @@ int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> } else
> addr = image_load_addr;
>
> - if (!valid_elf_image(addr))
> - return 1;
> -
> - if (sload && sload[1] == 'p')
> - addr = load_elf_image_phdr(addr);
> - else
> - addr = load_elf_image_shdr(addr);
> -
> #if CONFIG_IS_ENABLED(CMD_ELF_FDT_SETUP)
> if (fdt_addr) {
> - printf("## Setting up FDT at 0x%08lx ...\n", fdt_addr);
> + log_debug("Setting up FDT at 0x%08lx ...\n", fdt_addr);
> flush();
>
> if (image_setup_libfdt(&img, (void *)fdt_addr, NULL))
> @@ -93,21 +73,27 @@ int do_bootelf(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> }
> #endif
>
> - if (!env_get_autostart())
> - return rcode;
> -
> - printf("## Starting application at 0x%08lx ...\n", addr);
> - flush();
> + if (env_get_autostart()) {
> + flags.autostart = 1;
> + log_debug("Starting application at 0x%08lx ...\n", addr);
> + flush();
> + }
>
> /*
> * pass address parameter as argv[0] (aka command name),
> - * and all remaining args
> + * and all remaining arguments
> */
> - rc = do_bootelf_exec((void *)addr, argc, argv);
> + rc = bootelf(addr, flags, argc, argv);
> if (rc != 0)
> - rcode = 1;
> + rcode = CMD_RET_FAILURE;
>
> - printf("## Application terminated, rc = 0x%lx\n", rc);
> + if (flags.autostart)
> + {
> + if (ENOEXEC == errno)
> + log_err("Invalid ELF image\n");
> + else
> + log_debug("## Application terminated, rc = 0x%lx\n", rc);
> + }
>
> return rcode;
> }
> diff --git a/include/elf.h b/include/elf.h
> index a4ba74d8ab..b88e6cf403 100644
> --- a/include/elf.h
> +++ b/include/elf.h
> @@ -12,6 +12,12 @@
> #ifndef __ASSEMBLY__
> #include "compiler.h"
>
> +/* Flag param bits for bootelf() function */
> +typedef struct {
> + unsigned phdr : 1; /* load via program (not section) headers */
> + unsigned autostart : 1; /* Start ELF after loading */
> +} Bootelf_flags;
> +
> /* This version doesn't work for 64-bit ABIs - Erik */
>
> /* These typedefs need to be handled better */
> @@ -700,6 +706,10 @@ unsigned long elf_hash(const unsigned char *name);
> #define R_RISCV_RELATIVE 3
>
> #ifndef __ASSEMBLY__
> +unsigned long bootelf_exec(ulong (*entry)(int, char * const[]),
> + int argc, char *const argv[]);
> +unsigned long bootelf(unsigned long addr, Bootelf_flags flags,
> + int argc, char *const argv[]);
> int valid_elf_image(unsigned long addr);
> unsigned long load_elf64_image_phdr(unsigned long addr);
> unsigned long load_elf64_image_shdr(unsigned long addr);
> diff --git a/lib/elf.c b/lib/elf.c
> index 9a794f9cba..dc13935e10 100644
> --- a/lib/elf.c
> +++ b/lib/elf.c
> @@ -7,6 +7,7 @@
> #include <cpu_func.h>
> #include <elf.h>
> #include <env.h>
> +#include <errno.h>
> #include <net.h>
> #include <vxworks.h>
> #ifdef CONFIG_X86
> @@ -15,6 +16,59 @@
> #include <linux/linkage.h>
> #endif
>
> +/**
> + * bootelf_exec() - start the ELF image execution.
> + *
> + * @entry: address of entry point of ELF.
> + *
> + * May by used to allow ports to override the default behavior.
> + */
> +unsigned long bootelf_exec(ulong (*entry)(int, char * const[]),
> + int argc, char *const argv[])
> +{
> + return entry(argc, argv);
> +}
> +
> +/**
> + * bootelf() - Boot ELF from memory.
> + *
> + * @addr: Loading address of ELF in memory.
> + * @flags: Bits like ELF_PHDR to control boot details.
> + * @argc: May be used to pass command line arguments (maybe unused).
> + * Necessary for backward compatibility with the CLI command.
> + * If unused, must be 0.
> + * @argv: see @argc. If unused, must be NULL.
> + * Return: Number returned by ELF application.
> + *
> + * Sets errno = ENOEXEC if the ELF image is not valid.
> + */
> +unsigned long bootelf(unsigned long addr, Bootelf_flags flags,
> + int argc, char *const argv[])
> +{
> + unsigned long entry_addr;
> + char *args[] = {"", NULL};
> +
> + errno = 0;
> +
> + if (!valid_elf_image(addr)) {
> + errno = ENOEXEC;
> + return 1;
> + }
> +
> + entry_addr = flags.phdr ? load_elf_image_phdr(addr)
> + : load_elf_image_shdr(addr);
> +
> + if (!flags.autostart)
> + return 0;
> +
> + if (!argc && !argv) {
> + argc = 1;
> + argv = args;
> + }
> +
> + return bootelf_exec((void *)entry_addr, argc, argv);
> +}
> +
> /*
> * A very simple ELF64 loader, assumes the image is valid, returns the
> * entry point address.
More information about the U-Boot
mailing list