On 27/05/19 5:53 PM, Fabien Dessenne wrote:
> The current implementation supports only binary file load.
> Add helpers to support ELF format (sanity check, and load).
> Note that since an ELF image is built for the remote processor, the load
> function uses the device_to_virt ops to translate the addresses.
> Implement a basic translation for sandbox_testproc.
> 
> Add related tests. Test result:
> => ut dm remoteproc_elf
> Test: dm_test_remoteproc_elf: remoteproc.c
> Test: dm_test_remoteproc_elf: remoteproc.c (flat tree)
> Failures: 0
> 
> Signed-off-by: Loic Pallardy <loic.palla...@st.com>
> Signed-off-by: Fabien Dessenne <fabien.desse...@st.com>

Can you create a new file(rproc-elf-loader.c) or something similar for elf
loading support. Ill be sending 64bit elf loading support soon. Instead of
cluttering rproc-uclass, it is better to separate out elf loading support.

Thanks and regards,
Lokesh

> ---
>  drivers/remoteproc/rproc-uclass.c     |  99 +++++++++++++++++++++++++++
>  drivers/remoteproc/sandbox_testproc.c |  19 ++++++
>  include/remoteproc.h                  |  30 ++++++++-
>  test/dm/remoteproc.c                  | 122 
> ++++++++++++++++++++++++++++++++++
>  4 files changed, 267 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/remoteproc/rproc-uclass.c 
> b/drivers/remoteproc/rproc-uclass.c
> index c8a41a6..4d85732 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,104 @@ int rproc_dev_init(int id)
>       return ret;
>  }
>  
> +/* Basic function to verify ELF image format */
> +int rproc_elf_sanity_check(ulong addr, ulong size)
> +{
> +     Elf32_Ehdr *ehdr;
> +     char class;
> +
> +     if (!addr) {
> +             pr_debug("Invalid fw address?\n");
> +             return -EFAULT;
> +     }
> +
> +     if (size < sizeof(Elf32_Ehdr)) {
> +             pr_debug("Image is too small\n");
> +             return -ENOSPC;
> +     }
> +
> +     ehdr = (Elf32_Ehdr *)addr;
> +     class = ehdr->e_ident[EI_CLASS];
> +
> +     if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
> +             pr_debug("Not an executable ELF32 image\n");
> +             return -EPROTONOSUPPORT;
> +     }
> +
> +     /* 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_debug("Unsupported firmware endianness\n");
> +             return -EILSEQ;
> +     }
> +
> +     if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
> +             pr_debug("Image is too small\n");
> +             return -ENOSPC;
> +     }
> +
> +     if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> +             pr_debug("Image is corrupted (bad magic)\n");
> +             return -EBADF;
> +     }
> +
> +     if (ehdr->e_phnum == 0) {
> +             pr_debug("No loadable segments\n");
> +             return -ENOEXEC;
> +     }
> +
> +     if (ehdr->e_phoff > size) {
> +             pr_debug("Firmware size is too small\n");
> +             return -ENOSPC;
> +     }
> +
> +     return 0;
> +}
> +
> +/* 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);
> +
> +     /* 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->device_to_virt)
> +                     dst = ops->device_to_virt(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/drivers/remoteproc/sandbox_testproc.c 
> b/drivers/remoteproc/sandbox_testproc.c
> index 51a67e6..5f35119 100644
> --- a/drivers/remoteproc/sandbox_testproc.c
> +++ b/drivers/remoteproc/sandbox_testproc.c
> @@ -8,6 +8,7 @@
>  #include <dm.h>
>  #include <errno.h>
>  #include <remoteproc.h>
> +#include <asm/io.h>
>  
>  /**
>   * enum sandbox_state - different device states
> @@ -300,6 +301,23 @@ static int sandbox_testproc_ping(struct udevice *dev)
>       return ret;
>  }
>  
> +#define SANDBOX_RPROC_DEV_TO_PHY_OFFSET      0x1000
> +/**
> + * sandbox_testproc_device_to_virt() - Convert device address to virtual 
> address
> + * @dev:     device to operate upon
> + * @da:              device address
> + * @return converted virtual address
> + */
> +static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da)
> +{
> +     u64 paddr;
> +
> +     /* Use a simple offset conversion */
> +     paddr = da + SANDBOX_RPROC_DEV_TO_PHY_OFFSET;
> +
> +     return phys_to_virt(paddr);
> +}
> +
>  static const struct dm_rproc_ops sandbox_testproc_ops = {
>       .init = sandbox_testproc_init,
>       .reset = sandbox_testproc_reset,
> @@ -308,6 +326,7 @@ static const struct dm_rproc_ops sandbox_testproc_ops = {
>       .stop = sandbox_testproc_stop,
>       .is_running = sandbox_testproc_is_running,
>       .ping = sandbox_testproc_ping,
> +     .device_to_virt = sandbox_testproc_device_to_virt,
>  };
>  
>  static const struct udevice_id sandbox_ids[] = {
> diff --git a/include/remoteproc.h b/include/remoteproc.h
> index aef6ff2..f74ccc2 100644
> --- a/include/remoteproc.h
> +++ b/include/remoteproc.h
> @@ -151,10 +151,10 @@ 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
> + * @addr:    address in memory where the image is located
> + * @size:    size of the image
>   * @return 0 if all ok, else appropriate error value.
>   */
>  int rproc_load(int id, ulong addr, ulong size);
> @@ -200,6 +200,26 @@ int rproc_ping(int id);
>   * processor, but just ensures that it is out of reset and executing code.
>   */
>  int rproc_is_running(int id);
> +
> +/**
> + * rproc_elf_sanity_check() - Verify if an image is a valid ELF one
> + *
> + * Check if a valid ELF image exists at the given memory location. Verify
> + * basic ELF format requirements like magic number and sections size.
> + *
> + * @addr:    address of the image to verify
> + * @size:    size of the image
> + * @return 0 if the image looks good, else appropriate error value.
> + */
> +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 0 if the image is successfully loaded, else appropriate error 
> value.
> + */
> +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; }
> @@ -210,6 +230,10 @@ 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 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_ */
> diff --git a/test/dm/remoteproc.c b/test/dm/remoteproc.c
> index 3975c67..8d444fc 100644
> --- a/test/dm/remoteproc.c
> +++ b/test/dm/remoteproc.c
> @@ -5,8 +5,10 @@
>   */
>  #include <common.h>
>  #include <dm.h>
> +#include <elf.h>
>  #include <errno.h>
>  #include <remoteproc.h>
> +#include <asm/io.h>
>  #include <dm/test.h>
>  #include <test/ut.h>
>  /**
> @@ -65,3 +67,123 @@ static int dm_test_remoteproc_base(struct unit_test_state 
> *uts)
>       return 0;
>  }
>  DM_TEST(dm_test_remoteproc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> +
> +#define DEVICE_TO_PHYSICAL_OFFSET    0x1000
> +/**
> + * dm_test_remoteproc_elf() - test the ELF operations
> + * @uts:     unit test state
> + *
> + * Return:   0 if test passed, else error
> + */
> +static int dm_test_remoteproc_elf(struct unit_test_state *uts)
> +{
> +     u8 valid_elf32[] = {
> +             /* @0x00 - ELF HEADER - */
> +             /* ELF magic */
> +             0x7f, 0x45, 0x4c, 0x46,
> +             /* 32 Bits */
> +             0x01,
> +             /* Endianness */
> +#ifdef __LITTLE_ENDIAN
> +             0x01,
> +#else
> +             0x02,
> +#endif
> +             /* Version */
> +             0x01,
> +             /* Padding */
> +             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +             /* Type : executable */
> +             0x02, 0x00,
> +             /* Machine: ARM */
> +             0x28, 0x00,
> +             /* Version */
> +             0x01, 0x00, 0x00, 0x00,
> +             /* Entry */
> +             0x00, 0x00, 0x00, 0x08,
> +             /* phoff (program header offset @ 0x40)*/
> +             0x40, 0x00, 0x00, 0x00,
> +             /* shoff (section header offset : none) */
> +             0x00, 0x00, 0x00, 0x00,
> +             /* flags */
> +             0x00, 0x00, 0x00, 0x00,
> +             /* ehsize (elf header size = 0x34) */
> +             0x34, 0x00,
> +             /* phentsize (program header size = 0x20) */
> +             0x20, 0x00,
> +             /* phnum (program header number : 1) */
> +             0x01, 0x00,
> +             /* shentsize (section heade size : none) */
> +             0x00, 0x00,
> +             /* shnum (section header number: none) */
> +             0x00, 0x00,
> +             /* shstrndx (section header name section index: none) */
> +             0x00, 0x00,
> +             /* padding */
> +             0x00, 0x00, 0x00, 0x00,
> +             0x00, 0x00, 0x00, 0x00,
> +             0x00, 0x00, 0x00, 0x00,
> +             /* @0x40 - PROGRAM HEADER TABLE - */
> +             /* type : PT_LOAD */
> +             0x01, 0x00, 0x00, 0x00,
> +             /* offset */
> +             0x00, 0x00, 0x00, 0x00,
> +             /* vaddr */
> +             0x00, 0x00, 0x00, 0x00,
> +             /* paddr : physical address */
> +             0x00, 0x00, 0x00, 0x00,
> +             /* filesz : 0x20 bytes (program header size) */
> +             0x20, 0x00, 0x00, 0x00,
> +             /* memsz = filesz */
> +             0x20, 0x00, 0x00, 0x00,
> +             /* flags : readable and exectuable */
> +             0x05, 0x00, 0x00, 0x00,
> +             /* padding */
> +             0x00, 0x00, 0x00, 0x00,
> +     };
> +     unsigned int size = ARRAY_SIZE(valid_elf32);
> +     struct udevice *dev;
> +     phys_addr_t loaded_firmware_paddr;
> +     void *loaded_firmware;
> +     u32 loaded_firmware_size;
> +     Elf32_Ehdr *ehdr = (Elf32_Ehdr *)valid_elf32;
> +     Elf32_Phdr *phdr = (Elf32_Phdr *)(valid_elf32 + ehdr->e_phoff);
> +
> +     ut_assertok(uclass_get_device(UCLASS_REMOTEPROC, 0, &dev));
> +
> +     /*
> +      * In its Program Header Table, let the firmware specifies to be loaded
> +      * at SDRAM_BASE *device* address (p_paddr field).
> +      * Its size is defined by the p_filesz field.
> +      */
> +     phdr->p_paddr = CONFIG_SYS_SDRAM_BASE;
> +     loaded_firmware_size = phdr->p_filesz;
> +
> +     /*
> +      * This *device* address is converted to a *physical* address by the
> +      * device_to_virt() operation of sandbox_test_rproc which returns
> +      * DeviceAddress + DEVICE_TO_PHYSICAL_OFFSET.
> +      * This is where we expect to get the firmware loaded.
> +      */
> +     loaded_firmware_paddr = phdr->p_paddr + DEVICE_TO_PHYSICAL_OFFSET;
> +     loaded_firmware = map_physmem(loaded_firmware_paddr,
> +                                   loaded_firmware_size, MAP_NOCACHE);
> +     ut_assertnonnull(loaded_firmware);
> +     memset(loaded_firmware, 0, loaded_firmware_size);
> +
> +     /* Verify valid ELF format */
> +     ut_assertok(rproc_elf_sanity_check((ulong)valid_elf32, size));
> +
> +     /* Load firmware in loaded_firmware, and verify it */
> +     ut_assertok(rproc_elf_load_image(dev, (unsigned long)valid_elf32));
> +     ut_assertok(memcmp(loaded_firmware, valid_elf32, loaded_firmware_size));
> +     unmap_physmem(loaded_firmware, MAP_NOCACHE);
> +
> +     /* Invalid ELF Magic */
> +     valid_elf32[0] = 0;
> +     ut_asserteq(-EPROTONOSUPPORT,
> +                 rproc_elf_sanity_check((ulong)valid_elf32, size));
> +
> +     return 0;
> +}
> +DM_TEST(dm_test_remoteproc_elf, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
> 
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to