[U-Boot] [PATCH 4/7] remoteproc: add elf file load support
Simon Glass
sjg at chromium.org
Thu May 23 00:18:23 UTC 2019
Hi Fabien,
On Wed, 22 May 2019 at 02:07, Fabien Dessenne <fabien.dessenne at st.com> wrote:
>
> The current implementation supports only binary file load.
> Add helpers to support ELF format (check validity, sanity check, and
> load).
> Note that since an ELF image is built for the remote processor, the load
> function uses the da_to_pa ops to translate the addresses.
>
> Signed-off-by: Loic Pallardy <loic.pallardy at st.com>
> Signed-off-by: Fabien Dessenne <fabien.dessenne at st.com>
> ---
> drivers/remoteproc/rproc-uclass.c | 128 ++++++++++++++++++++++++++++++++++++++
> include/remoteproc.h | 29 ++++++++-
> 2 files changed, 156 insertions(+), 1 deletion(-)
It doesn't look like we can easily make use of the existing ELF loader.
But please add a test for this in test/dm/remoteproc.c and see below.
>
> diff --git a/drivers/remoteproc/rproc-uclass.c b/drivers/remoteproc/rproc-uclass.c
> index c8a41a6..ac5f9e2 100644
> --- a/drivers/remoteproc/rproc-uclass.c
> +++ b/drivers/remoteproc/rproc-uclass.c
> @@ -5,6 +5,7 @@
> */
> #define pr_fmt(fmt) "%s: " fmt, __func__
> #include <common.h>
> +#include <elf.h>
> #include <errno.h>
> #include <fdtdec.h>
> #include <malloc.h>
> @@ -291,6 +292,133 @@ int rproc_dev_init(int id)
> return ret;
> }
>
> +/*
> + * Determine if a valid ELF image exists at the given memory location.
> + * First look at the ELF header magic field, then make sure that it is
> + * executable.
> + */
> +bool rproc_elf_is_valid(unsigned long addr, int size)
> +{
> + Elf32_Ehdr *ehdr; /* Elf header structure pointer */
> +
> + ehdr = (Elf32_Ehdr *)addr;
> +
> + if (!IS_ELF(*ehdr) || size <= sizeof(Elf32_Ehdr)) {
> + pr_err("No elf image at address 0x%08lx\n", addr);
> + return false;
> + }
> +
> + if (ehdr->e_type != ET_EXEC) {
> + pr_err("Not a 32-bit elf image at address 0x%08lx\n", addr);
> + return false;
> + }
> +
> + return true;
> +}
> +
> +/* Basic function to verify ELF image format */
> +int rproc_elf_sanity_check(ulong addr, ulong size)
> +{
> + Elf32_Ehdr *ehdr;
> + char class;
> +
> + if (!addr) {
> + pr_err("Invalid fw address?\n");
> + return -EINVAL;
EFAULT ?
> + }
> +
> + if (size < sizeof(Elf32_Ehdr)) {
> + pr_err("Image is too small\n");
> + return -EINVAL;
ENOSPC?
> + }
> +
> + ehdr = (Elf32_Ehdr *)addr;
> +
> + /* We only support ELF32 at this point */
> + class = ehdr->e_ident[EI_CLASS];
> + if (class != ELFCLASS32) {
> + pr_err("Unsupported class: %d\n", class);
> + return -EINVAL;
EPROTONOSUPP?
> + }
> +
> + /* We assume the firmware has the same endianness as the host */
> +# ifdef __LITTLE_ENDIAN
> + if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
> +# else /* BIG ENDIAN */
> + if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
> +# endif
> + pr_err("Unsupported firmware endianness\n");
> + return -EINVAL;
> + }
> +
> + if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
> + pr_err("Image is too small\n");
> + return -EINVAL;
ESPC
> + }
> +
> + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> + pr_err("Image is corrupted (bad magic)\n");
> + return -EINVAL;
EBADF
> + }
> +
> + if (ehdr->e_phnum == 0) {
> + pr_err("No loadable segments\n");
> + return -EINVAL;
> + }
> +
> + if (ehdr->e_phoff > size) {
> + pr_err("Firmware size is too small\n");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
They are just suggestions, but please try to return useful numbers. In
general it should be possible to see what went wrong without needing
to output text.
> +/* A very simple elf loader, assumes the image is valid */
> +int rproc_elf_load_image(struct udevice *dev, unsigned long addr)
> +{
> + Elf32_Ehdr *ehdr; /* Elf header structure pointer */
> + Elf32_Phdr *phdr; /* Program header structure pointer */
> + const struct dm_rproc_ops *ops;
> + unsigned int i;
> +
> + ehdr = (Elf32_Ehdr *)addr;
> + phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
> +
> + ops = rproc_get_ops(dev);
> + if (!ops) {
> + dev_dbg(dev, "Driver has no ops?\n");
> + return -EINVAL;
> + }
This is not allowed, so you don't need to check for it.
> +
> + /* Load each program header */
> + for (i = 0; i < ehdr->e_phnum; ++i) {
> + void *dst = (void *)(uintptr_t)phdr->p_paddr;
> + void *src = (void *)addr + phdr->p_offset;
> +
> + if (phdr->p_type != PT_LOAD)
> + continue;
> +
> + if (ops->da_to_pa)
> + dst = (void *)ops->da_to_pa(dev, (ulong)dst);
> +
> + dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
> + i, dst, phdr->p_filesz);
> + if (phdr->p_filesz)
> + memcpy(dst, src, phdr->p_filesz);
> + if (phdr->p_filesz != phdr->p_memsz)
> + memset(dst + phdr->p_filesz, 0x00,
> + phdr->p_memsz - phdr->p_filesz);
> + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
> + roundup((unsigned long)dst + phdr->p_filesz,
> + ARCH_DMA_MINALIGN) -
> + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
> + ++phdr;
> + }
> +
> + return 0;
> +}
> +
> int rproc_load(int id, ulong addr, ulong size)
> {
> struct udevice *dev = NULL;
> diff --git a/include/remoteproc.h b/include/remoteproc.h
> index 58df11a..5cc04e6 100644
> --- a/include/remoteproc.h
> +++ b/include/remoteproc.h
> @@ -104,7 +104,7 @@ int rproc_dev_init(int id);
> bool rproc_is_initialized(void);
>
> /**
> - * rproc_load() - load binary to a remote processor
> + * rproc_load() - load binary or elf to a remote processor
> * @id: id of the remote processor
> * @addr: address in memory where the binary image is located
> * @size: size of the binary image
> @@ -159,6 +159,27 @@ int rproc_ping(int id);
> * Return: 0 if all ok, else appropriate error value.
What does ok mean? Running?
> */
> int rproc_is_running(int id);
> +
> +/**
> + * rproc_elf_is_valid() - check if an image is a valid ELF one
In what sense?
> + * @addr: image address
Is this address in the remote space?
In general your comments are a bit brief
> + * @size: image size
@return - also please use an int return (e.g. 0 is valid and -ve error
means not). You could rename to rproc_elf_check_valid()
> + */
> +bool rproc_elf_is_valid(unsigned long addr, int size);
> +
> +/**
> + * rproc_elf_sanity_check() - verify an ELF image format
What is different about this from the above functions?
> + * @addr: ELF image address
> + * @size: ELF image size
> + */
> +int rproc_elf_sanity_check(ulong addr, ulong size);
> +
> +/**
> + * rproc_elf_load_image() - load an ELF image
> + * @dev: device loading the ELF image
> + * @addr: valid ELF image address
@return
> + */
> +int rproc_elf_load_image(struct udevice *dev, unsigned long addr);
> #else
> static inline int rproc_init(void) { return -ENOSYS; }
> static inline int rproc_dev_init(int id) { return -ENOSYS; }
> @@ -169,6 +190,12 @@ static inline int rproc_stop(int id) { return -ENOSYS; }
> static inline int rproc_reset(int id) { return -ENOSYS; }
> static inline int rproc_ping(int id) { return -ENOSYS; }
> static inline int rproc_is_running(int id) { return -ENOSYS; }
> +static inline bool rproc_elf_is_valid(unsigned long addr,
> + int size) { return -ENOSYS; }
> +static inline int rproc_elf_sanity_check(ulong addr,
> + ulong size) { return -ENOSYS; }
> +static inline int rproc_elf_load_image(struct udevice *dev,
> + unsigned long addr) { return -ENOSYS; }
> #endif
>
> #endif /* _RPROC_H_ */
> --
> 2.7.4
>
Regards,
Simon
More information about the U-Boot
mailing list