[U-Boot] [PATCH 4/7] remoteproc: add elf file load support
Fabien Dessenne
fabien.dessenne at st.com
Wed May 22 08:06:46 UTC 2019
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(-)
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;
+ }
+
+ if (size < sizeof(Elf32_Ehdr)) {
+ pr_err("Image is too small\n");
+ return -EINVAL;
+ }
+
+ 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;
+ }
+
+ /* 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;
+ }
+
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+ pr_err("Image is corrupted (bad magic)\n");
+ return -EINVAL;
+ }
+
+ 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;
+}
+
+/* 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;
+ }
+
+ /* 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.
*/
int rproc_is_running(int id);
+
+/**
+ * rproc_elf_is_valid() - check if an image is a valid ELF one
+ * @addr: image address
+ * @size: image size
+ */
+bool rproc_elf_is_valid(unsigned long addr, int size);
+
+/**
+ * rproc_elf_sanity_check() - verify an ELF image format
+ * @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
+ */
+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
More information about the U-Boot
mailing list