Hi Lokesh
On 29/05/2019 6:21 AM, Lokesh Vutla wrote: > > 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. It sounds good, I'll do that. > Ill be sending 64bit elf loading support soon. Instead of > cluttering rproc-uclass, it is better to separate out elf loading support. Since you plan support for elf64, I may consider renaming the elf functions in elf32. I'll check this too. BR Fabien > > 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