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