linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] rproc: Add elf64 support in elf loader
       [not found] <04be3345-698d-29b0-7b4b-7eed088e490d@st.com>
@ 2019-08-19 11:45 ` Clement Leger
  2019-09-13 10:58   ` Clément Leger
  2019-10-04 18:42   ` [PATCH v2] remoteproc: " Clement Leger
  0 siblings, 2 replies; 76+ messages in thread
From: Clement Leger @ 2019-08-19 11:45 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel
  Cc: Loic Pallardy, Arnaud POULIQUEN, Clément Leger

From: Clément Leger <cleger@kalray.eu>

elf32 and elf64 mainly differ by their types. In order to avoid
copy/pasting the whole loader code, generate static inline functions
which will access values according to the elf class. It allows to keep a
common loader basis.
In order to accomodate both elf types sizes, the maximum size for a
elf header member is chosen using the maximum value of both elf class.

Signed-off-by: Clement Leger <cleger@kalray.eu>
Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
---
 drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
 drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
 drivers/remoteproc/remoteproc_internal.h   |   2 +-
 drivers/remoteproc/st_remoteproc.c         |   2 +-
 include/linux/remoteproc.h                 |   4 +-
 5 files changed, 156 insertions(+), 56 deletions(-)
 create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index b17d72ec8603..6a2d31d6092c 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -31,6 +31,7 @@
 #include <linux/elf.h>
 
 #include "remoteproc_internal.h"
+#include "remoteproc_elf_loader.h"
 
 /**
  * rproc_elf_sanity_check() - Sanity Check ELF firmware image
@@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 {
 	const char *name = rproc->firmware;
 	struct device *dev = &rproc->dev;
+	/*
+	 * Elf files are beginning with the same structure. Thus, to simplify
+	 * header parsing, we can use the elf32_hdr one for both elf64 and
+	 * elf32.
+	 */
 	struct elf32_hdr *ehdr;
+	u32 elf_shdr_size;
+	u64 phoff, shoff;
 	char class;
+	u16 phnum;
 
 	if (!fw) {
 		dev_err(dev, "failed to load %s\n", name);
@@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 
 	ehdr = (struct elf32_hdr *)fw->data;
 
-	/* We only support ELF32 at this point */
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(dev, "Image is corrupted (bad magic)\n");
+		return -EINVAL;
+	}
+
 	class = ehdr->e_ident[EI_CLASS];
-	if (class != ELFCLASS32) {
+	if (class != ELFCLASS32 && class != ELFCLASS64) {
 		dev_err(dev, "Unsupported class: %d\n", class);
 		return -EINVAL;
 	}
@@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 		return -EINVAL;
 	}
 
-	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
-		dev_err(dev, "Image is too small\n");
-		return -EINVAL;
-	}
+	phoff = elf_hdr_e_phoff(class, fw->data);
+	shoff = elf_hdr_e_shoff(class, fw->data);
+	phnum =  elf_hdr_e_phnum(class, fw->data);
+	elf_shdr_size = elf_size_of_shdr(class);
 
-	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(dev, "Image is corrupted (bad magic)\n");
+	if (fw->size < shoff + elf_shdr_size) {
+		dev_err(dev, "Image is too small\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phnum == 0) {
+	if (phnum == 0) {
 		dev_err(dev, "No loadable segments\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phoff > fw->size) {
+	if (phoff > fw->size) {
 		dev_err(dev, "Firmware size is too small\n");
 		return -EINVAL;
 	}
 
+	dev_dbg(dev, "Firmware is an elf%d file\n",
+		class == ELFCLASS32 ? 32 : 64);
+
 	return 0;
 }
 EXPORT_SYMBOL(rproc_elf_sanity_check);
@@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
  * Note that the boot address is not a configurable property of all remote
  * processors. Some will always boot at a specific hard-coded address.
  */
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
-
-	return ehdr->e_entry;
+	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
 }
 EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 
@@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 {
 	struct device *dev = &rproc->dev;
-	struct elf32_hdr *ehdr;
-	struct elf32_phdr *phdr;
+	const void *ehdr, *phdr;
 	int i, ret = 0;
+	u16 phnum;
 	const u8 *elf_data = fw->data;
+	u8 class = fw_elf_get_class(fw);
+	u32 elf_phdr_size = elf_size_of_phdr(class);
 
-	ehdr = (struct elf32_hdr *)elf_data;
-	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+	ehdr = elf_data;
+	phnum = elf_hdr_e_phnum(class, ehdr);
+	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
 
 	/* go through the available ELF segments */
-	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-		u32 da = phdr->p_paddr;
-		u32 memsz = phdr->p_memsz;
-		u32 filesz = phdr->p_filesz;
-		u32 offset = phdr->p_offset;
+	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
+		u64 da = elf_phdr_p_paddr(class, phdr);
+		u64 memsz = elf_phdr_p_memsz(class, phdr);
+		u64 filesz = elf_phdr_p_filesz(class, phdr);
+		u64 offset = elf_phdr_p_offset(class, phdr);
+		u32 type = elf_phdr_p_type(class, phdr);
 		void *ptr;
 
-		if (phdr->p_type != PT_LOAD)
+		if (type != PT_LOAD)
 			continue;
 
-		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-			phdr->p_type, da, memsz, filesz);
+		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
+			type, da, memsz, filesz);
 
 		if (filesz > memsz) {
-			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
 				filesz, memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		if (offset + filesz > fw->size) {
-			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
+			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
 				offset + filesz, fw->size);
 			ret = -EINVAL;
 			break;
@@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 		/* grab the kernel address for this device address */
 		ptr = rproc_da_to_va(rproc, da, memsz);
 		if (!ptr) {
-			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
+				memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		/* put the segment where the remote processor expects it */
-		if (phdr->p_filesz)
-			memcpy(ptr, elf_data + phdr->p_offset, filesz);
+		if (filesz)
+			memcpy(ptr, elf_data + offset, filesz);
 
 		/*
 		 * Zero out remaining memory for this segment.
@@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 }
 EXPORT_SYMBOL(rproc_elf_load_segments);
 
-static struct elf32_shdr *
-find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
+static const void *
+find_table(struct device *dev, const struct firmware *fw)
 {
-	struct elf32_shdr *shdr;
+	const void *shdr, *name_table_shdr;
 	int i;
 	const char *name_table;
 	struct resource_table *table = NULL;
-	const u8 *elf_data = (void *)ehdr;
+	const u8 *elf_data = (void *)fw->data;
+	u8 class = fw_elf_get_class(fw);
+	size_t fw_size = fw->size;
+	const void *ehdr = elf_data;
+	u16 shnum = elf_hdr_e_shnum(class, ehdr);
+	u32 elf_shdr_size = elf_size_of_shdr(class);
+	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
 
 	/* look for the resource table and handle it */
-	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
-	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
+	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
+	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
+	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
 
-	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
-		u32 size = shdr->sh_size;
-		u32 offset = shdr->sh_offset;
+	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
+		u64 size = elf_shdr_sh_size(class, shdr);
+		u64 offset = elf_shdr_sh_offset(class, shdr);
+		u32 name = elf_shdr_sh_name(class, shdr);
 
-		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+		if (strcmp(name_table + name, ".resource_table"))
 			continue;
 
 		table = (struct resource_table *)(elf_data + offset);
@@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
  */
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr;
-	struct elf32_shdr *shdr;
+	const void *shdr;
 	struct device *dev = &rproc->dev;
 	struct resource_table *table = NULL;
 	const u8 *elf_data = fw->data;
 	size_t tablesz;
+	u8 class = fw_elf_get_class(fw);
+	u64 sh_offset;
 
-	ehdr = (struct elf32_hdr *)elf_data;
-
-	shdr = find_table(dev, ehdr, fw->size);
+	shdr = find_table(dev, fw);
 	if (!shdr)
 		return -EINVAL;
 
-	table = (struct resource_table *)(elf_data + shdr->sh_offset);
-	tablesz = shdr->sh_size;
+	sh_offset = elf_shdr_sh_offset(class, shdr);
+	table = (struct resource_table *)(elf_data + sh_offset);
+	tablesz = elf_shdr_sh_size(class, shdr);
 
 	/*
 	 * Create a copy of the resource table. When a virtio device starts
@@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 						       const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
-	struct elf32_shdr *shdr;
+	const void *shdr;
+	u64 sh_addr, sh_size;
+	u8 class = fw_elf_get_class(fw);
 
-	shdr = find_table(&rproc->dev, ehdr, fw->size);
+	shdr = find_table(&rproc->dev, fw);
 	if (!shdr)
 		return NULL;
 
-	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
+	sh_addr = elf_shdr_sh_addr(class, shdr);
+	sh_size = elf_shdr_sh_size(class, shdr);
+
+	return rproc_da_to_va(rproc, sh_addr, sh_size);
 }
 EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
diff --git a/drivers/remoteproc/remoteproc_elf_loader.h b/drivers/remoteproc/remoteproc_elf_loader.h
new file mode 100644
index 000000000000..fac3565734f9
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_elf_loader.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Remote processor elf loader defines
+ *
+ * Copyright (C) 2019 Kalray, Inc.
+ */
+
+#ifndef REMOTEPROC_ELF_LOADER_H
+#define REMOTEPROC_ELF_LOADER_H
+
+#include <linux/elf.h>
+#include <linux/types.h>
+
+/**
+ * fw_elf_get_class - Get elf class
+ * @fw: the ELF firmware image
+ *
+ * Note that we use and elf32_hdr to access the class since the start of the
+ * struct is the same for both elf class
+ *
+ * Return: elf class of the firmware
+ */
+static inline u8 fw_elf_get_class(const struct firmware *fw)
+{
+	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
+
+	return ehdr->e_ident[EI_CLASS];
+}
+
+#define ELF_GET_FIELD(__s, __field, __type) \
+static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
+{ \
+	if (class == ELFCLASS32) \
+		return (__type) ((const struct elf32_##__s *) arg)->__field; \
+	else \
+		return (__type) ((const struct elf64_##__s *) arg)->__field; \
+}
+
+ELF_GET_FIELD(hdr, e_entry, u64)
+ELF_GET_FIELD(hdr, e_phnum, u16)
+ELF_GET_FIELD(hdr, e_shnum, u16)
+ELF_GET_FIELD(hdr, e_phoff, u64)
+ELF_GET_FIELD(hdr, e_shoff, u64)
+ELF_GET_FIELD(hdr, e_shstrndx, u16)
+
+ELF_GET_FIELD(phdr, p_paddr, u64)
+ELF_GET_FIELD(phdr, p_filesz, u64)
+ELF_GET_FIELD(phdr, p_memsz, u64)
+ELF_GET_FIELD(phdr, p_type, u32)
+ELF_GET_FIELD(phdr, p_offset, u64)
+
+ELF_GET_FIELD(shdr, sh_size, u64)
+ELF_GET_FIELD(shdr, sh_offset, u64)
+ELF_GET_FIELD(shdr, sh_name, u32)
+ELF_GET_FIELD(shdr, sh_addr, u64)
+
+#define ELF_STRUCT_SIZE(__s) \
+static inline unsigned long elf_size_of_##__s(u8 class) \
+{ \
+	if (class == ELFCLASS32)\
+		return sizeof(struct elf32_##__s); \
+	else \
+		return sizeof(struct elf64_##__s); \
+}
+
+ELF_STRUCT_SIZE(shdr)
+ELF_STRUCT_SIZE(phdr)
+
+#endif /* REMOTEPROC_ELF_LOADER_H */
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 45ff76a06c72..4ef745e3a1bc 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
 int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index 51049d17b1e5..e23abd8a96b0 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
 		}
 	}
 
-	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
+	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
 
 	return 0;
 
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 04d04709f2bd..512de9a2590c 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -362,7 +362,7 @@ struct rproc_ops {
 				struct rproc *rproc, const struct firmware *fw);
 	int (*load)(struct rproc *rproc, const struct firmware *fw);
 	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
-	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
 };
 
 /**
@@ -478,7 +478,7 @@ struct rproc {
 	int num_traces;
 	struct list_head carveouts;
 	struct list_head mappings;
-	u32 bootaddr;
+	u64 bootaddr;
 	struct list_head rvdevs;
 	struct list_head subdevs;
 	struct idr notifyids;
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [PATCH] rproc: Add elf64 support in elf loader
  2019-08-19 11:45 ` [PATCH] rproc: Add elf64 support in elf loader Clement Leger
@ 2019-09-13 10:58   ` Clément Leger
  2019-10-04  8:27     ` Clément Leger
  2019-10-04 18:42   ` [PATCH v2] remoteproc: " Clement Leger
  1 sibling, 1 reply; 76+ messages in thread
From: Clément Leger @ 2019-09-13 10:58 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel
  Cc: Loic PALLARDY, Arnaud Pouliquen

Ping ?

----- On 19 Aug, 2019, at 13:45, Clément Leger cleger@kalray.eu wrote:

> From: Clément Leger <cleger@kalray.eu>
> 
> elf32 and elf64 mainly differ by their types. In order to avoid
> copy/pasting the whole loader code, generate static inline functions
> which will access values according to the elf class. It allows to keep a
> common loader basis.
> In order to accomodate both elf types sizes, the maximum size for a
> elf header member is chosen using the maximum value of both elf class.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>
> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
> ---
> drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
> drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
> drivers/remoteproc/remoteproc_internal.h   |   2 +-
> drivers/remoteproc/st_remoteproc.c         |   2 +-
> include/linux/remoteproc.h                 |   4 +-
> 5 files changed, 156 insertions(+), 56 deletions(-)
> create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
> 
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
> b/drivers/remoteproc/remoteproc_elf_loader.c
> index b17d72ec8603..6a2d31d6092c 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -31,6 +31,7 @@
> #include <linux/elf.h>
> 
> #include "remoteproc_internal.h"
> +#include "remoteproc_elf_loader.h"
> 
> /**
>  * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> firmware *fw)
> {
> 	const char *name = rproc->firmware;
> 	struct device *dev = &rproc->dev;
> +	/*
> +	 * Elf files are beginning with the same structure. Thus, to simplify
> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
> +	 * elf32.
> +	 */
> 	struct elf32_hdr *ehdr;
> +	u32 elf_shdr_size;
> +	u64 phoff, shoff;
> 	char class;
> +	u16 phnum;
> 
> 	if (!fw) {
> 		dev_err(dev, "failed to load %s\n", name);
> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> firmware *fw)
> 
> 	ehdr = (struct elf32_hdr *)fw->data;
> 
> -	/* We only support ELF32 at this point */
> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> +		dev_err(dev, "Image is corrupted (bad magic)\n");
> +		return -EINVAL;
> +	}
> +
> 	class = ehdr->e_ident[EI_CLASS];
> -	if (class != ELFCLASS32) {
> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
> 		dev_err(dev, "Unsupported class: %d\n", class);
> 		return -EINVAL;
> 	}
> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> firmware *fw)
> 		return -EINVAL;
> 	}
> 
> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
> -		dev_err(dev, "Image is too small\n");
> -		return -EINVAL;
> -	}
> +	phoff = elf_hdr_e_phoff(class, fw->data);
> +	shoff = elf_hdr_e_shoff(class, fw->data);
> +	phnum =  elf_hdr_e_phnum(class, fw->data);
> +	elf_shdr_size = elf_size_of_shdr(class);
> 
> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> -		dev_err(dev, "Image is corrupted (bad magic)\n");
> +	if (fw->size < shoff + elf_shdr_size) {
> +		dev_err(dev, "Image is too small\n");
> 		return -EINVAL;
> 	}
> 
> -	if (ehdr->e_phnum == 0) {
> +	if (phnum == 0) {
> 		dev_err(dev, "No loadable segments\n");
> 		return -EINVAL;
> 	}
> 
> -	if (ehdr->e_phoff > fw->size) {
> +	if (phoff > fw->size) {
> 		dev_err(dev, "Firmware size is too small\n");
> 		return -EINVAL;
> 	}
> 
> +	dev_dbg(dev, "Firmware is an elf%d file\n",
> +		class == ELFCLASS32 ? 32 : 64);
> +
> 	return 0;
> }
> EXPORT_SYMBOL(rproc_elf_sanity_check);
> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>  * Note that the boot address is not a configurable property of all remote
>  * processors. Some will always boot at a specific hard-coded address.
>  */
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> {
> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
> -
> -	return ehdr->e_entry;
> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
> }
> EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> 
> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
> {
> 	struct device *dev = &rproc->dev;
> -	struct elf32_hdr *ehdr;
> -	struct elf32_phdr *phdr;
> +	const void *ehdr, *phdr;
> 	int i, ret = 0;
> +	u16 phnum;
> 	const u8 *elf_data = fw->data;
> +	u8 class = fw_elf_get_class(fw);
> +	u32 elf_phdr_size = elf_size_of_phdr(class);
> 
> -	ehdr = (struct elf32_hdr *)elf_data;
> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> +	ehdr = elf_data;
> +	phnum = elf_hdr_e_phnum(class, ehdr);
> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
> 
> 	/* go through the available ELF segments */
> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> -		u32 da = phdr->p_paddr;
> -		u32 memsz = phdr->p_memsz;
> -		u32 filesz = phdr->p_filesz;
> -		u32 offset = phdr->p_offset;
> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
> +		u64 da = elf_phdr_p_paddr(class, phdr);
> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
> +		u64 offset = elf_phdr_p_offset(class, phdr);
> +		u32 type = elf_phdr_p_type(class, phdr);
> 		void *ptr;
> 
> -		if (phdr->p_type != PT_LOAD)
> +		if (type != PT_LOAD)
> 			continue;
> 
> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
> -			phdr->p_type, da, memsz, filesz);
> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
> +			type, da, memsz, filesz);
> 
> 		if (filesz > memsz) {
> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
> 				filesz, memsz);
> 			ret = -EINVAL;
> 			break;
> 		}
> 
> 		if (offset + filesz > fw->size) {
> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
> 				offset + filesz, fw->size);
> 			ret = -EINVAL;
> 			break;
> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> struct firmware *fw)
> 		/* grab the kernel address for this device address */
> 		ptr = rproc_da_to_va(rproc, da, memsz);
> 		if (!ptr) {
> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
> +				memsz);
> 			ret = -EINVAL;
> 			break;
> 		}
> 
> 		/* put the segment where the remote processor expects it */
> -		if (phdr->p_filesz)
> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
> +		if (filesz)
> +			memcpy(ptr, elf_data + offset, filesz);
> 
> 		/*
> 		 * Zero out remaining memory for this segment.
> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> struct firmware *fw)
> }
> EXPORT_SYMBOL(rproc_elf_load_segments);
> 
> -static struct elf32_shdr *
> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> +static const void *
> +find_table(struct device *dev, const struct firmware *fw)
> {
> -	struct elf32_shdr *shdr;
> +	const void *shdr, *name_table_shdr;
> 	int i;
> 	const char *name_table;
> 	struct resource_table *table = NULL;
> -	const u8 *elf_data = (void *)ehdr;
> +	const u8 *elf_data = (void *)fw->data;
> +	u8 class = fw_elf_get_class(fw);
> +	size_t fw_size = fw->size;
> +	const void *ehdr = elf_data;
> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
> +	u32 elf_shdr_size = elf_size_of_shdr(class);
> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
> 
> 	/* look for the resource table and handle it */
> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
> 
> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> -		u32 size = shdr->sh_size;
> -		u32 offset = shdr->sh_offset;
> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
> +		u64 size = elf_shdr_sh_size(class, shdr);
> +		u64 offset = elf_shdr_sh_offset(class, shdr);
> +		u32 name = elf_shdr_sh_name(class, shdr);
> 
> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
> +		if (strcmp(name_table + name, ".resource_table"))
> 			continue;
> 
> 		table = (struct resource_table *)(elf_data + offset);
> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
> size_t fw_size)
>  */
> int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
> {
> -	struct elf32_hdr *ehdr;
> -	struct elf32_shdr *shdr;
> +	const void *shdr;
> 	struct device *dev = &rproc->dev;
> 	struct resource_table *table = NULL;
> 	const u8 *elf_data = fw->data;
> 	size_t tablesz;
> +	u8 class = fw_elf_get_class(fw);
> +	u64 sh_offset;
> 
> -	ehdr = (struct elf32_hdr *)elf_data;
> -
> -	shdr = find_table(dev, ehdr, fw->size);
> +	shdr = find_table(dev, fw);
> 	if (!shdr)
> 		return -EINVAL;
> 
> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
> -	tablesz = shdr->sh_size;
> +	sh_offset = elf_shdr_sh_offset(class, shdr);
> +	table = (struct resource_table *)(elf_data + sh_offset);
> +	tablesz = elf_shdr_sh_size(class, shdr);
> 
> 	/*
> 	 * Create a copy of the resource table. When a virtio device starts
> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
> struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> 						       const struct firmware *fw)
> {
> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> -	struct elf32_shdr *shdr;
> +	const void *shdr;
> +	u64 sh_addr, sh_size;
> +	u8 class = fw_elf_get_class(fw);
> 
> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
> +	shdr = find_table(&rproc->dev, fw);
> 	if (!shdr)
> 		return NULL;
> 
> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
> +	sh_addr = elf_shdr_sh_addr(class, shdr);
> +	sh_size = elf_shdr_sh_size(class, shdr);
> +
> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
> }
> EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
> b/drivers/remoteproc/remoteproc_elf_loader.h
> new file mode 100644
> index 000000000000..fac3565734f9
> --- /dev/null
> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
> @@ -0,0 +1,69 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Remote processor elf loader defines
> + *
> + * Copyright (C) 2019 Kalray, Inc.
> + */
> +
> +#ifndef REMOTEPROC_ELF_LOADER_H
> +#define REMOTEPROC_ELF_LOADER_H
> +
> +#include <linux/elf.h>
> +#include <linux/types.h>
> +
> +/**
> + * fw_elf_get_class - Get elf class
> + * @fw: the ELF firmware image
> + *
> + * Note that we use and elf32_hdr to access the class since the start of the
> + * struct is the same for both elf class
> + *
> + * Return: elf class of the firmware
> + */
> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> +{
> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> +
> +	return ehdr->e_ident[EI_CLASS];
> +}
> +
> +#define ELF_GET_FIELD(__s, __field, __type) \
> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
> +{ \
> +	if (class == ELFCLASS32) \
> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
> +	else \
> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
> +}
> +
> +ELF_GET_FIELD(hdr, e_entry, u64)
> +ELF_GET_FIELD(hdr, e_phnum, u16)
> +ELF_GET_FIELD(hdr, e_shnum, u16)
> +ELF_GET_FIELD(hdr, e_phoff, u64)
> +ELF_GET_FIELD(hdr, e_shoff, u64)
> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
> +
> +ELF_GET_FIELD(phdr, p_paddr, u64)
> +ELF_GET_FIELD(phdr, p_filesz, u64)
> +ELF_GET_FIELD(phdr, p_memsz, u64)
> +ELF_GET_FIELD(phdr, p_type, u32)
> +ELF_GET_FIELD(phdr, p_offset, u64)
> +
> +ELF_GET_FIELD(shdr, sh_size, u64)
> +ELF_GET_FIELD(shdr, sh_offset, u64)
> +ELF_GET_FIELD(shdr, sh_name, u32)
> +ELF_GET_FIELD(shdr, sh_addr, u64)
> +
> +#define ELF_STRUCT_SIZE(__s) \
> +static inline unsigned long elf_size_of_##__s(u8 class) \
> +{ \
> +	if (class == ELFCLASS32)\
> +		return sizeof(struct elf32_##__s); \
> +	else \
> +		return sizeof(struct elf64_##__s); \
> +}
> +
> +ELF_STRUCT_SIZE(shdr)
> +ELF_STRUCT_SIZE(phdr)
> +
> +#endif /* REMOTEPROC_ELF_LOADER_H */
> diff --git a/drivers/remoteproc/remoteproc_internal.h
> b/drivers/remoteproc/remoteproc_internal.h
> index 45ff76a06c72..4ef745e3a1bc 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
> int rproc_trigger_recovery(struct rproc *rproc);
> 
> int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
> int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
> struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> diff --git a/drivers/remoteproc/st_remoteproc.c
> b/drivers/remoteproc/st_remoteproc.c
> index 51049d17b1e5..e23abd8a96b0 100644
> --- a/drivers/remoteproc/st_remoteproc.c
> +++ b/drivers/remoteproc/st_remoteproc.c
> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
> 		}
> 	}
> 
> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
> 
> 	return 0;
> 
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 04d04709f2bd..512de9a2590c 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -362,7 +362,7 @@ struct rproc_ops {
> 				struct rproc *rproc, const struct firmware *fw);
> 	int (*load)(struct rproc *rproc, const struct firmware *fw);
> 	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> };
> 
> /**
> @@ -478,7 +478,7 @@ struct rproc {
> 	int num_traces;
> 	struct list_head carveouts;
> 	struct list_head mappings;
> -	u32 bootaddr;
> +	u64 bootaddr;
> 	struct list_head rvdevs;
> 	struct list_head subdevs;
> 	struct idr notifyids;
> --
> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH] rproc: Add elf64 support in elf loader
  2019-09-13 10:58   ` Clément Leger
@ 2019-10-04  8:27     ` Clément Leger
  0 siblings, 0 replies; 76+ messages in thread
From: Clément Leger @ 2019-10-04  8:27 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel
  Cc: Loic PALLARDY, Arnaud Pouliquen

Ping ?

----- On 13 Sep, 2019, at 12:58, Clément Leger cleger@kalray.eu wrote:

> Ping ?
> 
> ----- On 19 Aug, 2019, at 13:45, Clément Leger cleger@kalray.eu wrote:
> 
>> From: Clément Leger <cleger@kalray.eu>
>> 
>> elf32 and elf64 mainly differ by their types. In order to avoid
>> copy/pasting the whole loader code, generate static inline functions
>> which will access values according to the elf class. It allows to keep a
>> common loader basis.
>> In order to accomodate both elf types sizes, the maximum size for a
>> elf header member is chosen using the maximum value of both elf class.
>> 
>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
>> ---
>> drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
>> drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
>> drivers/remoteproc/remoteproc_internal.h   |   2 +-
>> drivers/remoteproc/st_remoteproc.c         |   2 +-
>> include/linux/remoteproc.h                 |   4 +-
>> 5 files changed, 156 insertions(+), 56 deletions(-)
>> create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
>> 
>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
>> b/drivers/remoteproc/remoteproc_elf_loader.c
>> index b17d72ec8603..6a2d31d6092c 100644
>> --- a/drivers/remoteproc/remoteproc_elf_loader.c
>> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
>> @@ -31,6 +31,7 @@
>> #include <linux/elf.h>
>> 
>> #include "remoteproc_internal.h"
>> +#include "remoteproc_elf_loader.h"
>> 
>> /**
>>  * rproc_elf_sanity_check() - Sanity Check ELF firmware image
>> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> firmware *fw)
>> {
>> 	const char *name = rproc->firmware;
>> 	struct device *dev = &rproc->dev;
>> +	/*
>> +	 * Elf files are beginning with the same structure. Thus, to simplify
>> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
>> +	 * elf32.
>> +	 */
>> 	struct elf32_hdr *ehdr;
>> +	u32 elf_shdr_size;
>> +	u64 phoff, shoff;
>> 	char class;
>> +	u16 phnum;
>> 
>> 	if (!fw) {
>> 		dev_err(dev, "failed to load %s\n", name);
>> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> firmware *fw)
>> 
>> 	ehdr = (struct elf32_hdr *)fw->data;
>> 
>> -	/* We only support ELF32 at this point */
>> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> +		dev_err(dev, "Image is corrupted (bad magic)\n");
>> +		return -EINVAL;
>> +	}
>> +
>> 	class = ehdr->e_ident[EI_CLASS];
>> -	if (class != ELFCLASS32) {
>> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
>> 		dev_err(dev, "Unsupported class: %d\n", class);
>> 		return -EINVAL;
>> 	}
>> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> firmware *fw)
>> 		return -EINVAL;
>> 	}
>> 
>> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
>> -		dev_err(dev, "Image is too small\n");
>> -		return -EINVAL;
>> -	}
>> +	phoff = elf_hdr_e_phoff(class, fw->data);
>> +	shoff = elf_hdr_e_shoff(class, fw->data);
>> +	phnum =  elf_hdr_e_phnum(class, fw->data);
>> +	elf_shdr_size = elf_size_of_shdr(class);
>> 
>> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> -		dev_err(dev, "Image is corrupted (bad magic)\n");
>> +	if (fw->size < shoff + elf_shdr_size) {
>> +		dev_err(dev, "Image is too small\n");
>> 		return -EINVAL;
>> 	}
>> 
>> -	if (ehdr->e_phnum == 0) {
>> +	if (phnum == 0) {
>> 		dev_err(dev, "No loadable segments\n");
>> 		return -EINVAL;
>> 	}
>> 
>> -	if (ehdr->e_phoff > fw->size) {
>> +	if (phoff > fw->size) {
>> 		dev_err(dev, "Firmware size is too small\n");
>> 		return -EINVAL;
>> 	}
>> 
>> +	dev_dbg(dev, "Firmware is an elf%d file\n",
>> +		class == ELFCLASS32 ? 32 : 64);
>> +
>> 	return 0;
>> }
>> EXPORT_SYMBOL(rproc_elf_sanity_check);
>> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>>  * Note that the boot address is not a configurable property of all remote
>>  * processors. Some will always boot at a specific hard-coded address.
>>  */
>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> {
>> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
>> -
>> -	return ehdr->e_entry;
>> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
>> }
>> EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>> 
>> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>> int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>> {
>> 	struct device *dev = &rproc->dev;
>> -	struct elf32_hdr *ehdr;
>> -	struct elf32_phdr *phdr;
>> +	const void *ehdr, *phdr;
>> 	int i, ret = 0;
>> +	u16 phnum;
>> 	const u8 *elf_data = fw->data;
>> +	u8 class = fw_elf_get_class(fw);
>> +	u32 elf_phdr_size = elf_size_of_phdr(class);
>> 
>> -	ehdr = (struct elf32_hdr *)elf_data;
>> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
>> +	ehdr = elf_data;
>> +	phnum = elf_hdr_e_phnum(class, ehdr);
>> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
>> 
>> 	/* go through the available ELF segments */
>> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
>> -		u32 da = phdr->p_paddr;
>> -		u32 memsz = phdr->p_memsz;
>> -		u32 filesz = phdr->p_filesz;
>> -		u32 offset = phdr->p_offset;
>> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
>> +		u64 da = elf_phdr_p_paddr(class, phdr);
>> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
>> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
>> +		u64 offset = elf_phdr_p_offset(class, phdr);
>> +		u32 type = elf_phdr_p_type(class, phdr);
>> 		void *ptr;
>> 
>> -		if (phdr->p_type != PT_LOAD)
>> +		if (type != PT_LOAD)
>> 			continue;
>> 
>> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
>> -			phdr->p_type, da, memsz, filesz);
>> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
>> +			type, da, memsz, filesz);
>> 
>> 		if (filesz > memsz) {
>> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
>> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
>> 				filesz, memsz);
>> 			ret = -EINVAL;
>> 			break;
>> 		}
>> 
>> 		if (offset + filesz > fw->size) {
>> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
>> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
>> 				offset + filesz, fw->size);
>> 			ret = -EINVAL;
>> 			break;
>> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> struct firmware *fw)
>> 		/* grab the kernel address for this device address */
>> 		ptr = rproc_da_to_va(rproc, da, memsz);
>> 		if (!ptr) {
>> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
>> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
>> +				memsz);
>> 			ret = -EINVAL;
>> 			break;
>> 		}
>> 
>> 		/* put the segment where the remote processor expects it */
>> -		if (phdr->p_filesz)
>> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
>> +		if (filesz)
>> +			memcpy(ptr, elf_data + offset, filesz);
>> 
>> 		/*
>> 		 * Zero out remaining memory for this segment.
>> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> struct firmware *fw)
>> }
>> EXPORT_SYMBOL(rproc_elf_load_segments);
>> 
>> -static struct elf32_shdr *
>> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>> +static const void *
>> +find_table(struct device *dev, const struct firmware *fw)
>> {
>> -	struct elf32_shdr *shdr;
>> +	const void *shdr, *name_table_shdr;
>> 	int i;
>> 	const char *name_table;
>> 	struct resource_table *table = NULL;
>> -	const u8 *elf_data = (void *)ehdr;
>> +	const u8 *elf_data = (void *)fw->data;
>> +	u8 class = fw_elf_get_class(fw);
>> +	size_t fw_size = fw->size;
>> +	const void *ehdr = elf_data;
>> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
>> +	u32 elf_shdr_size = elf_size_of_shdr(class);
>> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
>> 
>> 	/* look for the resource table and handle it */
>> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
>> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
>> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
>> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
>> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
>> 
>> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
>> -		u32 size = shdr->sh_size;
>> -		u32 offset = shdr->sh_offset;
>> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
>> +		u64 size = elf_shdr_sh_size(class, shdr);
>> +		u64 offset = elf_shdr_sh_offset(class, shdr);
>> +		u32 name = elf_shdr_sh_name(class, shdr);
>> 
>> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
>> +		if (strcmp(name_table + name, ".resource_table"))
>> 			continue;
>> 
>> 		table = (struct resource_table *)(elf_data + offset);
>> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
>> size_t fw_size)
>>  */
>> int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>> {
>> -	struct elf32_hdr *ehdr;
>> -	struct elf32_shdr *shdr;
>> +	const void *shdr;
>> 	struct device *dev = &rproc->dev;
>> 	struct resource_table *table = NULL;
>> 	const u8 *elf_data = fw->data;
>> 	size_t tablesz;
>> +	u8 class = fw_elf_get_class(fw);
>> +	u64 sh_offset;
>> 
>> -	ehdr = (struct elf32_hdr *)elf_data;
>> -
>> -	shdr = find_table(dev, ehdr, fw->size);
>> +	shdr = find_table(dev, fw);
>> 	if (!shdr)
>> 		return -EINVAL;
>> 
>> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
>> -	tablesz = shdr->sh_size;
>> +	sh_offset = elf_shdr_sh_offset(class, shdr);
>> +	table = (struct resource_table *)(elf_data + sh_offset);
>> +	tablesz = elf_shdr_sh_size(class, shdr);
>> 
>> 	/*
>> 	 * Create a copy of the resource table. When a virtio device starts
>> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
>> struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>> 						       const struct firmware *fw)
>> {
>> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> -	struct elf32_shdr *shdr;
>> +	const void *shdr;
>> +	u64 sh_addr, sh_size;
>> +	u8 class = fw_elf_get_class(fw);
>> 
>> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
>> +	shdr = find_table(&rproc->dev, fw);
>> 	if (!shdr)
>> 		return NULL;
>> 
>> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
>> +	sh_addr = elf_shdr_sh_addr(class, shdr);
>> +	sh_size = elf_shdr_sh_size(class, shdr);
>> +
>> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
>> }
>> EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
>> b/drivers/remoteproc/remoteproc_elf_loader.h
>> new file mode 100644
>> index 000000000000..fac3565734f9
>> --- /dev/null
>> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
>> @@ -0,0 +1,69 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Remote processor elf loader defines
>> + *
>> + * Copyright (C) 2019 Kalray, Inc.
>> + */
>> +
>> +#ifndef REMOTEPROC_ELF_LOADER_H
>> +#define REMOTEPROC_ELF_LOADER_H
>> +
>> +#include <linux/elf.h>
>> +#include <linux/types.h>
>> +
>> +/**
>> + * fw_elf_get_class - Get elf class
>> + * @fw: the ELF firmware image
>> + *
>> + * Note that we use and elf32_hdr to access the class since the start of the
>> + * struct is the same for both elf class
>> + *
>> + * Return: elf class of the firmware
>> + */
>> +static inline u8 fw_elf_get_class(const struct firmware *fw)
>> +{
>> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> +
>> +	return ehdr->e_ident[EI_CLASS];
>> +}
>> +
>> +#define ELF_GET_FIELD(__s, __field, __type) \
>> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
>> +{ \
>> +	if (class == ELFCLASS32) \
>> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
>> +	else \
>> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
>> +}
>> +
>> +ELF_GET_FIELD(hdr, e_entry, u64)
>> +ELF_GET_FIELD(hdr, e_phnum, u16)
>> +ELF_GET_FIELD(hdr, e_shnum, u16)
>> +ELF_GET_FIELD(hdr, e_phoff, u64)
>> +ELF_GET_FIELD(hdr, e_shoff, u64)
>> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
>> +
>> +ELF_GET_FIELD(phdr, p_paddr, u64)
>> +ELF_GET_FIELD(phdr, p_filesz, u64)
>> +ELF_GET_FIELD(phdr, p_memsz, u64)
>> +ELF_GET_FIELD(phdr, p_type, u32)
>> +ELF_GET_FIELD(phdr, p_offset, u64)
>> +
>> +ELF_GET_FIELD(shdr, sh_size, u64)
>> +ELF_GET_FIELD(shdr, sh_offset, u64)
>> +ELF_GET_FIELD(shdr, sh_name, u32)
>> +ELF_GET_FIELD(shdr, sh_addr, u64)
>> +
>> +#define ELF_STRUCT_SIZE(__s) \
>> +static inline unsigned long elf_size_of_##__s(u8 class) \
>> +{ \
>> +	if (class == ELFCLASS32)\
>> +		return sizeof(struct elf32_##__s); \
>> +	else \
>> +		return sizeof(struct elf64_##__s); \
>> +}
>> +
>> +ELF_STRUCT_SIZE(shdr)
>> +ELF_STRUCT_SIZE(phdr)
>> +
>> +#endif /* REMOTEPROC_ELF_LOADER_H */
>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> b/drivers/remoteproc/remoteproc_internal.h
>> index 45ff76a06c72..4ef745e3a1bc 100644
>> --- a/drivers/remoteproc/remoteproc_internal.h
>> +++ b/drivers/remoteproc/remoteproc_internal.h
>> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>> int rproc_trigger_recovery(struct rproc *rproc);
>> 
>> int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>> int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>> struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>> diff --git a/drivers/remoteproc/st_remoteproc.c
>> b/drivers/remoteproc/st_remoteproc.c
>> index 51049d17b1e5..e23abd8a96b0 100644
>> --- a/drivers/remoteproc/st_remoteproc.c
>> +++ b/drivers/remoteproc/st_remoteproc.c
>> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
>> 		}
>> 	}
>> 
>> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
>> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>> 
>> 	return 0;
>> 
>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> index 04d04709f2bd..512de9a2590c 100644
>> --- a/include/linux/remoteproc.h
>> +++ b/include/linux/remoteproc.h
>> @@ -362,7 +362,7 @@ struct rproc_ops {
>> 				struct rproc *rproc, const struct firmware *fw);
>> 	int (*load)(struct rproc *rproc, const struct firmware *fw);
>> 	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
>> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> };
>> 
>> /**
>> @@ -478,7 +478,7 @@ struct rproc {
>> 	int num_traces;
>> 	struct list_head carveouts;
>> 	struct list_head mappings;
>> -	u32 bootaddr;
>> +	u64 bootaddr;
>> 	struct list_head rvdevs;
>> 	struct list_head subdevs;
>> 	struct idr notifyids;
>> --
> > 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v2] remoteproc: Add elf64 support in elf loader
  2019-08-19 11:45 ` [PATCH] rproc: Add elf64 support in elf loader Clement Leger
  2019-09-13 10:58   ` Clément Leger
@ 2019-10-04 18:42   ` Clement Leger
  2020-01-09  9:31     ` Clément Leger
  2020-01-24  0:53     ` Mathieu Poirier
  1 sibling, 2 replies; 76+ messages in thread
From: Clement Leger @ 2019-10-04 18:42 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson
  Cc: linux-remoteproc, linux-kernel, Arnaud POULIQUEN, Loic PALLARDY,
	Clement Leger

elf32 and elf64 mainly differ by their types. In order to avoid
copy/pasting the whole loader code, generate static inline functions
which will access values according to the elf class. It allows to keep a
common loader basis.
In order to accomodate both elf types sizes, the maximum size for a
elf header member is chosen using the maximum value of both elf class.

Signed-off-by: Clement Leger <cleger@kalray.eu>
Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
---
Changes in v2:
 - Add ELF64 support in documentation

---
 Documentation/remoteproc.txt               |   2 +-
 drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
 drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
 drivers/remoteproc/remoteproc_internal.h   |   2 +-
 drivers/remoteproc/st_remoteproc.c         |   2 +-
 include/linux/remoteproc.h                 |   4 +-
 6 files changed, 157 insertions(+), 57 deletions(-)
 create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h

diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
index 77fb03acdbb4..bf4f0c41ec4e 100644
--- a/Documentation/remoteproc.txt
+++ b/Documentation/remoteproc.txt
@@ -230,7 +230,7 @@ in the used rings.
 Binary Firmware Structure
 =========================
 
-At this point remoteproc only supports ELF32 firmware binaries. However,
+At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
 it is quite expected that other platforms/devices which we'd want to
 support with this framework will be based on different binary formats.
 
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index b17d72ec8603..6a2d31d6092c 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -31,6 +31,7 @@
 #include <linux/elf.h>
 
 #include "remoteproc_internal.h"
+#include "remoteproc_elf_loader.h"
 
 /**
  * rproc_elf_sanity_check() - Sanity Check ELF firmware image
@@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 {
 	const char *name = rproc->firmware;
 	struct device *dev = &rproc->dev;
+	/*
+	 * Elf files are beginning with the same structure. Thus, to simplify
+	 * header parsing, we can use the elf32_hdr one for both elf64 and
+	 * elf32.
+	 */
 	struct elf32_hdr *ehdr;
+	u32 elf_shdr_size;
+	u64 phoff, shoff;
 	char class;
+	u16 phnum;
 
 	if (!fw) {
 		dev_err(dev, "failed to load %s\n", name);
@@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 
 	ehdr = (struct elf32_hdr *)fw->data;
 
-	/* We only support ELF32 at this point */
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(dev, "Image is corrupted (bad magic)\n");
+		return -EINVAL;
+	}
+
 	class = ehdr->e_ident[EI_CLASS];
-	if (class != ELFCLASS32) {
+	if (class != ELFCLASS32 && class != ELFCLASS64) {
 		dev_err(dev, "Unsupported class: %d\n", class);
 		return -EINVAL;
 	}
@@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 		return -EINVAL;
 	}
 
-	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
-		dev_err(dev, "Image is too small\n");
-		return -EINVAL;
-	}
+	phoff = elf_hdr_e_phoff(class, fw->data);
+	shoff = elf_hdr_e_shoff(class, fw->data);
+	phnum =  elf_hdr_e_phnum(class, fw->data);
+	elf_shdr_size = elf_size_of_shdr(class);
 
-	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(dev, "Image is corrupted (bad magic)\n");
+	if (fw->size < shoff + elf_shdr_size) {
+		dev_err(dev, "Image is too small\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phnum == 0) {
+	if (phnum == 0) {
 		dev_err(dev, "No loadable segments\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phoff > fw->size) {
+	if (phoff > fw->size) {
 		dev_err(dev, "Firmware size is too small\n");
 		return -EINVAL;
 	}
 
+	dev_dbg(dev, "Firmware is an elf%d file\n",
+		class == ELFCLASS32 ? 32 : 64);
+
 	return 0;
 }
 EXPORT_SYMBOL(rproc_elf_sanity_check);
@@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
  * Note that the boot address is not a configurable property of all remote
  * processors. Some will always boot at a specific hard-coded address.
  */
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
-
-	return ehdr->e_entry;
+	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
 }
 EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 
@@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 {
 	struct device *dev = &rproc->dev;
-	struct elf32_hdr *ehdr;
-	struct elf32_phdr *phdr;
+	const void *ehdr, *phdr;
 	int i, ret = 0;
+	u16 phnum;
 	const u8 *elf_data = fw->data;
+	u8 class = fw_elf_get_class(fw);
+	u32 elf_phdr_size = elf_size_of_phdr(class);
 
-	ehdr = (struct elf32_hdr *)elf_data;
-	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+	ehdr = elf_data;
+	phnum = elf_hdr_e_phnum(class, ehdr);
+	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
 
 	/* go through the available ELF segments */
-	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-		u32 da = phdr->p_paddr;
-		u32 memsz = phdr->p_memsz;
-		u32 filesz = phdr->p_filesz;
-		u32 offset = phdr->p_offset;
+	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
+		u64 da = elf_phdr_p_paddr(class, phdr);
+		u64 memsz = elf_phdr_p_memsz(class, phdr);
+		u64 filesz = elf_phdr_p_filesz(class, phdr);
+		u64 offset = elf_phdr_p_offset(class, phdr);
+		u32 type = elf_phdr_p_type(class, phdr);
 		void *ptr;
 
-		if (phdr->p_type != PT_LOAD)
+		if (type != PT_LOAD)
 			continue;
 
-		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-			phdr->p_type, da, memsz, filesz);
+		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
+			type, da, memsz, filesz);
 
 		if (filesz > memsz) {
-			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
 				filesz, memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		if (offset + filesz > fw->size) {
-			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
+			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
 				offset + filesz, fw->size);
 			ret = -EINVAL;
 			break;
@@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 		/* grab the kernel address for this device address */
 		ptr = rproc_da_to_va(rproc, da, memsz);
 		if (!ptr) {
-			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
+				memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		/* put the segment where the remote processor expects it */
-		if (phdr->p_filesz)
-			memcpy(ptr, elf_data + phdr->p_offset, filesz);
+		if (filesz)
+			memcpy(ptr, elf_data + offset, filesz);
 
 		/*
 		 * Zero out remaining memory for this segment.
@@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 }
 EXPORT_SYMBOL(rproc_elf_load_segments);
 
-static struct elf32_shdr *
-find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
+static const void *
+find_table(struct device *dev, const struct firmware *fw)
 {
-	struct elf32_shdr *shdr;
+	const void *shdr, *name_table_shdr;
 	int i;
 	const char *name_table;
 	struct resource_table *table = NULL;
-	const u8 *elf_data = (void *)ehdr;
+	const u8 *elf_data = (void *)fw->data;
+	u8 class = fw_elf_get_class(fw);
+	size_t fw_size = fw->size;
+	const void *ehdr = elf_data;
+	u16 shnum = elf_hdr_e_shnum(class, ehdr);
+	u32 elf_shdr_size = elf_size_of_shdr(class);
+	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
 
 	/* look for the resource table and handle it */
-	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
-	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
+	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
+	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
+	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
 
-	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
-		u32 size = shdr->sh_size;
-		u32 offset = shdr->sh_offset;
+	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
+		u64 size = elf_shdr_sh_size(class, shdr);
+		u64 offset = elf_shdr_sh_offset(class, shdr);
+		u32 name = elf_shdr_sh_name(class, shdr);
 
-		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+		if (strcmp(name_table + name, ".resource_table"))
 			continue;
 
 		table = (struct resource_table *)(elf_data + offset);
@@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
  */
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr;
-	struct elf32_shdr *shdr;
+	const void *shdr;
 	struct device *dev = &rproc->dev;
 	struct resource_table *table = NULL;
 	const u8 *elf_data = fw->data;
 	size_t tablesz;
+	u8 class = fw_elf_get_class(fw);
+	u64 sh_offset;
 
-	ehdr = (struct elf32_hdr *)elf_data;
-
-	shdr = find_table(dev, ehdr, fw->size);
+	shdr = find_table(dev, fw);
 	if (!shdr)
 		return -EINVAL;
 
-	table = (struct resource_table *)(elf_data + shdr->sh_offset);
-	tablesz = shdr->sh_size;
+	sh_offset = elf_shdr_sh_offset(class, shdr);
+	table = (struct resource_table *)(elf_data + sh_offset);
+	tablesz = elf_shdr_sh_size(class, shdr);
 
 	/*
 	 * Create a copy of the resource table. When a virtio device starts
@@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 						       const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
-	struct elf32_shdr *shdr;
+	const void *shdr;
+	u64 sh_addr, sh_size;
+	u8 class = fw_elf_get_class(fw);
 
-	shdr = find_table(&rproc->dev, ehdr, fw->size);
+	shdr = find_table(&rproc->dev, fw);
 	if (!shdr)
 		return NULL;
 
-	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
+	sh_addr = elf_shdr_sh_addr(class, shdr);
+	sh_size = elf_shdr_sh_size(class, shdr);
+
+	return rproc_da_to_va(rproc, sh_addr, sh_size);
 }
 EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
diff --git a/drivers/remoteproc/remoteproc_elf_loader.h b/drivers/remoteproc/remoteproc_elf_loader.h
new file mode 100644
index 000000000000..fac3565734f9
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_elf_loader.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Remote processor elf loader defines
+ *
+ * Copyright (C) 2019 Kalray, Inc.
+ */
+
+#ifndef REMOTEPROC_ELF_LOADER_H
+#define REMOTEPROC_ELF_LOADER_H
+
+#include <linux/elf.h>
+#include <linux/types.h>
+
+/**
+ * fw_elf_get_class - Get elf class
+ * @fw: the ELF firmware image
+ *
+ * Note that we use and elf32_hdr to access the class since the start of the
+ * struct is the same for both elf class
+ *
+ * Return: elf class of the firmware
+ */
+static inline u8 fw_elf_get_class(const struct firmware *fw)
+{
+	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
+
+	return ehdr->e_ident[EI_CLASS];
+}
+
+#define ELF_GET_FIELD(__s, __field, __type) \
+static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
+{ \
+	if (class == ELFCLASS32) \
+		return (__type) ((const struct elf32_##__s *) arg)->__field; \
+	else \
+		return (__type) ((const struct elf64_##__s *) arg)->__field; \
+}
+
+ELF_GET_FIELD(hdr, e_entry, u64)
+ELF_GET_FIELD(hdr, e_phnum, u16)
+ELF_GET_FIELD(hdr, e_shnum, u16)
+ELF_GET_FIELD(hdr, e_phoff, u64)
+ELF_GET_FIELD(hdr, e_shoff, u64)
+ELF_GET_FIELD(hdr, e_shstrndx, u16)
+
+ELF_GET_FIELD(phdr, p_paddr, u64)
+ELF_GET_FIELD(phdr, p_filesz, u64)
+ELF_GET_FIELD(phdr, p_memsz, u64)
+ELF_GET_FIELD(phdr, p_type, u32)
+ELF_GET_FIELD(phdr, p_offset, u64)
+
+ELF_GET_FIELD(shdr, sh_size, u64)
+ELF_GET_FIELD(shdr, sh_offset, u64)
+ELF_GET_FIELD(shdr, sh_name, u32)
+ELF_GET_FIELD(shdr, sh_addr, u64)
+
+#define ELF_STRUCT_SIZE(__s) \
+static inline unsigned long elf_size_of_##__s(u8 class) \
+{ \
+	if (class == ELFCLASS32)\
+		return sizeof(struct elf32_##__s); \
+	else \
+		return sizeof(struct elf64_##__s); \
+}
+
+ELF_STRUCT_SIZE(shdr)
+ELF_STRUCT_SIZE(phdr)
+
+#endif /* REMOTEPROC_ELF_LOADER_H */
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 45ff76a06c72..4ef745e3a1bc 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
 int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index 51049d17b1e5..e23abd8a96b0 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
 		}
 	}
 
-	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
+	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
 
 	return 0;
 
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 04d04709f2bd..512de9a2590c 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -362,7 +362,7 @@ struct rproc_ops {
 				struct rproc *rproc, const struct firmware *fw);
 	int (*load)(struct rproc *rproc, const struct firmware *fw);
 	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
-	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
 };
 
 /**
@@ -478,7 +478,7 @@ struct rproc {
 	int num_traces;
 	struct list_head carveouts;
 	struct list_head mappings;
-	u32 bootaddr;
+	u64 bootaddr;
 	struct list_head rvdevs;
 	struct list_head subdevs;
 	struct idr notifyids;
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [PATCH v2] remoteproc: Add elf64 support in elf loader
  2019-10-04 18:42   ` [PATCH v2] remoteproc: " Clement Leger
@ 2020-01-09  9:31     ` Clément Leger
  2020-01-24  0:53     ` Mathieu Poirier
  1 sibling, 0 replies; 76+ messages in thread
From: Clément Leger @ 2020-01-09  9:31 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson
  Cc: linux-remoteproc, linux-kernel, Arnaud Pouliquen, Loic PALLARDY

Ping ?

----- On 4 Oct, 2019, at 20:42, Clément Leger cleger@kalray.eu wrote:

> elf32 and elf64 mainly differ by their types. In order to avoid
> copy/pasting the whole loader code, generate static inline functions
> which will access values according to the elf class. It allows to keep a
> common loader basis.
> In order to accomodate both elf types sizes, the maximum size for a
> elf header member is chosen using the maximum value of both elf class.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>
> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
> ---
> Changes in v2:
> - Add ELF64 support in documentation
> 
> ---
> Documentation/remoteproc.txt               |   2 +-
> drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
> drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
> drivers/remoteproc/remoteproc_internal.h   |   2 +-
> drivers/remoteproc/st_remoteproc.c         |   2 +-
> include/linux/remoteproc.h                 |   4 +-
> 6 files changed, 157 insertions(+), 57 deletions(-)
> create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
> 
> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
> index 77fb03acdbb4..bf4f0c41ec4e 100644
> --- a/Documentation/remoteproc.txt
> +++ b/Documentation/remoteproc.txt
> @@ -230,7 +230,7 @@ in the used rings.
> Binary Firmware Structure
> =========================
> 
> -At this point remoteproc only supports ELF32 firmware binaries. However,
> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
> it is quite expected that other platforms/devices which we'd want to
> support with this framework will be based on different binary formats.
> 
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
> b/drivers/remoteproc/remoteproc_elf_loader.c
> index b17d72ec8603..6a2d31d6092c 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -31,6 +31,7 @@
> #include <linux/elf.h>
> 
> #include "remoteproc_internal.h"
> +#include "remoteproc_elf_loader.h"
> 
> /**
>  * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> firmware *fw)
> {
> 	const char *name = rproc->firmware;
> 	struct device *dev = &rproc->dev;
> +	/*
> +	 * Elf files are beginning with the same structure. Thus, to simplify
> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
> +	 * elf32.
> +	 */
> 	struct elf32_hdr *ehdr;
> +	u32 elf_shdr_size;
> +	u64 phoff, shoff;
> 	char class;
> +	u16 phnum;
> 
> 	if (!fw) {
> 		dev_err(dev, "failed to load %s\n", name);
> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> firmware *fw)
> 
> 	ehdr = (struct elf32_hdr *)fw->data;
> 
> -	/* We only support ELF32 at this point */
> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> +		dev_err(dev, "Image is corrupted (bad magic)\n");
> +		return -EINVAL;
> +	}
> +
> 	class = ehdr->e_ident[EI_CLASS];
> -	if (class != ELFCLASS32) {
> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
> 		dev_err(dev, "Unsupported class: %d\n", class);
> 		return -EINVAL;
> 	}
> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> firmware *fw)
> 		return -EINVAL;
> 	}
> 
> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
> -		dev_err(dev, "Image is too small\n");
> -		return -EINVAL;
> -	}
> +	phoff = elf_hdr_e_phoff(class, fw->data);
> +	shoff = elf_hdr_e_shoff(class, fw->data);
> +	phnum =  elf_hdr_e_phnum(class, fw->data);
> +	elf_shdr_size = elf_size_of_shdr(class);
> 
> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> -		dev_err(dev, "Image is corrupted (bad magic)\n");
> +	if (fw->size < shoff + elf_shdr_size) {
> +		dev_err(dev, "Image is too small\n");
> 		return -EINVAL;
> 	}
> 
> -	if (ehdr->e_phnum == 0) {
> +	if (phnum == 0) {
> 		dev_err(dev, "No loadable segments\n");
> 		return -EINVAL;
> 	}
> 
> -	if (ehdr->e_phoff > fw->size) {
> +	if (phoff > fw->size) {
> 		dev_err(dev, "Firmware size is too small\n");
> 		return -EINVAL;
> 	}
> 
> +	dev_dbg(dev, "Firmware is an elf%d file\n",
> +		class == ELFCLASS32 ? 32 : 64);
> +
> 	return 0;
> }
> EXPORT_SYMBOL(rproc_elf_sanity_check);
> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>  * Note that the boot address is not a configurable property of all remote
>  * processors. Some will always boot at a specific hard-coded address.
>  */
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> {
> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
> -
> -	return ehdr->e_entry;
> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
> }
> EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> 
> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
> {
> 	struct device *dev = &rproc->dev;
> -	struct elf32_hdr *ehdr;
> -	struct elf32_phdr *phdr;
> +	const void *ehdr, *phdr;
> 	int i, ret = 0;
> +	u16 phnum;
> 	const u8 *elf_data = fw->data;
> +	u8 class = fw_elf_get_class(fw);
> +	u32 elf_phdr_size = elf_size_of_phdr(class);
> 
> -	ehdr = (struct elf32_hdr *)elf_data;
> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> +	ehdr = elf_data;
> +	phnum = elf_hdr_e_phnum(class, ehdr);
> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
> 
> 	/* go through the available ELF segments */
> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> -		u32 da = phdr->p_paddr;
> -		u32 memsz = phdr->p_memsz;
> -		u32 filesz = phdr->p_filesz;
> -		u32 offset = phdr->p_offset;
> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
> +		u64 da = elf_phdr_p_paddr(class, phdr);
> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
> +		u64 offset = elf_phdr_p_offset(class, phdr);
> +		u32 type = elf_phdr_p_type(class, phdr);
> 		void *ptr;
> 
> -		if (phdr->p_type != PT_LOAD)
> +		if (type != PT_LOAD)
> 			continue;
> 
> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
> -			phdr->p_type, da, memsz, filesz);
> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
> +			type, da, memsz, filesz);
> 
> 		if (filesz > memsz) {
> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
> 				filesz, memsz);
> 			ret = -EINVAL;
> 			break;
> 		}
> 
> 		if (offset + filesz > fw->size) {
> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
> 				offset + filesz, fw->size);
> 			ret = -EINVAL;
> 			break;
> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> struct firmware *fw)
> 		/* grab the kernel address for this device address */
> 		ptr = rproc_da_to_va(rproc, da, memsz);
> 		if (!ptr) {
> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
> +				memsz);
> 			ret = -EINVAL;
> 			break;
> 		}
> 
> 		/* put the segment where the remote processor expects it */
> -		if (phdr->p_filesz)
> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
> +		if (filesz)
> +			memcpy(ptr, elf_data + offset, filesz);
> 
> 		/*
> 		 * Zero out remaining memory for this segment.
> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> struct firmware *fw)
> }
> EXPORT_SYMBOL(rproc_elf_load_segments);
> 
> -static struct elf32_shdr *
> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> +static const void *
> +find_table(struct device *dev, const struct firmware *fw)
> {
> -	struct elf32_shdr *shdr;
> +	const void *shdr, *name_table_shdr;
> 	int i;
> 	const char *name_table;
> 	struct resource_table *table = NULL;
> -	const u8 *elf_data = (void *)ehdr;
> +	const u8 *elf_data = (void *)fw->data;
> +	u8 class = fw_elf_get_class(fw);
> +	size_t fw_size = fw->size;
> +	const void *ehdr = elf_data;
> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
> +	u32 elf_shdr_size = elf_size_of_shdr(class);
> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
> 
> 	/* look for the resource table and handle it */
> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
> 
> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> -		u32 size = shdr->sh_size;
> -		u32 offset = shdr->sh_offset;
> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
> +		u64 size = elf_shdr_sh_size(class, shdr);
> +		u64 offset = elf_shdr_sh_offset(class, shdr);
> +		u32 name = elf_shdr_sh_name(class, shdr);
> 
> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
> +		if (strcmp(name_table + name, ".resource_table"))
> 			continue;
> 
> 		table = (struct resource_table *)(elf_data + offset);
> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
> size_t fw_size)
>  */
> int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
> {
> -	struct elf32_hdr *ehdr;
> -	struct elf32_shdr *shdr;
> +	const void *shdr;
> 	struct device *dev = &rproc->dev;
> 	struct resource_table *table = NULL;
> 	const u8 *elf_data = fw->data;
> 	size_t tablesz;
> +	u8 class = fw_elf_get_class(fw);
> +	u64 sh_offset;
> 
> -	ehdr = (struct elf32_hdr *)elf_data;
> -
> -	shdr = find_table(dev, ehdr, fw->size);
> +	shdr = find_table(dev, fw);
> 	if (!shdr)
> 		return -EINVAL;
> 
> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
> -	tablesz = shdr->sh_size;
> +	sh_offset = elf_shdr_sh_offset(class, shdr);
> +	table = (struct resource_table *)(elf_data + sh_offset);
> +	tablesz = elf_shdr_sh_size(class, shdr);
> 
> 	/*
> 	 * Create a copy of the resource table. When a virtio device starts
> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
> struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> 						       const struct firmware *fw)
> {
> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> -	struct elf32_shdr *shdr;
> +	const void *shdr;
> +	u64 sh_addr, sh_size;
> +	u8 class = fw_elf_get_class(fw);
> 
> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
> +	shdr = find_table(&rproc->dev, fw);
> 	if (!shdr)
> 		return NULL;
> 
> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
> +	sh_addr = elf_shdr_sh_addr(class, shdr);
> +	sh_size = elf_shdr_sh_size(class, shdr);
> +
> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
> }
> EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
> b/drivers/remoteproc/remoteproc_elf_loader.h
> new file mode 100644
> index 000000000000..fac3565734f9
> --- /dev/null
> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
> @@ -0,0 +1,69 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Remote processor elf loader defines
> + *
> + * Copyright (C) 2019 Kalray, Inc.
> + */
> +
> +#ifndef REMOTEPROC_ELF_LOADER_H
> +#define REMOTEPROC_ELF_LOADER_H
> +
> +#include <linux/elf.h>
> +#include <linux/types.h>
> +
> +/**
> + * fw_elf_get_class - Get elf class
> + * @fw: the ELF firmware image
> + *
> + * Note that we use and elf32_hdr to access the class since the start of the
> + * struct is the same for both elf class
> + *
> + * Return: elf class of the firmware
> + */
> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> +{
> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> +
> +	return ehdr->e_ident[EI_CLASS];
> +}
> +
> +#define ELF_GET_FIELD(__s, __field, __type) \
> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
> +{ \
> +	if (class == ELFCLASS32) \
> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
> +	else \
> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
> +}
> +
> +ELF_GET_FIELD(hdr, e_entry, u64)
> +ELF_GET_FIELD(hdr, e_phnum, u16)
> +ELF_GET_FIELD(hdr, e_shnum, u16)
> +ELF_GET_FIELD(hdr, e_phoff, u64)
> +ELF_GET_FIELD(hdr, e_shoff, u64)
> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
> +
> +ELF_GET_FIELD(phdr, p_paddr, u64)
> +ELF_GET_FIELD(phdr, p_filesz, u64)
> +ELF_GET_FIELD(phdr, p_memsz, u64)
> +ELF_GET_FIELD(phdr, p_type, u32)
> +ELF_GET_FIELD(phdr, p_offset, u64)
> +
> +ELF_GET_FIELD(shdr, sh_size, u64)
> +ELF_GET_FIELD(shdr, sh_offset, u64)
> +ELF_GET_FIELD(shdr, sh_name, u32)
> +ELF_GET_FIELD(shdr, sh_addr, u64)
> +
> +#define ELF_STRUCT_SIZE(__s) \
> +static inline unsigned long elf_size_of_##__s(u8 class) \
> +{ \
> +	if (class == ELFCLASS32)\
> +		return sizeof(struct elf32_##__s); \
> +	else \
> +		return sizeof(struct elf64_##__s); \
> +}
> +
> +ELF_STRUCT_SIZE(shdr)
> +ELF_STRUCT_SIZE(phdr)
> +
> +#endif /* REMOTEPROC_ELF_LOADER_H */
> diff --git a/drivers/remoteproc/remoteproc_internal.h
> b/drivers/remoteproc/remoteproc_internal.h
> index 45ff76a06c72..4ef745e3a1bc 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
> int rproc_trigger_recovery(struct rproc *rproc);
> 
> int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
> int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
> struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> diff --git a/drivers/remoteproc/st_remoteproc.c
> b/drivers/remoteproc/st_remoteproc.c
> index 51049d17b1e5..e23abd8a96b0 100644
> --- a/drivers/remoteproc/st_remoteproc.c
> +++ b/drivers/remoteproc/st_remoteproc.c
> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
> 		}
> 	}
> 
> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
> 
> 	return 0;
> 
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 04d04709f2bd..512de9a2590c 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -362,7 +362,7 @@ struct rproc_ops {
> 				struct rproc *rproc, const struct firmware *fw);
> 	int (*load)(struct rproc *rproc, const struct firmware *fw);
> 	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> };
> 
> /**
> @@ -478,7 +478,7 @@ struct rproc {
> 	int num_traces;
> 	struct list_head carveouts;
> 	struct list_head mappings;
> -	u32 bootaddr;
> +	u64 bootaddr;
> 	struct list_head rvdevs;
> 	struct list_head subdevs;
> 	struct idr notifyids;
> --
> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v2] remoteproc: Add elf64 support in elf loader
  2019-10-04 18:42   ` [PATCH v2] remoteproc: " Clement Leger
  2020-01-09  9:31     ` Clément Leger
@ 2020-01-24  0:53     ` Mathieu Poirier
  2020-01-24  8:24       ` Clément Leger
  1 sibling, 1 reply; 76+ messages in thread
From: Mathieu Poirier @ 2020-01-24  0:53 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel,
	Arnaud POULIQUEN, Loic PALLARDY

Hi Clement,

On Fri, Oct 04, 2019 at 08:42:20PM +0200, Clement Leger wrote:
> elf32 and elf64 mainly differ by their types. In order to avoid
> copy/pasting the whole loader code, generate static inline functions
> which will access values according to the elf class. It allows to keep a
> common loader basis.
> In order to accomodate both elf types sizes, the maximum size for a
> elf header member is chosen using the maximum value of both elf class.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>
> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
> ---
> Changes in v2:
>  - Add ELF64 support in documentation
>

First and foremost please address the complaints from checkpatch.
 
> ---
>  Documentation/remoteproc.txt               |   2 +-
>  drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
>  drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
>  drivers/remoteproc/st_remoteproc.c         |   2 +-
>  include/linux/remoteproc.h                 |   4 +-
>  6 files changed, 157 insertions(+), 57 deletions(-)
>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
> 
> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
> index 77fb03acdbb4..bf4f0c41ec4e 100644
> --- a/Documentation/remoteproc.txt
> +++ b/Documentation/remoteproc.txt
> @@ -230,7 +230,7 @@ in the used rings.
>  Binary Firmware Structure
>  =========================
>  
> -At this point remoteproc only supports ELF32 firmware binaries. However,
> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
>  it is quite expected that other platforms/devices which we'd want to
>  support with this framework will be based on different binary formats.
>  
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index b17d72ec8603..6a2d31d6092c 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -31,6 +31,7 @@
>  #include <linux/elf.h>
>  
>  #include "remoteproc_internal.h"
> +#include "remoteproc_elf_loader.h"
>  
>  /**
>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
>  {
>  	const char *name = rproc->firmware;
>  	struct device *dev = &rproc->dev;
> +	/*
> +	 * Elf files are beginning with the same structure. Thus, to simplify
> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
> +	 * elf32.
> +	 */
>  	struct elf32_hdr *ehdr;
> +	u32 elf_shdr_size;
> +	u64 phoff, shoff;
>  	char class;
> +	u16 phnum;
>  
>  	if (!fw) {
>  		dev_err(dev, "failed to load %s\n", name);
> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)

In the current code [1] fw->size is compared against the size of an elf32_hdr.
If support for elf64 is added that code needs to be modified to check for the
right header size using fw_elf_get_class().

[1] https://elixir.bootlin.com/linux/v5.5-rc6/source/drivers/remoteproc/remoteproc_elf_loader.c#L46

>  
>  	ehdr = (struct elf32_hdr *)fw->data;
>  
> -	/* We only support ELF32 at this point */
> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> +		dev_err(dev, "Image is corrupted (bad magic)\n");
> +		return -EINVAL;
> +	}
> +

Is there a reason to move this check up where?  If not please bring it back to
its original location, that is below:

 "if (fw->size < ehdr->e_shoff + sizeof(structelf32_shdr))"

>  	class = ehdr->e_ident[EI_CLASS];
> -	if (class != ELFCLASS32) {
> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
>  		dev_err(dev, "Unsupported class: %d\n", class);
>  		return -EINVAL;
>  	}
> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
>  		return -EINVAL;
>  	}
>  
> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
> -		dev_err(dev, "Image is too small\n");
> -		return -EINVAL;
> -	}
> +	phoff = elf_hdr_e_phoff(class, fw->data);
> +	shoff = elf_hdr_e_shoff(class, fw->data);
> +	phnum =  elf_hdr_e_phnum(class, fw->data);
> +	elf_shdr_size = elf_size_of_shdr(class);
>  
> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> -		dev_err(dev, "Image is corrupted (bad magic)\n");
> +	if (fw->size < shoff + elf_shdr_size) {
> +		dev_err(dev, "Image is too small\n");
>  		return -EINVAL;
>  	}
>  
> -	if (ehdr->e_phnum == 0) {
> +	if (phnum == 0) {
>  		dev_err(dev, "No loadable segments\n");
>  		return -EINVAL;
>  	}
>  
> -	if (ehdr->e_phoff > fw->size) {
> +	if (phoff > fw->size) {
>  		dev_err(dev, "Firmware size is too small\n");
>  		return -EINVAL;
>  	}
>  
> +	dev_dbg(dev, "Firmware is an elf%d file\n",
> +		class == ELFCLASS32 ? 32 : 64);
> +

Yes, this is useful.

>  	return 0;
>  }
>  EXPORT_SYMBOL(rproc_elf_sanity_check);
> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>   * Note that the boot address is not a configurable property of all remote
>   * processors. Some will always boot at a specific hard-coded address.
>   */
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>  {
> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
> -
> -	return ehdr->e_entry;
> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
>  }
>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>  
> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  {
>  	struct device *dev = &rproc->dev;
> -	struct elf32_hdr *ehdr;
> -	struct elf32_phdr *phdr;
> +	const void *ehdr, *phdr;
>  	int i, ret = 0;
> +	u16 phnum;
>  	const u8 *elf_data = fw->data;
> +	u8 class = fw_elf_get_class(fw);
> +	u32 elf_phdr_size = elf_size_of_phdr(class);
>  
> -	ehdr = (struct elf32_hdr *)elf_data;
> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> +	ehdr = elf_data;
> +	phnum = elf_hdr_e_phnum(class, ehdr);
> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
>  
>  	/* go through the available ELF segments */
> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> -		u32 da = phdr->p_paddr;
> -		u32 memsz = phdr->p_memsz;
> -		u32 filesz = phdr->p_filesz;
> -		u32 offset = phdr->p_offset;
> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
> +		u64 da = elf_phdr_p_paddr(class, phdr);
> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
> +		u64 offset = elf_phdr_p_offset(class, phdr);
> +		u32 type = elf_phdr_p_type(class, phdr);
>  		void *ptr;
>  
> -		if (phdr->p_type != PT_LOAD)
> +		if (type != PT_LOAD)
>  			continue;
>  
> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
> -			phdr->p_type, da, memsz, filesz);
> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
> +			type, da, memsz, filesz);
>  
>  		if (filesz > memsz) {
> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
>  				filesz, memsz);
>  			ret = -EINVAL;
>  			break;
>  		}
>  
>  		if (offset + filesz > fw->size) {
> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
>  				offset + filesz, fw->size);
>  			ret = -EINVAL;
>  			break;
> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  		/* grab the kernel address for this device address */
>  		ptr = rproc_da_to_va(rproc, da, memsz);
>  		if (!ptr) {
> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
> +				memsz);
>  			ret = -EINVAL;
>  			break;
>  		}
>  
>  		/* put the segment where the remote processor expects it */
> -		if (phdr->p_filesz)
> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
> +		if (filesz)
> +			memcpy(ptr, elf_data + offset, filesz);
>  
>  		/*
>  		 * Zero out remaining memory for this segment.
> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  }
>  EXPORT_SYMBOL(rproc_elf_load_segments);
>  
> -static struct elf32_shdr *
> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> +static const void *

Not sure I understand the "const" - was the compiler complaining?

> +find_table(struct device *dev, const struct firmware *fw)
>  {
> -	struct elf32_shdr *shdr;
> +	const void *shdr, *name_table_shdr;
>  	int i;
>  	const char *name_table;
>  	struct resource_table *table = NULL;
> -	const u8 *elf_data = (void *)ehdr;
> +	const u8 *elf_data = (void *)fw->data;
> +	u8 class = fw_elf_get_class(fw);
> +	size_t fw_size = fw->size;
> +	const void *ehdr = elf_data;
> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
> +	u32 elf_shdr_size = elf_size_of_shdr(class);
> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
>  
>  	/* look for the resource table and handle it */
> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);

It took me a while but I figured out what is happening here.  To save me (and
other people) from going through the same mental process every time I look at
this code, please add a comment for each of the above 3 lines. 

>  
> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> -		u32 size = shdr->sh_size;
> -		u32 offset = shdr->sh_offset;
> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
> +		u64 size = elf_shdr_sh_size(class, shdr);
> +		u64 offset = elf_shdr_sh_offset(class, shdr);
> +		u32 name = elf_shdr_sh_name(class, shdr);
>  
> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
> +		if (strcmp(name_table + name, ".resource_table"))
>  			continue;
>  
>  		table = (struct resource_table *)(elf_data + offset);
> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>   */
>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>  {
> -	struct elf32_hdr *ehdr;
> -	struct elf32_shdr *shdr;
> +	const void *shdr;
>  	struct device *dev = &rproc->dev;
>  	struct resource_table *table = NULL;
>  	const u8 *elf_data = fw->data;
>  	size_t tablesz;
> +	u8 class = fw_elf_get_class(fw);
> +	u64 sh_offset;
>  
> -	ehdr = (struct elf32_hdr *)elf_data;
> -
> -	shdr = find_table(dev, ehdr, fw->size);
> +	shdr = find_table(dev, fw);
>  	if (!shdr)
>  		return -EINVAL;
>  
> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
> -	tablesz = shdr->sh_size;
> +	sh_offset = elf_shdr_sh_offset(class, shdr);
> +	table = (struct resource_table *)(elf_data + sh_offset);
> +	tablesz = elf_shdr_sh_size(class, shdr);
>  
>  	/*
>  	 * Create a copy of the resource table. When a virtio device starts
> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>  						       const struct firmware *fw)
>  {
> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> -	struct elf32_shdr *shdr;
> +	const void *shdr;
> +	u64 sh_addr, sh_size;
> +	u8 class = fw_elf_get_class(fw);
>  
> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
> +	shdr = find_table(&rproc->dev, fw);
>  	if (!shdr)
>  		return NULL;
>  
> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
> +	sh_addr = elf_shdr_sh_addr(class, shdr);
> +	sh_size = elf_shdr_sh_size(class, shdr);
> +
> +	return rproc_da_to_va(rproc, sh_addr, sh_size);

The prototype for the above is as follow:

void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)

But sh_size is a u64, which will cause problem that are hard to debug.  I think
it is better to move 'len' to an 8 byte type along with the refactoring of the
existing code that is implied.  I suggest to split this work in a preparatory
patch (that will still be part of this set).  

>  }
>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h b/drivers/remoteproc/remoteproc_elf_loader.h
> new file mode 100644
> index 000000000000..fac3565734f9
> --- /dev/null
> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
> @@ -0,0 +1,69 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Remote processor elf loader defines
> + *
> + * Copyright (C) 2019 Kalray, Inc.
> + */
> +
> +#ifndef REMOTEPROC_ELF_LOADER_H
> +#define REMOTEPROC_ELF_LOADER_H
> +
> +#include <linux/elf.h>
> +#include <linux/types.h>
> +
> +/**
> + * fw_elf_get_class - Get elf class
> + * @fw: the ELF firmware image
> + *
> + * Note that we use and elf32_hdr to access the class since the start of the
> + * struct is the same for both elf class
> + *
> + * Return: elf class of the firmware
> + */
> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> +{
> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> +
> +	return ehdr->e_ident[EI_CLASS];
> +}
> +
> +#define ELF_GET_FIELD(__s, __field, __type) \
> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
> +{ \
> +	if (class == ELFCLASS32) \
> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
> +	else \
> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
> +}
> +
> +ELF_GET_FIELD(hdr, e_entry, u64)
> +ELF_GET_FIELD(hdr, e_phnum, u16)
> +ELF_GET_FIELD(hdr, e_shnum, u16)
> +ELF_GET_FIELD(hdr, e_phoff, u64)
> +ELF_GET_FIELD(hdr, e_shoff, u64)
> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
> +
> +ELF_GET_FIELD(phdr, p_paddr, u64)
> +ELF_GET_FIELD(phdr, p_filesz, u64)
> +ELF_GET_FIELD(phdr, p_memsz, u64)
> +ELF_GET_FIELD(phdr, p_type, u32)
> +ELF_GET_FIELD(phdr, p_offset, u64)
> +
> +ELF_GET_FIELD(shdr, sh_size, u64)
> +ELF_GET_FIELD(shdr, sh_offset, u64)
> +ELF_GET_FIELD(shdr, sh_name, u32)
> +ELF_GET_FIELD(shdr, sh_addr, u64)

I like how you did this.

> +
> +#define ELF_STRUCT_SIZE(__s) \
> +static inline unsigned long elf_size_of_##__s(u8 class) \
> +{ \
> +	if (class == ELFCLASS32)\
> +		return sizeof(struct elf32_##__s); \
> +	else \
> +		return sizeof(struct elf64_##__s); \
> +}
> +
> +ELF_STRUCT_SIZE(shdr)
> +ELF_STRUCT_SIZE(phdr)
> +
> +#endif /* REMOTEPROC_ELF_LOADER_H */
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 45ff76a06c72..4ef745e3a1bc 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>  int rproc_trigger_recovery(struct rproc *rproc);
>  
>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
> index 51049d17b1e5..e23abd8a96b0 100644
> --- a/drivers/remoteproc/st_remoteproc.c
> +++ b/drivers/remoteproc/st_remoteproc.c
> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
>  		}
>  	}
>  
> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>  
>  	return 0;
>  
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 04d04709f2bd..512de9a2590c 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -362,7 +362,7 @@ struct rproc_ops {
>  				struct rproc *rproc, const struct firmware *fw);
>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>  };
>  
>  /**
> @@ -478,7 +478,7 @@ struct rproc {
>  	int num_traces;
>  	struct list_head carveouts;
>  	struct list_head mappings;
> -	u32 bootaddr;
> +	u64 bootaddr;
>  	struct list_head rvdevs;
>  	struct list_head subdevs;
>  	struct idr notifyids;

Please hold off before doing another respin of this patch.  While doing
something completely different I noticed TI also did some work in this area.
I'd like to take some time to look at their implementation and see if they carry
features that haven't been included here.  I intend to do this tomorrow.

Thanks,
Mathieu 

> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v2] remoteproc: Add elf64 support in elf loader
  2020-01-24  0:53     ` Mathieu Poirier
@ 2020-01-24  8:24       ` Clément Leger
  2020-01-24 18:10         ` Mathieu Poirier
  2020-01-24 21:58         ` Mathieu Poirier
  0 siblings, 2 replies; 76+ messages in thread
From: Clément Leger @ 2020-01-24  8:24 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel,
	Arnaud Pouliquen, Loic PALLARDY

Hi Mathieu,

----- On 24 Jan, 2020, at 01:53, Mathieu Poirier mathieu.poirier@linaro.org wrote:

> Hi Clement,
> 
> On Fri, Oct 04, 2019 at 08:42:20PM +0200, Clement Leger wrote:
>> elf32 and elf64 mainly differ by their types. In order to avoid
>> copy/pasting the whole loader code, generate static inline functions
>> which will access values according to the elf class. It allows to keep a
>> common loader basis.
>> In order to accomodate both elf types sizes, the maximum size for a
>> elf header member is chosen using the maximum value of both elf class.
>> 
>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
>> ---
>> Changes in v2:
>>  - Add ELF64 support in documentation
>>
> 
> First and foremost please address the complaints from checkpatch.

I fixed one typo in accommodate. The other checkpatch complaint is
about missing parenthesis for macros with complex values which is
unfortunately not possible since I'm generating inline functions.

Did you have any other one ?

> 
>> ---
>>  Documentation/remoteproc.txt               |   2 +-
>>  drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
>>  drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
>>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
>>  drivers/remoteproc/st_remoteproc.c         |   2 +-
>>  include/linux/remoteproc.h                 |   4 +-
>>  6 files changed, 157 insertions(+), 57 deletions(-)
>>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
>> 
>> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
>> index 77fb03acdbb4..bf4f0c41ec4e 100644
>> --- a/Documentation/remoteproc.txt
>> +++ b/Documentation/remoteproc.txt
>> @@ -230,7 +230,7 @@ in the used rings.
>>  Binary Firmware Structure
>>  =========================
>>  
>> -At this point remoteproc only supports ELF32 firmware binaries. However,
>> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
>>  it is quite expected that other platforms/devices which we'd want to
>>  support with this framework will be based on different binary formats.
>>  
>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
>> b/drivers/remoteproc/remoteproc_elf_loader.c
>> index b17d72ec8603..6a2d31d6092c 100644
>> --- a/drivers/remoteproc/remoteproc_elf_loader.c
>> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
>> @@ -31,6 +31,7 @@
>>  #include <linux/elf.h>
>>  
>>  #include "remoteproc_internal.h"
>> +#include "remoteproc_elf_loader.h"
>>  
>>  /**
>>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
>> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> firmware *fw)
>>  {
>>  	const char *name = rproc->firmware;
>>  	struct device *dev = &rproc->dev;
>> +	/*
>> +	 * Elf files are beginning with the same structure. Thus, to simplify
>> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
>> +	 * elf32.
>> +	 */
>>  	struct elf32_hdr *ehdr;
>> +	u32 elf_shdr_size;
>> +	u64 phoff, shoff;
>>  	char class;
>> +	u16 phnum;
>>  
>>  	if (!fw) {
>>  		dev_err(dev, "failed to load %s\n", name);
>> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> firmware *fw)
> 
> In the current code [1] fw->size is compared against the size of an elf32_hdr.
> If support for elf64 is added that code needs to be modified to check for the
> right header size using fw_elf_get_class().

Actually, the elf32 header is smaller than the elf64 one so this check is
there to ensure that we have at least a minimal elf header (elf32).
And since the class is derived from the header, you better have to check the
header size before accessing it.

To be more clear, I could compare it to min(sizeof(struct elf32_hdr),
sizeof(struct elf64_hdr)) or add a comment at least stating that since
elf header contains the same fields for identification, we can use the 
elf32 one.

> 
> [1]
> https://elixir.bootlin.com/linux/v5.5-rc6/source/drivers/remoteproc/remoteproc_elf_loader.c#L46
> 
>>  
>>  	ehdr = (struct elf32_hdr *)fw->data;
>>  
>> -	/* We only support ELF32 at this point */
>> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> +		dev_err(dev, "Image is corrupted (bad magic)\n");
>> +		return -EINVAL;
>> +	}
>> +
> 
> Is there a reason to move this check up where?  If not please bring it back to
> its original location, that is below:
> 
> "if (fw->size < ehdr->e_shoff + sizeof(structelf32_shdr))"
> 

This is because the new check for size uses elf_shdr_size which is derived from
the class. And since the class is extracted from the elf header, we need to check
the header to be correct first.

>>  	class = ehdr->e_ident[EI_CLASS];
>> -	if (class != ELFCLASS32) {
>> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
>>  		dev_err(dev, "Unsupported class: %d\n", class);
>>  		return -EINVAL;
>>  	}
>> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> firmware *fw)
>>  		return -EINVAL;
>>  	}
>>  
>> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
>> -		dev_err(dev, "Image is too small\n");
>> -		return -EINVAL;
>> -	}
>> +	phoff = elf_hdr_e_phoff(class, fw->data);
>> +	shoff = elf_hdr_e_shoff(class, fw->data);
>> +	phnum =  elf_hdr_e_phnum(class, fw->data);
>> +	elf_shdr_size = elf_size_of_shdr(class);
>>  
>> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> -		dev_err(dev, "Image is corrupted (bad magic)\n");
>> +	if (fw->size < shoff + elf_shdr_size) {
>> +		dev_err(dev, "Image is too small\n");
>>  		return -EINVAL;
>>  	}
>>  
>> -	if (ehdr->e_phnum == 0) {
>> +	if (phnum == 0) {
>>  		dev_err(dev, "No loadable segments\n");
>>  		return -EINVAL;
>>  	}
>>  
>> -	if (ehdr->e_phoff > fw->size) {
>> +	if (phoff > fw->size) {
>>  		dev_err(dev, "Firmware size is too small\n");
>>  		return -EINVAL;
>>  	}
>>  
>> +	dev_dbg(dev, "Firmware is an elf%d file\n",
>> +		class == ELFCLASS32 ? 32 : 64);
>> +
> 
> Yes, this is useful.
> 
>>  	return 0;
>>  }
>>  EXPORT_SYMBOL(rproc_elf_sanity_check);
>> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>>   * Note that the boot address is not a configurable property of all remote
>>   * processors. Some will always boot at a specific hard-coded address.
>>   */
>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>>  {
>> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
>> -
>> -	return ehdr->e_entry;
>> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
>>  }
>>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>>  
>> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>>  {
>>  	struct device *dev = &rproc->dev;
>> -	struct elf32_hdr *ehdr;
>> -	struct elf32_phdr *phdr;
>> +	const void *ehdr, *phdr;
>>  	int i, ret = 0;
>> +	u16 phnum;
>>  	const u8 *elf_data = fw->data;
>> +	u8 class = fw_elf_get_class(fw);
>> +	u32 elf_phdr_size = elf_size_of_phdr(class);
>>  
>> -	ehdr = (struct elf32_hdr *)elf_data;
>> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
>> +	ehdr = elf_data;
>> +	phnum = elf_hdr_e_phnum(class, ehdr);
>> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
>>  
>>  	/* go through the available ELF segments */
>> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
>> -		u32 da = phdr->p_paddr;
>> -		u32 memsz = phdr->p_memsz;
>> -		u32 filesz = phdr->p_filesz;
>> -		u32 offset = phdr->p_offset;
>> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
>> +		u64 da = elf_phdr_p_paddr(class, phdr);
>> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
>> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
>> +		u64 offset = elf_phdr_p_offset(class, phdr);
>> +		u32 type = elf_phdr_p_type(class, phdr);
>>  		void *ptr;
>>  
>> -		if (phdr->p_type != PT_LOAD)
>> +		if (type != PT_LOAD)
>>  			continue;
>>  
>> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
>> -			phdr->p_type, da, memsz, filesz);
>> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
>> +			type, da, memsz, filesz);
>>  
>>  		if (filesz > memsz) {
>> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
>> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
>>  				filesz, memsz);
>>  			ret = -EINVAL;
>>  			break;
>>  		}
>>  
>>  		if (offset + filesz > fw->size) {
>> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
>> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
>>  				offset + filesz, fw->size);
>>  			ret = -EINVAL;
>>  			break;
>> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> struct firmware *fw)
>>  		/* grab the kernel address for this device address */
>>  		ptr = rproc_da_to_va(rproc, da, memsz);
>>  		if (!ptr) {
>> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
>> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
>> +				memsz);
>>  			ret = -EINVAL;
>>  			break;
>>  		}
>>  
>>  		/* put the segment where the remote processor expects it */
>> -		if (phdr->p_filesz)
>> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
>> +		if (filesz)
>> +			memcpy(ptr, elf_data + offset, filesz);
>>  
>>  		/*
>>  		 * Zero out remaining memory for this segment.
>> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> struct firmware *fw)
>>  }
>>  EXPORT_SYMBOL(rproc_elf_load_segments);
>>  
>> -static struct elf32_shdr *
>> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>> +static const void *
> 
> Not sure I understand the "const" - was the compiler complaining?

It's actually caused by the fact I used a const void* shdr in the caller.
I will check if this is mandatory.

> 
>> +find_table(struct device *dev, const struct firmware *fw)
>>  {
>> -	struct elf32_shdr *shdr;
>> +	const void *shdr, *name_table_shdr;
>>  	int i;
>>  	const char *name_table;
>>  	struct resource_table *table = NULL;
>> -	const u8 *elf_data = (void *)ehdr;
>> +	const u8 *elf_data = (void *)fw->data;
>> +	u8 class = fw_elf_get_class(fw);
>> +	size_t fw_size = fw->size;
>> +	const void *ehdr = elf_data;
>> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
>> +	u32 elf_shdr_size = elf_size_of_shdr(class);
>> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
>>  
>>  	/* look for the resource table and handle it */
>> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
>> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
>> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
>> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
>> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
> 
> It took me a while but I figured out what is happening here.  To save me (and
> other people) from going through the same mental process every time I look at
> this code, please add a comment for each of the above 3 lines.

Indeed.

> 
>>  
>> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
>> -		u32 size = shdr->sh_size;
>> -		u32 offset = shdr->sh_offset;
>> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
>> +		u64 size = elf_shdr_sh_size(class, shdr);
>> +		u64 offset = elf_shdr_sh_offset(class, shdr);
>> +		u32 name = elf_shdr_sh_name(class, shdr);
>>  
>> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
>> +		if (strcmp(name_table + name, ".resource_table"))
>>  			continue;
>>  
>>  		table = (struct resource_table *)(elf_data + offset);
>> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
>> size_t fw_size)
>>   */
>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>>  {
>> -	struct elf32_hdr *ehdr;
>> -	struct elf32_shdr *shdr;
>> +	const void *shdr;
>>  	struct device *dev = &rproc->dev;
>>  	struct resource_table *table = NULL;
>>  	const u8 *elf_data = fw->data;
>>  	size_t tablesz;
>> +	u8 class = fw_elf_get_class(fw);
>> +	u64 sh_offset;
>>  
>> -	ehdr = (struct elf32_hdr *)elf_data;
>> -
>> -	shdr = find_table(dev, ehdr, fw->size);
>> +	shdr = find_table(dev, fw);
>>  	if (!shdr)
>>  		return -EINVAL;
>>  
>> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
>> -	tablesz = shdr->sh_size;
>> +	sh_offset = elf_shdr_sh_offset(class, shdr);
>> +	table = (struct resource_table *)(elf_data + sh_offset);
>> +	tablesz = elf_shdr_sh_size(class, shdr);
>>  
>>  	/*
>>  	 * Create a copy of the resource table. When a virtio device starts
>> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>>  						       const struct firmware *fw)
>>  {
>> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> -	struct elf32_shdr *shdr;
>> +	const void *shdr;
>> +	u64 sh_addr, sh_size;
>> +	u8 class = fw_elf_get_class(fw);
>>  
>> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
>> +	shdr = find_table(&rproc->dev, fw);
>>  	if (!shdr)
>>  		return NULL;
>>  
>> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
>> +	sh_addr = elf_shdr_sh_addr(class, shdr);
>> +	sh_size = elf_shdr_sh_size(class, shdr);
>> +
>> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
> 
> The prototype for the above is as follow:
> 
> void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> 
> But sh_size is a u64, which will cause problem that are hard to debug.  I think
> it is better to move 'len' to an 8 byte type along with the refactoring of the
> existing code that is implied.  I suggest to split this work in a preparatory
> patch (that will still be part of this set).

Nice catch ! I will do that.

> 
>>  }
>>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
>> b/drivers/remoteproc/remoteproc_elf_loader.h
>> new file mode 100644
>> index 000000000000..fac3565734f9
>> --- /dev/null
>> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
>> @@ -0,0 +1,69 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Remote processor elf loader defines
>> + *
>> + * Copyright (C) 2019 Kalray, Inc.
>> + */
>> +
>> +#ifndef REMOTEPROC_ELF_LOADER_H
>> +#define REMOTEPROC_ELF_LOADER_H
>> +
>> +#include <linux/elf.h>
>> +#include <linux/types.h>
>> +
>> +/**
>> + * fw_elf_get_class - Get elf class
>> + * @fw: the ELF firmware image
>> + *
>> + * Note that we use and elf32_hdr to access the class since the start of the
>> + * struct is the same for both elf class
>> + *
>> + * Return: elf class of the firmware
>> + */
>> +static inline u8 fw_elf_get_class(const struct firmware *fw)
>> +{
>> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> +
>> +	return ehdr->e_ident[EI_CLASS];
>> +}
>> +
>> +#define ELF_GET_FIELD(__s, __field, __type) \
>> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
>> +{ \
>> +	if (class == ELFCLASS32) \
>> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
>> +	else \
>> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
>> +}
>> +
>> +ELF_GET_FIELD(hdr, e_entry, u64)
>> +ELF_GET_FIELD(hdr, e_phnum, u16)
>> +ELF_GET_FIELD(hdr, e_shnum, u16)
>> +ELF_GET_FIELD(hdr, e_phoff, u64)
>> +ELF_GET_FIELD(hdr, e_shoff, u64)
>> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
>> +
>> +ELF_GET_FIELD(phdr, p_paddr, u64)
>> +ELF_GET_FIELD(phdr, p_filesz, u64)
>> +ELF_GET_FIELD(phdr, p_memsz, u64)
>> +ELF_GET_FIELD(phdr, p_type, u32)
>> +ELF_GET_FIELD(phdr, p_offset, u64)
>> +
>> +ELF_GET_FIELD(shdr, sh_size, u64)
>> +ELF_GET_FIELD(shdr, sh_offset, u64)
>> +ELF_GET_FIELD(shdr, sh_name, u32)
>> +ELF_GET_FIELD(shdr, sh_addr, u64)
> 
> I like how you did this.
> 
>> +
>> +#define ELF_STRUCT_SIZE(__s) \
>> +static inline unsigned long elf_size_of_##__s(u8 class) \
>> +{ \
>> +	if (class == ELFCLASS32)\
>> +		return sizeof(struct elf32_##__s); \
>> +	else \
>> +		return sizeof(struct elf64_##__s); \
>> +}
>> +
>> +ELF_STRUCT_SIZE(shdr)
>> +ELF_STRUCT_SIZE(phdr)
>> +
>> +#endif /* REMOTEPROC_ELF_LOADER_H */
>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> b/drivers/remoteproc/remoteproc_internal.h
>> index 45ff76a06c72..4ef745e3a1bc 100644
>> --- a/drivers/remoteproc/remoteproc_internal.h
>> +++ b/drivers/remoteproc/remoteproc_internal.h
>> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>>  int rproc_trigger_recovery(struct rproc *rproc);
>>  
>>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>> diff --git a/drivers/remoteproc/st_remoteproc.c
>> b/drivers/remoteproc/st_remoteproc.c
>> index 51049d17b1e5..e23abd8a96b0 100644
>> --- a/drivers/remoteproc/st_remoteproc.c
>> +++ b/drivers/remoteproc/st_remoteproc.c
>> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
>>  		}
>>  	}
>>  
>> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
>> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>>  
>>  	return 0;
>>  
>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> index 04d04709f2bd..512de9a2590c 100644
>> --- a/include/linux/remoteproc.h
>> +++ b/include/linux/remoteproc.h
>> @@ -362,7 +362,7 @@ struct rproc_ops {
>>  				struct rproc *rproc, const struct firmware *fw);
>>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
>>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
>> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>>  };
>>  
>>  /**
>> @@ -478,7 +478,7 @@ struct rproc {
>>  	int num_traces;
>>  	struct list_head carveouts;
>>  	struct list_head mappings;
>> -	u32 bootaddr;
>> +	u64 bootaddr;
>>  	struct list_head rvdevs;
>>  	struct list_head subdevs;
>>  	struct idr notifyids;
> 
> Please hold off before doing another respin of this patch.  While doing
> something completely different I noticed TI also did some work in this area.
> I'd like to take some time to look at their implementation and see if they carry
> features that haven't been included here.  I intend to do this tomorrow.

Ok,

Thanks for your review,

Clément

> 
> Thanks,
> Mathieu
> 
>> --
>> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v2] remoteproc: Add elf64 support in elf loader
  2020-01-24  8:24       ` Clément Leger
@ 2020-01-24 18:10         ` Mathieu Poirier
  2020-01-24 21:58         ` Mathieu Poirier
  1 sibling, 0 replies; 76+ messages in thread
From: Mathieu Poirier @ 2020-01-24 18:10 UTC (permalink / raw)
  To: Clément Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel,
	Arnaud Pouliquen, Loic PALLARDY

On Fri, Jan 24, 2020 at 09:24:16AM +0100, Clément Leger wrote:
> Hi Mathieu,
> 
> ----- On 24 Jan, 2020, at 01:53, Mathieu Poirier mathieu.poirier@linaro.org wrote:
> 
> > Hi Clement,
> > 
> > On Fri, Oct 04, 2019 at 08:42:20PM +0200, Clement Leger wrote:
> >> elf32 and elf64 mainly differ by their types. In order to avoid
> >> copy/pasting the whole loader code, generate static inline functions
> >> which will access values according to the elf class. It allows to keep a
> >> common loader basis.
> >> In order to accomodate both elf types sizes, the maximum size for a
> >> elf header member is chosen using the maximum value of both elf class.
> >> 
> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
> >> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
> >> ---
> >> Changes in v2:
> >>  - Add ELF64 support in documentation
> >>
> > 
> > First and foremost please address the complaints from checkpatch.
> 
> I fixed one typo in accommodate. The other checkpatch complaint is
> about missing parenthesis for macros with complex values which is
> unfortunately not possible since I'm generating inline functions.
> 
> Did you have any other one ?

No

> 
> > 
> >> ---
> >>  Documentation/remoteproc.txt               |   2 +-
> >>  drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
> >>  drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
> >>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
> >>  drivers/remoteproc/st_remoteproc.c         |   2 +-
> >>  include/linux/remoteproc.h                 |   4 +-
> >>  6 files changed, 157 insertions(+), 57 deletions(-)
> >>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
> >> 
> >> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
> >> index 77fb03acdbb4..bf4f0c41ec4e 100644
> >> --- a/Documentation/remoteproc.txt
> >> +++ b/Documentation/remoteproc.txt
> >> @@ -230,7 +230,7 @@ in the used rings.
> >>  Binary Firmware Structure
> >>  =========================
> >>  
> >> -At this point remoteproc only supports ELF32 firmware binaries. However,
> >> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
> >>  it is quite expected that other platforms/devices which we'd want to
> >>  support with this framework will be based on different binary formats.
> >>  
> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
> >> b/drivers/remoteproc/remoteproc_elf_loader.c
> >> index b17d72ec8603..6a2d31d6092c 100644
> >> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> >> @@ -31,6 +31,7 @@
> >>  #include <linux/elf.h>
> >>  
> >>  #include "remoteproc_internal.h"
> >> +#include "remoteproc_elf_loader.h"
> >>  
> >>  /**
> >>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> >> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> firmware *fw)
> >>  {
> >>  	const char *name = rproc->firmware;
> >>  	struct device *dev = &rproc->dev;
> >> +	/*
> >> +	 * Elf files are beginning with the same structure. Thus, to simplify
> >> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
> >> +	 * elf32.
> >> +	 */
> >>  	struct elf32_hdr *ehdr;
> >> +	u32 elf_shdr_size;
> >> +	u64 phoff, shoff;
> >>  	char class;
> >> +	u16 phnum;
> >>  
> >>  	if (!fw) {
> >>  		dev_err(dev, "failed to load %s\n", name);
> >> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> firmware *fw)
> > 
> > In the current code [1] fw->size is compared against the size of an elf32_hdr.
> > If support for elf64 is added that code needs to be modified to check for the
> > right header size using fw_elf_get_class().
> 
> Actually, the elf32 header is smaller than the elf64 one so this check is
> there to ensure that we have at least a minimal elf header (elf32).
> And since the class is derived from the header, you better have to check the
> header size before accessing it.

This is a chicken-and-egg issue... We can't derive the class from the header if
we don't check the header and we can't check the header if we don't have the
class.  Since ehdr->e_ident[] is the same for both, it is probably safe to
access e_ident[EI_CLASS] without further checks.  

> 
> To be more clear, I could compare it to min(sizeof(struct elf32_hdr),
> sizeof(struct elf64_hdr)) or add a comment at least stating that since
> elf header contains the same fields for identification, we can use the 
> elf32 one.

I am concerned about cases where we deal with an elf64 and fw->size is >=
sizeof(struct elf32_hdr) and < sizeof(struct elf64_hdr).  With the current code
we won't catch the error.  It might be that we do something like this:

        size_t header_size;

        header_size = (fw_elf_get_class(fw) == ELFCLASS32 ?
                       sizeof(structelf32_hdr):
                       sizeof(structelf64_hdr);

        if (fw->size < header_size ) {
                ...
        }

> 
> > 
> > [1]
> > https://elixir.bootlin.com/linux/v5.5-rc6/source/drivers/remoteproc/remoteproc_elf_loader.c#L46
> > 
> >>  
> >>  	ehdr = (struct elf32_hdr *)fw->data;
> >>  
> >> -	/* We only support ELF32 at this point */
> >> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> >> +		dev_err(dev, "Image is corrupted (bad magic)\n");
> >> +		return -EINVAL;
> >> +	}
> >> +
> > 
> > Is there a reason to move this check up where?  If not please bring it back to
> > its original location, that is below:
> > 
> > "if (fw->size < ehdr->e_shoff + sizeof(structelf32_shdr))"
> > 
> 
> This is because the new check for size uses elf_shdr_size which is derived from
> the class. And since the class is extracted from the elf header, we need to check
> the header to be correct first.
> 
> >>  	class = ehdr->e_ident[EI_CLASS];
> >> -	if (class != ELFCLASS32) {
> >> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
> >>  		dev_err(dev, "Unsupported class: %d\n", class);
> >>  		return -EINVAL;
> >>  	}
> >> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> firmware *fw)
> >>  		return -EINVAL;
> >>  	}
> >>  
> >> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
> >> -		dev_err(dev, "Image is too small\n");
> >> -		return -EINVAL;
> >> -	}
> >> +	phoff = elf_hdr_e_phoff(class, fw->data);
> >> +	shoff = elf_hdr_e_shoff(class, fw->data);
> >> +	phnum =  elf_hdr_e_phnum(class, fw->data);
> >> +	elf_shdr_size = elf_size_of_shdr(class);
> >>  
> >> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> >> -		dev_err(dev, "Image is corrupted (bad magic)\n");
> >> +	if (fw->size < shoff + elf_shdr_size) {
> >> +		dev_err(dev, "Image is too small\n");
> >>  		return -EINVAL;
> >>  	}
> >>  
> >> -	if (ehdr->e_phnum == 0) {
> >> +	if (phnum == 0) {
> >>  		dev_err(dev, "No loadable segments\n");
> >>  		return -EINVAL;
> >>  	}
> >>  
> >> -	if (ehdr->e_phoff > fw->size) {
> >> +	if (phoff > fw->size) {
> >>  		dev_err(dev, "Firmware size is too small\n");
> >>  		return -EINVAL;
> >>  	}
> >>  
> >> +	dev_dbg(dev, "Firmware is an elf%d file\n",
> >> +		class == ELFCLASS32 ? 32 : 64);
> >> +
> > 
> > Yes, this is useful.
> > 
> >>  	return 0;
> >>  }
> >>  EXPORT_SYMBOL(rproc_elf_sanity_check);
> >> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
> >>   * Note that the boot address is not a configurable property of all remote
> >>   * processors. Some will always boot at a specific hard-coded address.
> >>   */
> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> >>  {
> >> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
> >> -
> >> -	return ehdr->e_entry;
> >> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
> >>  }
> >>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> >>  
> >> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
> >>  {
> >>  	struct device *dev = &rproc->dev;
> >> -	struct elf32_hdr *ehdr;
> >> -	struct elf32_phdr *phdr;
> >> +	const void *ehdr, *phdr;
> >>  	int i, ret = 0;
> >> +	u16 phnum;
> >>  	const u8 *elf_data = fw->data;
> >> +	u8 class = fw_elf_get_class(fw);
> >> +	u32 elf_phdr_size = elf_size_of_phdr(class);
> >>  
> >> -	ehdr = (struct elf32_hdr *)elf_data;
> >> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> >> +	ehdr = elf_data;
> >> +	phnum = elf_hdr_e_phnum(class, ehdr);
> >> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
> >>  
> >>  	/* go through the available ELF segments */
> >> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> >> -		u32 da = phdr->p_paddr;
> >> -		u32 memsz = phdr->p_memsz;
> >> -		u32 filesz = phdr->p_filesz;
> >> -		u32 offset = phdr->p_offset;
> >> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
> >> +		u64 da = elf_phdr_p_paddr(class, phdr);
> >> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
> >> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
> >> +		u64 offset = elf_phdr_p_offset(class, phdr);
> >> +		u32 type = elf_phdr_p_type(class, phdr);
> >>  		void *ptr;
> >>  
> >> -		if (phdr->p_type != PT_LOAD)
> >> +		if (type != PT_LOAD)
> >>  			continue;
> >>  
> >> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
> >> -			phdr->p_type, da, memsz, filesz);
> >> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
> >> +			type, da, memsz, filesz);
> >>  
> >>  		if (filesz > memsz) {
> >> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
> >> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
> >>  				filesz, memsz);
> >>  			ret = -EINVAL;
> >>  			break;
> >>  		}
> >>  
> >>  		if (offset + filesz > fw->size) {
> >> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
> >> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
> >>  				offset + filesz, fw->size);
> >>  			ret = -EINVAL;
> >>  			break;
> >> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> >> struct firmware *fw)
> >>  		/* grab the kernel address for this device address */
> >>  		ptr = rproc_da_to_va(rproc, da, memsz);
> >>  		if (!ptr) {
> >> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> >> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
> >> +				memsz);
> >>  			ret = -EINVAL;
> >>  			break;
> >>  		}
> >>  
> >>  		/* put the segment where the remote processor expects it */
> >> -		if (phdr->p_filesz)
> >> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
> >> +		if (filesz)
> >> +			memcpy(ptr, elf_data + offset, filesz);
> >>  
> >>  		/*
> >>  		 * Zero out remaining memory for this segment.
> >> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> >> struct firmware *fw)
> >>  }
> >>  EXPORT_SYMBOL(rproc_elf_load_segments);
> >>  
> >> -static struct elf32_shdr *
> >> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> >> +static const void *
> > 
> > Not sure I understand the "const" - was the compiler complaining?
> 
> It's actually caused by the fact I used a const void* shdr in the caller.
> I will check if this is mandatory.
> 
> > 
> >> +find_table(struct device *dev, const struct firmware *fw)
> >>  {
> >> -	struct elf32_shdr *shdr;
> >> +	const void *shdr, *name_table_shdr;
> >>  	int i;
> >>  	const char *name_table;
> >>  	struct resource_table *table = NULL;
> >> -	const u8 *elf_data = (void *)ehdr;
> >> +	const u8 *elf_data = (void *)fw->data;
> >> +	u8 class = fw_elf_get_class(fw);
> >> +	size_t fw_size = fw->size;
> >> +	const void *ehdr = elf_data;
> >> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
> >> +	u32 elf_shdr_size = elf_size_of_shdr(class);
> >> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
> >>  
> >>  	/* look for the resource table and handle it */
> >> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> >> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
> >> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
> >> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
> >> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
> > 
> > It took me a while but I figured out what is happening here.  To save me (and
> > other people) from going through the same mental process every time I look at
> > this code, please add a comment for each of the above 3 lines.
> 
> Indeed.
> 
> > 
> >>  
> >> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> >> -		u32 size = shdr->sh_size;
> >> -		u32 offset = shdr->sh_offset;
> >> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
> >> +		u64 size = elf_shdr_sh_size(class, shdr);
> >> +		u64 offset = elf_shdr_sh_offset(class, shdr);
> >> +		u32 name = elf_shdr_sh_name(class, shdr);
> >>  
> >> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
> >> +		if (strcmp(name_table + name, ".resource_table"))
> >>  			continue;
> >>  
> >>  		table = (struct resource_table *)(elf_data + offset);
> >> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
> >> size_t fw_size)
> >>   */
> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
> >>  {
> >> -	struct elf32_hdr *ehdr;
> >> -	struct elf32_shdr *shdr;
> >> +	const void *shdr;
> >>  	struct device *dev = &rproc->dev;
> >>  	struct resource_table *table = NULL;
> >>  	const u8 *elf_data = fw->data;
> >>  	size_t tablesz;
> >> +	u8 class = fw_elf_get_class(fw);
> >> +	u64 sh_offset;
> >>  
> >> -	ehdr = (struct elf32_hdr *)elf_data;
> >> -
> >> -	shdr = find_table(dev, ehdr, fw->size);
> >> +	shdr = find_table(dev, fw);
> >>  	if (!shdr)
> >>  		return -EINVAL;
> >>  
> >> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
> >> -	tablesz = shdr->sh_size;
> >> +	sh_offset = elf_shdr_sh_offset(class, shdr);
> >> +	table = (struct resource_table *)(elf_data + sh_offset);
> >> +	tablesz = elf_shdr_sh_size(class, shdr);
> >>  
> >>  	/*
> >>  	 * Create a copy of the resource table. When a virtio device starts
> >> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> >>  						       const struct firmware *fw)
> >>  {
> >> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> >> -	struct elf32_shdr *shdr;
> >> +	const void *shdr;
> >> +	u64 sh_addr, sh_size;
> >> +	u8 class = fw_elf_get_class(fw);
> >>  
> >> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
> >> +	shdr = find_table(&rproc->dev, fw);
> >>  	if (!shdr)
> >>  		return NULL;
> >>  
> >> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
> >> +	sh_addr = elf_shdr_sh_addr(class, shdr);
> >> +	sh_size = elf_shdr_sh_size(class, shdr);
> >> +
> >> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
> > 
> > The prototype for the above is as follow:
> > 
> > void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> > 
> > But sh_size is a u64, which will cause problem that are hard to debug.  I think
> > it is better to move 'len' to an 8 byte type along with the refactoring of the
> > existing code that is implied.  I suggest to split this work in a preparatory
> > patch (that will still be part of this set).
> 
> Nice catch ! I will do that.
> 
> > 
> >>  }
> >>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
> >> b/drivers/remoteproc/remoteproc_elf_loader.h
> >> new file mode 100644
> >> index 000000000000..fac3565734f9
> >> --- /dev/null
> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
> >> @@ -0,0 +1,69 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Remote processor elf loader defines
> >> + *
> >> + * Copyright (C) 2019 Kalray, Inc.
> >> + */
> >> +
> >> +#ifndef REMOTEPROC_ELF_LOADER_H
> >> +#define REMOTEPROC_ELF_LOADER_H
> >> +
> >> +#include <linux/elf.h>
> >> +#include <linux/types.h>
> >> +
> >> +/**
> >> + * fw_elf_get_class - Get elf class
> >> + * @fw: the ELF firmware image
> >> + *
> >> + * Note that we use and elf32_hdr to access the class since the start of the
> >> + * struct is the same for both elf class
> >> + *
> >> + * Return: elf class of the firmware
> >> + */
> >> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> >> +{
> >> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> >> +
> >> +	return ehdr->e_ident[EI_CLASS];
> >> +}
> >> +
> >> +#define ELF_GET_FIELD(__s, __field, __type) \
> >> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
> >> +{ \
> >> +	if (class == ELFCLASS32) \
> >> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
> >> +	else \
> >> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
> >> +}
> >> +
> >> +ELF_GET_FIELD(hdr, e_entry, u64)
> >> +ELF_GET_FIELD(hdr, e_phnum, u16)
> >> +ELF_GET_FIELD(hdr, e_shnum, u16)
> >> +ELF_GET_FIELD(hdr, e_phoff, u64)
> >> +ELF_GET_FIELD(hdr, e_shoff, u64)
> >> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
> >> +
> >> +ELF_GET_FIELD(phdr, p_paddr, u64)
> >> +ELF_GET_FIELD(phdr, p_filesz, u64)
> >> +ELF_GET_FIELD(phdr, p_memsz, u64)
> >> +ELF_GET_FIELD(phdr, p_type, u32)
> >> +ELF_GET_FIELD(phdr, p_offset, u64)
> >> +
> >> +ELF_GET_FIELD(shdr, sh_size, u64)
> >> +ELF_GET_FIELD(shdr, sh_offset, u64)
> >> +ELF_GET_FIELD(shdr, sh_name, u32)
> >> +ELF_GET_FIELD(shdr, sh_addr, u64)
> > 
> > I like how you did this.
> > 
> >> +
> >> +#define ELF_STRUCT_SIZE(__s) \
> >> +static inline unsigned long elf_size_of_##__s(u8 class) \
> >> +{ \
> >> +	if (class == ELFCLASS32)\
> >> +		return sizeof(struct elf32_##__s); \
> >> +	else \
> >> +		return sizeof(struct elf64_##__s); \
> >> +}
> >> +
> >> +ELF_STRUCT_SIZE(shdr)
> >> +ELF_STRUCT_SIZE(phdr)
> >> +
> >> +#endif /* REMOTEPROC_ELF_LOADER_H */
> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
> >> b/drivers/remoteproc/remoteproc_internal.h
> >> index 45ff76a06c72..4ef745e3a1bc 100644
> >> --- a/drivers/remoteproc/remoteproc_internal.h
> >> +++ b/drivers/remoteproc/remoteproc_internal.h
> >> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
> >>  int rproc_trigger_recovery(struct rproc *rproc);
> >>  
> >>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> >> diff --git a/drivers/remoteproc/st_remoteproc.c
> >> b/drivers/remoteproc/st_remoteproc.c
> >> index 51049d17b1e5..e23abd8a96b0 100644
> >> --- a/drivers/remoteproc/st_remoteproc.c
> >> +++ b/drivers/remoteproc/st_remoteproc.c
> >> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
> >>  		}
> >>  	}
> >>  
> >> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> >> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
> >>  
> >>  	return 0;
> >>  
> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> >> index 04d04709f2bd..512de9a2590c 100644
> >> --- a/include/linux/remoteproc.h
> >> +++ b/include/linux/remoteproc.h
> >> @@ -362,7 +362,7 @@ struct rproc_ops {
> >>  				struct rproc *rproc, const struct firmware *fw);
> >>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
> >>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> >> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> >> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> >>  };
> >>  
> >>  /**
> >> @@ -478,7 +478,7 @@ struct rproc {
> >>  	int num_traces;
> >>  	struct list_head carveouts;
> >>  	struct list_head mappings;
> >> -	u32 bootaddr;
> >> +	u64 bootaddr;
> >>  	struct list_head rvdevs;
> >>  	struct list_head subdevs;
> >>  	struct idr notifyids;
> > 
> > Please hold off before doing another respin of this patch.  While doing
> > something completely different I noticed TI also did some work in this area.
> > I'd like to take some time to look at their implementation and see if they carry
> > features that haven't been included here.  I intend to do this tomorrow.
> 
> Ok,
> 
> Thanks for your review,
> 
> Clément
> 
> > 
> > Thanks,
> > Mathieu
> > 
> >> --
> >> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v2] remoteproc: Add elf64 support in elf loader
  2020-01-24  8:24       ` Clément Leger
  2020-01-24 18:10         ` Mathieu Poirier
@ 2020-01-24 21:58         ` Mathieu Poirier
  2020-01-27  8:33           ` Clément Leger
  1 sibling, 1 reply; 76+ messages in thread
From: Mathieu Poirier @ 2020-01-24 21:58 UTC (permalink / raw)
  To: Clément Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Fri, Jan 24, 2020 at 09:24:16AM +0100, Clément Leger wrote:
> Hi Mathieu,
> 
> ----- On 24 Jan, 2020, at 01:53, Mathieu Poirier mathieu.poirier@linaro.org wrote:
> 
> > Hi Clement,
> > 
> > On Fri, Oct 04, 2019 at 08:42:20PM +0200, Clement Leger wrote:
> >> elf32 and elf64 mainly differ by their types. In order to avoid
> >> copy/pasting the whole loader code, generate static inline functions
> >> which will access values according to the elf class. It allows to keep a
> >> common loader basis.
> >> In order to accomodate both elf types sizes, the maximum size for a
> >> elf header member is chosen using the maximum value of both elf class.
> >> 
> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
> >> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
> >> ---
> >> Changes in v2:
> >>  - Add ELF64 support in documentation
> >>
> > 
> > First and foremost please address the complaints from checkpatch.
> 
> I fixed one typo in accommodate. The other checkpatch complaint is
> about missing parenthesis for macros with complex values which is
> unfortunately not possible since I'm generating inline functions.
> 
> Did you have any other one ?
> 
> > 
> >> ---
> >>  Documentation/remoteproc.txt               |   2 +-
> >>  drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
> >>  drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
> >>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
> >>  drivers/remoteproc/st_remoteproc.c         |   2 +-
> >>  include/linux/remoteproc.h                 |   4 +-
> >>  6 files changed, 157 insertions(+), 57 deletions(-)
> >>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
> >> 
> >> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
> >> index 77fb03acdbb4..bf4f0c41ec4e 100644
> >> --- a/Documentation/remoteproc.txt
> >> +++ b/Documentation/remoteproc.txt
> >> @@ -230,7 +230,7 @@ in the used rings.
> >>  Binary Firmware Structure
> >>  =========================
> >>  
> >> -At this point remoteproc only supports ELF32 firmware binaries. However,
> >> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
> >>  it is quite expected that other platforms/devices which we'd want to
> >>  support with this framework will be based on different binary formats.
> >>  
> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
> >> b/drivers/remoteproc/remoteproc_elf_loader.c
> >> index b17d72ec8603..6a2d31d6092c 100644
> >> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> >> @@ -31,6 +31,7 @@
> >>  #include <linux/elf.h>
> >>  
> >>  #include "remoteproc_internal.h"
> >> +#include "remoteproc_elf_loader.h"
> >>  
> >>  /**
> >>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> >> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> firmware *fw)
> >>  {
> >>  	const char *name = rproc->firmware;
> >>  	struct device *dev = &rproc->dev;
> >> +	/*
> >> +	 * Elf files are beginning with the same structure. Thus, to simplify
> >> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
> >> +	 * elf32.
> >> +	 */
> >>  	struct elf32_hdr *ehdr;
> >> +	u32 elf_shdr_size;
> >> +	u64 phoff, shoff;
> >>  	char class;
> >> +	u16 phnum;
> >>  
> >>  	if (!fw) {
> >>  		dev_err(dev, "failed to load %s\n", name);
> >> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> firmware *fw)
> > 
> > In the current code [1] fw->size is compared against the size of an elf32_hdr.
> > If support for elf64 is added that code needs to be modified to check for the
> > right header size using fw_elf_get_class().
> 
> Actually, the elf32 header is smaller than the elf64 one so this check is
> there to ensure that we have at least a minimal elf header (elf32).
> And since the class is derived from the header, you better have to check the
> header size before accessing it.
> 
> To be more clear, I could compare it to min(sizeof(struct elf32_hdr),
> sizeof(struct elf64_hdr)) or add a comment at least stating that since
> elf header contains the same fields for identification, we can use the 
> elf32 one.
> 
> > 
> > [1]
> > https://elixir.bootlin.com/linux/v5.5-rc6/source/drivers/remoteproc/remoteproc_elf_loader.c#L46
> > 
> >>  
> >>  	ehdr = (struct elf32_hdr *)fw->data;
> >>  
> >> -	/* We only support ELF32 at this point */
> >> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> >> +		dev_err(dev, "Image is corrupted (bad magic)\n");
> >> +		return -EINVAL;
> >> +	}
> >> +
> > 
> > Is there a reason to move this check up where?  If not please bring it back to
> > its original location, that is below:
> > 
> > "if (fw->size < ehdr->e_shoff + sizeof(structelf32_shdr))"
> > 
> 
> This is because the new check for size uses elf_shdr_size which is derived from
> the class. And since the class is extracted from the elf header, we need to check
> the header to be correct first.
> 
> >>  	class = ehdr->e_ident[EI_CLASS];
> >> -	if (class != ELFCLASS32) {
> >> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
> >>  		dev_err(dev, "Unsupported class: %d\n", class);
> >>  		return -EINVAL;
> >>  	}
> >> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> firmware *fw)
> >>  		return -EINVAL;
> >>  	}
> >>  
> >> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
> >> -		dev_err(dev, "Image is too small\n");
> >> -		return -EINVAL;
> >> -	}
> >> +	phoff = elf_hdr_e_phoff(class, fw->data);
> >> +	shoff = elf_hdr_e_shoff(class, fw->data);
> >> +	phnum =  elf_hdr_e_phnum(class, fw->data);
> >> +	elf_shdr_size = elf_size_of_shdr(class);
> >>  
> >> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> >> -		dev_err(dev, "Image is corrupted (bad magic)\n");
> >> +	if (fw->size < shoff + elf_shdr_size) {
> >> +		dev_err(dev, "Image is too small\n");
> >>  		return -EINVAL;
> >>  	}
> >>  
> >> -	if (ehdr->e_phnum == 0) {
> >> +	if (phnum == 0) {
> >>  		dev_err(dev, "No loadable segments\n");
> >>  		return -EINVAL;
> >>  	}
> >>  
> >> -	if (ehdr->e_phoff > fw->size) {
> >> +	if (phoff > fw->size) {
> >>  		dev_err(dev, "Firmware size is too small\n");
> >>  		return -EINVAL;
> >>  	}
> >>  
> >> +	dev_dbg(dev, "Firmware is an elf%d file\n",
> >> +		class == ELFCLASS32 ? 32 : 64);
> >> +
> > 
> > Yes, this is useful.
> > 
> >>  	return 0;
> >>  }
> >>  EXPORT_SYMBOL(rproc_elf_sanity_check);
> >> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
> >>   * Note that the boot address is not a configurable property of all remote
> >>   * processors. Some will always boot at a specific hard-coded address.
> >>   */
> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> >>  {
> >> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
> >> -
> >> -	return ehdr->e_entry;
> >> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
> >>  }
> >>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> >>  
> >> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
> >>  {
> >>  	struct device *dev = &rproc->dev;
> >> -	struct elf32_hdr *ehdr;
> >> -	struct elf32_phdr *phdr;
> >> +	const void *ehdr, *phdr;
> >>  	int i, ret = 0;
> >> +	u16 phnum;
> >>  	const u8 *elf_data = fw->data;
> >> +	u8 class = fw_elf_get_class(fw);
> >> +	u32 elf_phdr_size = elf_size_of_phdr(class);
> >>  
> >> -	ehdr = (struct elf32_hdr *)elf_data;
> >> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> >> +	ehdr = elf_data;
> >> +	phnum = elf_hdr_e_phnum(class, ehdr);
> >> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
> >>  
> >>  	/* go through the available ELF segments */
> >> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> >> -		u32 da = phdr->p_paddr;
> >> -		u32 memsz = phdr->p_memsz;
> >> -		u32 filesz = phdr->p_filesz;
> >> -		u32 offset = phdr->p_offset;
> >> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
> >> +		u64 da = elf_phdr_p_paddr(class, phdr);
> >> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
> >> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
> >> +		u64 offset = elf_phdr_p_offset(class, phdr);
> >> +		u32 type = elf_phdr_p_type(class, phdr);
> >>  		void *ptr;
> >>  
> >> -		if (phdr->p_type != PT_LOAD)
> >> +		if (type != PT_LOAD)
> >>  			continue;
> >>  
> >> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
> >> -			phdr->p_type, da, memsz, filesz);
> >> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
> >> +			type, da, memsz, filesz);
> >>  
> >>  		if (filesz > memsz) {
> >> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
> >> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
> >>  				filesz, memsz);
> >>  			ret = -EINVAL;
> >>  			break;
> >>  		}
> >>  
> >>  		if (offset + filesz > fw->size) {
> >> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
> >> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
> >>  				offset + filesz, fw->size);
> >>  			ret = -EINVAL;
> >>  			break;
> >> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> >> struct firmware *fw)
> >>  		/* grab the kernel address for this device address */
> >>  		ptr = rproc_da_to_va(rproc, da, memsz);
> >>  		if (!ptr) {
> >> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> >> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
> >> +				memsz);
> >>  			ret = -EINVAL;
> >>  			break;
> >>  		}
> >>  
> >>  		/* put the segment where the remote processor expects it */
> >> -		if (phdr->p_filesz)
> >> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
> >> +		if (filesz)
> >> +			memcpy(ptr, elf_data + offset, filesz);
> >>  
> >>  		/*
> >>  		 * Zero out remaining memory for this segment.
> >> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> >> struct firmware *fw)
> >>  }
> >>  EXPORT_SYMBOL(rproc_elf_load_segments);
> >>  
> >> -static struct elf32_shdr *
> >> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> >> +static const void *
> > 
> > Not sure I understand the "const" - was the compiler complaining?
> 
> It's actually caused by the fact I used a const void* shdr in the caller.
> I will check if this is mandatory.
> 
> > 
> >> +find_table(struct device *dev, const struct firmware *fw)
> >>  {
> >> -	struct elf32_shdr *shdr;
> >> +	const void *shdr, *name_table_shdr;
> >>  	int i;
> >>  	const char *name_table;
> >>  	struct resource_table *table = NULL;
> >> -	const u8 *elf_data = (void *)ehdr;
> >> +	const u8 *elf_data = (void *)fw->data;
> >> +	u8 class = fw_elf_get_class(fw);
> >> +	size_t fw_size = fw->size;
> >> +	const void *ehdr = elf_data;
> >> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
> >> +	u32 elf_shdr_size = elf_size_of_shdr(class);
> >> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
> >>  
> >>  	/* look for the resource table and handle it */
> >> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> >> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
> >> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
> >> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
> >> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
> > 
> > It took me a while but I figured out what is happening here.  To save me (and
> > other people) from going through the same mental process every time I look at
> > this code, please add a comment for each of the above 3 lines.
> 
> Indeed.
> 
> > 
> >>  
> >> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> >> -		u32 size = shdr->sh_size;
> >> -		u32 offset = shdr->sh_offset;
> >> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
> >> +		u64 size = elf_shdr_sh_size(class, shdr);
> >> +		u64 offset = elf_shdr_sh_offset(class, shdr);
> >> +		u32 name = elf_shdr_sh_name(class, shdr);
> >>  
> >> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
> >> +		if (strcmp(name_table + name, ".resource_table"))
> >>  			continue;
> >>  
> >>  		table = (struct resource_table *)(elf_data + offset);
> >> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
> >> size_t fw_size)
> >>   */
> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
> >>  {
> >> -	struct elf32_hdr *ehdr;
> >> -	struct elf32_shdr *shdr;
> >> +	const void *shdr;
> >>  	struct device *dev = &rproc->dev;
> >>  	struct resource_table *table = NULL;
> >>  	const u8 *elf_data = fw->data;
> >>  	size_t tablesz;
> >> +	u8 class = fw_elf_get_class(fw);
> >> +	u64 sh_offset;
> >>  
> >> -	ehdr = (struct elf32_hdr *)elf_data;
> >> -
> >> -	shdr = find_table(dev, ehdr, fw->size);
> >> +	shdr = find_table(dev, fw);
> >>  	if (!shdr)
> >>  		return -EINVAL;
> >>  
> >> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
> >> -	tablesz = shdr->sh_size;
> >> +	sh_offset = elf_shdr_sh_offset(class, shdr);
> >> +	table = (struct resource_table *)(elf_data + sh_offset);
> >> +	tablesz = elf_shdr_sh_size(class, shdr);
> >>  
> >>  	/*
> >>  	 * Create a copy of the resource table. When a virtio device starts
> >> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> >>  						       const struct firmware *fw)
> >>  {
> >> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> >> -	struct elf32_shdr *shdr;
> >> +	const void *shdr;
> >> +	u64 sh_addr, sh_size;
> >> +	u8 class = fw_elf_get_class(fw);
> >>  
> >> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
> >> +	shdr = find_table(&rproc->dev, fw);
> >>  	if (!shdr)
> >>  		return NULL;
> >>  
> >> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
> >> +	sh_addr = elf_shdr_sh_addr(class, shdr);
> >> +	sh_size = elf_shdr_sh_size(class, shdr);
> >> +
> >> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
> > 
> > The prototype for the above is as follow:
> > 
> > void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> > 
> > But sh_size is a u64, which will cause problem that are hard to debug.  I think
> > it is better to move 'len' to an 8 byte type along with the refactoring of the
> > existing code that is implied.  I suggest to split this work in a preparatory
> > patch (that will still be part of this set).
> 
> Nice catch ! I will do that.
> 
> > 
> >>  }
> >>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
> >> b/drivers/remoteproc/remoteproc_elf_loader.h
> >> new file mode 100644
> >> index 000000000000..fac3565734f9
> >> --- /dev/null
> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
> >> @@ -0,0 +1,69 @@
> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> +/*
> >> + * Remote processor elf loader defines
> >> + *
> >> + * Copyright (C) 2019 Kalray, Inc.
> >> + */
> >> +
> >> +#ifndef REMOTEPROC_ELF_LOADER_H
> >> +#define REMOTEPROC_ELF_LOADER_H
> >> +
> >> +#include <linux/elf.h>
> >> +#include <linux/types.h>
> >> +
> >> +/**
> >> + * fw_elf_get_class - Get elf class
> >> + * @fw: the ELF firmware image
> >> + *
> >> + * Note that we use and elf32_hdr to access the class since the start of the
> >> + * struct is the same for both elf class
> >> + *
> >> + * Return: elf class of the firmware
> >> + */
> >> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> >> +{
> >> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> >> +
> >> +	return ehdr->e_ident[EI_CLASS];
> >> +}
> >> +
> >> +#define ELF_GET_FIELD(__s, __field, __type) \
> >> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
> >> +{ \
> >> +	if (class == ELFCLASS32) \
> >> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
> >> +	else \
> >> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
> >> +}
> >> +
> >> +ELF_GET_FIELD(hdr, e_entry, u64)
> >> +ELF_GET_FIELD(hdr, e_phnum, u16)
> >> +ELF_GET_FIELD(hdr, e_shnum, u16)
> >> +ELF_GET_FIELD(hdr, e_phoff, u64)
> >> +ELF_GET_FIELD(hdr, e_shoff, u64)
> >> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
> >> +
> >> +ELF_GET_FIELD(phdr, p_paddr, u64)
> >> +ELF_GET_FIELD(phdr, p_filesz, u64)
> >> +ELF_GET_FIELD(phdr, p_memsz, u64)
> >> +ELF_GET_FIELD(phdr, p_type, u32)
> >> +ELF_GET_FIELD(phdr, p_offset, u64)
> >> +
> >> +ELF_GET_FIELD(shdr, sh_size, u64)
> >> +ELF_GET_FIELD(shdr, sh_offset, u64)
> >> +ELF_GET_FIELD(shdr, sh_name, u32)
> >> +ELF_GET_FIELD(shdr, sh_addr, u64)
> > 
> > I like how you did this.
> > 
> >> +
> >> +#define ELF_STRUCT_SIZE(__s) \
> >> +static inline unsigned long elf_size_of_##__s(u8 class) \
> >> +{ \
> >> +	if (class == ELFCLASS32)\
> >> +		return sizeof(struct elf32_##__s); \
> >> +	else \
> >> +		return sizeof(struct elf64_##__s); \
> >> +}
> >> +
> >> +ELF_STRUCT_SIZE(shdr)
> >> +ELF_STRUCT_SIZE(phdr)
> >> +
> >> +#endif /* REMOTEPROC_ELF_LOADER_H */
> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
> >> b/drivers/remoteproc/remoteproc_internal.h
> >> index 45ff76a06c72..4ef745e3a1bc 100644
> >> --- a/drivers/remoteproc/remoteproc_internal.h
> >> +++ b/drivers/remoteproc/remoteproc_internal.h
> >> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
> >>  int rproc_trigger_recovery(struct rproc *rproc);
> >>  
> >>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> >> diff --git a/drivers/remoteproc/st_remoteproc.c
> >> b/drivers/remoteproc/st_remoteproc.c
> >> index 51049d17b1e5..e23abd8a96b0 100644
> >> --- a/drivers/remoteproc/st_remoteproc.c
> >> +++ b/drivers/remoteproc/st_remoteproc.c
> >> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
> >>  		}
> >>  	}
> >>  
> >> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> >> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
> >>  
> >>  	return 0;
> >>  
> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> >> index 04d04709f2bd..512de9a2590c 100644
> >> --- a/include/linux/remoteproc.h
> >> +++ b/include/linux/remoteproc.h
> >> @@ -362,7 +362,7 @@ struct rproc_ops {
> >>  				struct rproc *rproc, const struct firmware *fw);
> >>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
> >>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> >> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> >> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> >>  };
> >>  
> >>  /**
> >> @@ -478,7 +478,7 @@ struct rproc {
> >>  	int num_traces;
> >>  	struct list_head carveouts;
> >>  	struct list_head mappings;
> >> -	u32 bootaddr;
> >> +	u64 bootaddr;
> >>  	struct list_head rvdevs;
> >>  	struct list_head subdevs;
> >>  	struct idr notifyids;
> > 
> > Please hold off before doing another respin of this patch.  While doing
> > something completely different I noticed TI also did some work in this area.
> > I'd like to take some time to look at their implementation and see if they carry
> > features that haven't been included here.  I intend to do this tomorrow.
> 
> Ok,
> 
> Thanks for your review,

As promised I looked at what Suman had done on his side [1] to support 64-bit ELF
files. His approach to offer the same functionality but for 64 bit in a new file
is quick, simple and flexible.  On the flip side it introduces code duplication,
something that is seriously frowned upon upstream.  

I did some soul searching in the kernel code and found very little in terms of
implementation that deals with both 32 and 64 bit ELF format.  The most
convincing approach was set forth by the MIPS guys [2].  They too have decided
to support both types in the same functions, but I don't see us adding an if()
statement (and the code duplication that comes with it) every time we need to
deal with file types.

Given the above I'm in favour of moving forward with your approach.  One could
rightly argue the macros make the code harder to read but given the
alternatives, it seems to be the best solution.

Mathieu   

[1]. https://bit.ly/2Rpmb4E
[2]. https://elixir.bootlin.com/linux/v5.5-rc6/source/arch/mips/kernel/elf.c#L75
> 
> Clément
> 
> > 
> > Thanks,
> > Mathieu
> > 
> >> --
> >> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v2] remoteproc: Add elf64 support in elf loader
  2020-01-24 21:58         ` Mathieu Poirier
@ 2020-01-27  8:33           ` Clément Leger
  2020-01-28 17:14             ` Mathieu Poirier
  0 siblings, 1 reply; 76+ messages in thread
From: Clément Leger @ 2020-01-27  8:33 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

Hi Mathieu, 

Thanks for your thorough review. While thinking about it,there is at least
another option which would consist in splitting all elf specific functions into
a separate .h file and then include it in a .c to "instantiate" the functions
with correct types. For instance, it would look like this:

#define ELF_TYPE 32
#include "elf_functions.h"
#undef ELF_TYPE
#define ELF_TYPE 64
#include "elf_functions.h"

pros: More readable and type-checking ok
cons: A bit hackish

I would say this might be a better optino than my current patch.
However, I'm not sure this kind of thing of well accepted in the kernel.

Clément

----- On 24 Jan, 2020, at 22:58, Mathieu Poirier mathieu.poirier@linaro.org wrote:

> On Fri, Jan 24, 2020 at 09:24:16AM +0100, Clément Leger wrote:
>> Hi Mathieu,
>> 
>> ----- On 24 Jan, 2020, at 01:53, Mathieu Poirier mathieu.poirier@linaro.org
>> wrote:
>> 
>> > Hi Clement,
>> > 
>> > On Fri, Oct 04, 2019 at 08:42:20PM +0200, Clement Leger wrote:
>> >> elf32 and elf64 mainly differ by their types. In order to avoid
>> >> copy/pasting the whole loader code, generate static inline functions
>> >> which will access values according to the elf class. It allows to keep a
>> >> common loader basis.
>> >> In order to accomodate both elf types sizes, the maximum size for a
>> >> elf header member is chosen using the maximum value of both elf class.
>> >> 
>> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> >> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
>> >> ---
>> >> Changes in v2:
>> >>  - Add ELF64 support in documentation
>> >>
>> > 
>> > First and foremost please address the complaints from checkpatch.
>> 
>> I fixed one typo in accommodate. The other checkpatch complaint is
>> about missing parenthesis for macros with complex values which is
>> unfortunately not possible since I'm generating inline functions.
>> 
>> Did you have any other one ?
>> 
>> > 
>> >> ---
>> >>  Documentation/remoteproc.txt               |   2 +-
>> >>  drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
>> >>  drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
>> >>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
>> >>  drivers/remoteproc/st_remoteproc.c         |   2 +-
>> >>  include/linux/remoteproc.h                 |   4 +-
>> >>  6 files changed, 157 insertions(+), 57 deletions(-)
>> >>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
>> >> 
>> >> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
>> >> index 77fb03acdbb4..bf4f0c41ec4e 100644
>> >> --- a/Documentation/remoteproc.txt
>> >> +++ b/Documentation/remoteproc.txt
>> >> @@ -230,7 +230,7 @@ in the used rings.
>> >>  Binary Firmware Structure
>> >>  =========================
>> >>  
>> >> -At this point remoteproc only supports ELF32 firmware binaries. However,
>> >> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
>> >>  it is quite expected that other platforms/devices which we'd want to
>> >>  support with this framework will be based on different binary formats.
>> >>  
>> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
>> >> b/drivers/remoteproc/remoteproc_elf_loader.c
>> >> index b17d72ec8603..6a2d31d6092c 100644
>> >> --- a/drivers/remoteproc/remoteproc_elf_loader.c
>> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
>> >> @@ -31,6 +31,7 @@
>> >>  #include <linux/elf.h>
>> >>  
>> >>  #include "remoteproc_internal.h"
>> >> +#include "remoteproc_elf_loader.h"
>> >>  
>> >>  /**
>> >>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
>> >> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> >> firmware *fw)
>> >>  {
>> >>  	const char *name = rproc->firmware;
>> >>  	struct device *dev = &rproc->dev;
>> >> +	/*
>> >> +	 * Elf files are beginning with the same structure. Thus, to simplify
>> >> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
>> >> +	 * elf32.
>> >> +	 */
>> >>  	struct elf32_hdr *ehdr;
>> >> +	u32 elf_shdr_size;
>> >> +	u64 phoff, shoff;
>> >>  	char class;
>> >> +	u16 phnum;
>> >>  
>> >>  	if (!fw) {
>> >>  		dev_err(dev, "failed to load %s\n", name);
>> >> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> >> firmware *fw)
>> > 
>> > In the current code [1] fw->size is compared against the size of an elf32_hdr.
>> > If support for elf64 is added that code needs to be modified to check for the
>> > right header size using fw_elf_get_class().
>> 
>> Actually, the elf32 header is smaller than the elf64 one so this check is
>> there to ensure that we have at least a minimal elf header (elf32).
>> And since the class is derived from the header, you better have to check the
>> header size before accessing it.
>> 
>> To be more clear, I could compare it to min(sizeof(struct elf32_hdr),
>> sizeof(struct elf64_hdr)) or add a comment at least stating that since
>> elf header contains the same fields for identification, we can use the
>> elf32 one.
>> 
>> > 
>> > [1]
>> > https://elixir.bootlin.com/linux/v5.5-rc6/source/drivers/remoteproc/remoteproc_elf_loader.c#L46
>> > 
>> >>  
>> >>  	ehdr = (struct elf32_hdr *)fw->data;
>> >>  
>> >> -	/* We only support ELF32 at this point */
>> >> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> >> +		dev_err(dev, "Image is corrupted (bad magic)\n");
>> >> +		return -EINVAL;
>> >> +	}
>> >> +
>> > 
>> > Is there a reason to move this check up where?  If not please bring it back to
>> > its original location, that is below:
>> > 
>> > "if (fw->size < ehdr->e_shoff + sizeof(structelf32_shdr))"
>> > 
>> 
>> This is because the new check for size uses elf_shdr_size which is derived from
>> the class. And since the class is extracted from the elf header, we need to
>> check
>> the header to be correct first.
>> 
>> >>  	class = ehdr->e_ident[EI_CLASS];
>> >> -	if (class != ELFCLASS32) {
>> >> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
>> >>  		dev_err(dev, "Unsupported class: %d\n", class);
>> >>  		return -EINVAL;
>> >>  	}
>> >> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> >> firmware *fw)
>> >>  		return -EINVAL;
>> >>  	}
>> >>  
>> >> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
>> >> -		dev_err(dev, "Image is too small\n");
>> >> -		return -EINVAL;
>> >> -	}
>> >> +	phoff = elf_hdr_e_phoff(class, fw->data);
>> >> +	shoff = elf_hdr_e_shoff(class, fw->data);
>> >> +	phnum =  elf_hdr_e_phnum(class, fw->data);
>> >> +	elf_shdr_size = elf_size_of_shdr(class);
>> >>  
>> >> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> >> -		dev_err(dev, "Image is corrupted (bad magic)\n");
>> >> +	if (fw->size < shoff + elf_shdr_size) {
>> >> +		dev_err(dev, "Image is too small\n");
>> >>  		return -EINVAL;
>> >>  	}
>> >>  
>> >> -	if (ehdr->e_phnum == 0) {
>> >> +	if (phnum == 0) {
>> >>  		dev_err(dev, "No loadable segments\n");
>> >>  		return -EINVAL;
>> >>  	}
>> >>  
>> >> -	if (ehdr->e_phoff > fw->size) {
>> >> +	if (phoff > fw->size) {
>> >>  		dev_err(dev, "Firmware size is too small\n");
>> >>  		return -EINVAL;
>> >>  	}
>> >>  
>> >> +	dev_dbg(dev, "Firmware is an elf%d file\n",
>> >> +		class == ELFCLASS32 ? 32 : 64);
>> >> +
>> > 
>> > Yes, this is useful.
>> > 
>> >>  	return 0;
>> >>  }
>> >>  EXPORT_SYMBOL(rproc_elf_sanity_check);
>> >> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>> >>   * Note that the boot address is not a configurable property of all remote
>> >>   * processors. Some will always boot at a specific hard-coded address.
>> >>   */
>> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> >>  {
>> >> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
>> >> -
>> >> -	return ehdr->e_entry;
>> >> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
>> >>  }
>> >>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>> >>  
>> >> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>> >>  {
>> >>  	struct device *dev = &rproc->dev;
>> >> -	struct elf32_hdr *ehdr;
>> >> -	struct elf32_phdr *phdr;
>> >> +	const void *ehdr, *phdr;
>> >>  	int i, ret = 0;
>> >> +	u16 phnum;
>> >>  	const u8 *elf_data = fw->data;
>> >> +	u8 class = fw_elf_get_class(fw);
>> >> +	u32 elf_phdr_size = elf_size_of_phdr(class);
>> >>  
>> >> -	ehdr = (struct elf32_hdr *)elf_data;
>> >> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
>> >> +	ehdr = elf_data;
>> >> +	phnum = elf_hdr_e_phnum(class, ehdr);
>> >> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
>> >>  
>> >>  	/* go through the available ELF segments */
>> >> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
>> >> -		u32 da = phdr->p_paddr;
>> >> -		u32 memsz = phdr->p_memsz;
>> >> -		u32 filesz = phdr->p_filesz;
>> >> -		u32 offset = phdr->p_offset;
>> >> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
>> >> +		u64 da = elf_phdr_p_paddr(class, phdr);
>> >> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
>> >> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
>> >> +		u64 offset = elf_phdr_p_offset(class, phdr);
>> >> +		u32 type = elf_phdr_p_type(class, phdr);
>> >>  		void *ptr;
>> >>  
>> >> -		if (phdr->p_type != PT_LOAD)
>> >> +		if (type != PT_LOAD)
>> >>  			continue;
>> >>  
>> >> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
>> >> -			phdr->p_type, da, memsz, filesz);
>> >> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
>> >> +			type, da, memsz, filesz);
>> >>  
>> >>  		if (filesz > memsz) {
>> >> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
>> >> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
>> >>  				filesz, memsz);
>> >>  			ret = -EINVAL;
>> >>  			break;
>> >>  		}
>> >>  
>> >>  		if (offset + filesz > fw->size) {
>> >> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
>> >> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
>> >>  				offset + filesz, fw->size);
>> >>  			ret = -EINVAL;
>> >>  			break;
>> >> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> >> struct firmware *fw)
>> >>  		/* grab the kernel address for this device address */
>> >>  		ptr = rproc_da_to_va(rproc, da, memsz);
>> >>  		if (!ptr) {
>> >> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
>> >> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
>> >> +				memsz);
>> >>  			ret = -EINVAL;
>> >>  			break;
>> >>  		}
>> >>  
>> >>  		/* put the segment where the remote processor expects it */
>> >> -		if (phdr->p_filesz)
>> >> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
>> >> +		if (filesz)
>> >> +			memcpy(ptr, elf_data + offset, filesz);
>> >>  
>> >>  		/*
>> >>  		 * Zero out remaining memory for this segment.
>> >> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> >> struct firmware *fw)
>> >>  }
>> >>  EXPORT_SYMBOL(rproc_elf_load_segments);
>> >>  
>> >> -static struct elf32_shdr *
>> >> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>> >> +static const void *
>> > 
>> > Not sure I understand the "const" - was the compiler complaining?
>> 
>> It's actually caused by the fact I used a const void* shdr in the caller.
>> I will check if this is mandatory.
>> 
>> > 
>> >> +find_table(struct device *dev, const struct firmware *fw)
>> >>  {
>> >> -	struct elf32_shdr *shdr;
>> >> +	const void *shdr, *name_table_shdr;
>> >>  	int i;
>> >>  	const char *name_table;
>> >>  	struct resource_table *table = NULL;
>> >> -	const u8 *elf_data = (void *)ehdr;
>> >> +	const u8 *elf_data = (void *)fw->data;
>> >> +	u8 class = fw_elf_get_class(fw);
>> >> +	size_t fw_size = fw->size;
>> >> +	const void *ehdr = elf_data;
>> >> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
>> >> +	u32 elf_shdr_size = elf_size_of_shdr(class);
>> >> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
>> >>  
>> >>  	/* look for the resource table and handle it */
>> >> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
>> >> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
>> >> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
>> >> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
>> >> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
>> > 
>> > It took me a while but I figured out what is happening here.  To save me (and
>> > other people) from going through the same mental process every time I look at
>> > this code, please add a comment for each of the above 3 lines.
>> 
>> Indeed.
>> 
>> > 
>> >>  
>> >> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
>> >> -		u32 size = shdr->sh_size;
>> >> -		u32 offset = shdr->sh_offset;
>> >> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
>> >> +		u64 size = elf_shdr_sh_size(class, shdr);
>> >> +		u64 offset = elf_shdr_sh_offset(class, shdr);
>> >> +		u32 name = elf_shdr_sh_name(class, shdr);
>> >>  
>> >> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
>> >> +		if (strcmp(name_table + name, ".resource_table"))
>> >>  			continue;
>> >>  
>> >>  		table = (struct resource_table *)(elf_data + offset);
>> >> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
>> >> size_t fw_size)
>> >>   */
>> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>> >>  {
>> >> -	struct elf32_hdr *ehdr;
>> >> -	struct elf32_shdr *shdr;
>> >> +	const void *shdr;
>> >>  	struct device *dev = &rproc->dev;
>> >>  	struct resource_table *table = NULL;
>> >>  	const u8 *elf_data = fw->data;
>> >>  	size_t tablesz;
>> >> +	u8 class = fw_elf_get_class(fw);
>> >> +	u64 sh_offset;
>> >>  
>> >> -	ehdr = (struct elf32_hdr *)elf_data;
>> >> -
>> >> -	shdr = find_table(dev, ehdr, fw->size);
>> >> +	shdr = find_table(dev, fw);
>> >>  	if (!shdr)
>> >>  		return -EINVAL;
>> >>  
>> >> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
>> >> -	tablesz = shdr->sh_size;
>> >> +	sh_offset = elf_shdr_sh_offset(class, shdr);
>> >> +	table = (struct resource_table *)(elf_data + sh_offset);
>> >> +	tablesz = elf_shdr_sh_size(class, shdr);
>> >>  
>> >>  	/*
>> >>  	 * Create a copy of the resource table. When a virtio device starts
>> >> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
>> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>> >>  						       const struct firmware *fw)
>> >>  {
>> >> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> >> -	struct elf32_shdr *shdr;
>> >> +	const void *shdr;
>> >> +	u64 sh_addr, sh_size;
>> >> +	u8 class = fw_elf_get_class(fw);
>> >>  
>> >> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
>> >> +	shdr = find_table(&rproc->dev, fw);
>> >>  	if (!shdr)
>> >>  		return NULL;
>> >>  
>> >> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
>> >> +	sh_addr = elf_shdr_sh_addr(class, shdr);
>> >> +	sh_size = elf_shdr_sh_size(class, shdr);
>> >> +
>> >> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
>> > 
>> > The prototype for the above is as follow:
>> > 
>> > void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> > 
>> > But sh_size is a u64, which will cause problem that are hard to debug.  I think
>> > it is better to move 'len' to an 8 byte type along with the refactoring of the
>> > existing code that is implied.  I suggest to split this work in a preparatory
>> > patch (that will still be part of this set).
>> 
>> Nice catch ! I will do that.
>> 
>> > 
>> >>  }
>> >>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
>> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
>> >> b/drivers/remoteproc/remoteproc_elf_loader.h
>> >> new file mode 100644
>> >> index 000000000000..fac3565734f9
>> >> --- /dev/null
>> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
>> >> @@ -0,0 +1,69 @@
>> >> +/* SPDX-License-Identifier: GPL-2.0 */
>> >> +/*
>> >> + * Remote processor elf loader defines
>> >> + *
>> >> + * Copyright (C) 2019 Kalray, Inc.
>> >> + */
>> >> +
>> >> +#ifndef REMOTEPROC_ELF_LOADER_H
>> >> +#define REMOTEPROC_ELF_LOADER_H
>> >> +
>> >> +#include <linux/elf.h>
>> >> +#include <linux/types.h>
>> >> +
>> >> +/**
>> >> + * fw_elf_get_class - Get elf class
>> >> + * @fw: the ELF firmware image
>> >> + *
>> >> + * Note that we use and elf32_hdr to access the class since the start of the
>> >> + * struct is the same for both elf class
>> >> + *
>> >> + * Return: elf class of the firmware
>> >> + */
>> >> +static inline u8 fw_elf_get_class(const struct firmware *fw)
>> >> +{
>> >> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> >> +
>> >> +	return ehdr->e_ident[EI_CLASS];
>> >> +}
>> >> +
>> >> +#define ELF_GET_FIELD(__s, __field, __type) \
>> >> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
>> >> +{ \
>> >> +	if (class == ELFCLASS32) \
>> >> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
>> >> +	else \
>> >> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
>> >> +}
>> >> +
>> >> +ELF_GET_FIELD(hdr, e_entry, u64)
>> >> +ELF_GET_FIELD(hdr, e_phnum, u16)
>> >> +ELF_GET_FIELD(hdr, e_shnum, u16)
>> >> +ELF_GET_FIELD(hdr, e_phoff, u64)
>> >> +ELF_GET_FIELD(hdr, e_shoff, u64)
>> >> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
>> >> +
>> >> +ELF_GET_FIELD(phdr, p_paddr, u64)
>> >> +ELF_GET_FIELD(phdr, p_filesz, u64)
>> >> +ELF_GET_FIELD(phdr, p_memsz, u64)
>> >> +ELF_GET_FIELD(phdr, p_type, u32)
>> >> +ELF_GET_FIELD(phdr, p_offset, u64)
>> >> +
>> >> +ELF_GET_FIELD(shdr, sh_size, u64)
>> >> +ELF_GET_FIELD(shdr, sh_offset, u64)
>> >> +ELF_GET_FIELD(shdr, sh_name, u32)
>> >> +ELF_GET_FIELD(shdr, sh_addr, u64)
>> > 
>> > I like how you did this.
>> > 
>> >> +
>> >> +#define ELF_STRUCT_SIZE(__s) \
>> >> +static inline unsigned long elf_size_of_##__s(u8 class) \
>> >> +{ \
>> >> +	if (class == ELFCLASS32)\
>> >> +		return sizeof(struct elf32_##__s); \
>> >> +	else \
>> >> +		return sizeof(struct elf64_##__s); \
>> >> +}
>> >> +
>> >> +ELF_STRUCT_SIZE(shdr)
>> >> +ELF_STRUCT_SIZE(phdr)
>> >> +
>> >> +#endif /* REMOTEPROC_ELF_LOADER_H */
>> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> >> b/drivers/remoteproc/remoteproc_internal.h
>> >> index 45ff76a06c72..4ef745e3a1bc 100644
>> >> --- a/drivers/remoteproc/remoteproc_internal.h
>> >> +++ b/drivers/remoteproc/remoteproc_internal.h
>> >> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>> >>  int rproc_trigger_recovery(struct rproc *rproc);
>> >>  
>> >>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
>> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>> >> diff --git a/drivers/remoteproc/st_remoteproc.c
>> >> b/drivers/remoteproc/st_remoteproc.c
>> >> index 51049d17b1e5..e23abd8a96b0 100644
>> >> --- a/drivers/remoteproc/st_remoteproc.c
>> >> +++ b/drivers/remoteproc/st_remoteproc.c
>> >> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
>> >>  		}
>> >>  	}
>> >>  
>> >> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
>> >> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>> >>  
>> >>  	return 0;
>> >>  
>> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> >> index 04d04709f2bd..512de9a2590c 100644
>> >> --- a/include/linux/remoteproc.h
>> >> +++ b/include/linux/remoteproc.h
>> >> @@ -362,7 +362,7 @@ struct rproc_ops {
>> >>  				struct rproc *rproc, const struct firmware *fw);
>> >>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
>> >>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
>> >> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> >> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> >>  };
>> >>  
>> >>  /**
>> >> @@ -478,7 +478,7 @@ struct rproc {
>> >>  	int num_traces;
>> >>  	struct list_head carveouts;
>> >>  	struct list_head mappings;
>> >> -	u32 bootaddr;
>> >> +	u64 bootaddr;
>> >>  	struct list_head rvdevs;
>> >>  	struct list_head subdevs;
>> >>  	struct idr notifyids;
>> > 
>> > Please hold off before doing another respin of this patch.  While doing
>> > something completely different I noticed TI also did some work in this area.
>> > I'd like to take some time to look at their implementation and see if they carry
>> > features that haven't been included here.  I intend to do this tomorrow.
>> 
>> Ok,
>> 
>> Thanks for your review,
> 
> As promised I looked at what Suman had done on his side [1] to support 64-bit
> ELF
> files. His approach to offer the same functionality but for 64 bit in a new file
> is quick, simple and flexible.  On the flip side it introduces code duplication,
> something that is seriously frowned upon upstream.
> 
> I did some soul searching in the kernel code and found very little in terms of
> implementation that deals with both 32 and 64 bit ELF format.  The most
> convincing approach was set forth by the MIPS guys [2].  They too have decided
> to support both types in the same functions, but I don't see us adding an if()
> statement (and the code duplication that comes with it) every time we need to
> deal with file types.
> 
> Given the above I'm in favour of moving forward with your approach.  One could
> rightly argue the macros make the code harder to read but given the
> alternatives, it seems to be the best solution.
> 
> Mathieu
> 
> [1]. https://bit.ly/2Rpmb4E
> [2]. https://elixir.bootlin.com/linux/v5.5-rc6/source/arch/mips/kernel/elf.c#L75
>> 
>> Clément
>> 
>> > 
>> > Thanks,
>> > Mathieu
>> > 
>> >> --
> > >> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v2] remoteproc: Add elf64 support in elf loader
  2020-01-27  8:33           ` Clément Leger
@ 2020-01-28 17:14             ` Mathieu Poirier
  2020-01-29  8:55               ` Clément Leger
  0 siblings, 1 reply; 76+ messages in thread
From: Mathieu Poirier @ 2020-01-28 17:14 UTC (permalink / raw)
  To: Clément Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel,
	Arnaud Pouliquen, Loic PALLARDY, Suman Anna

On Mon, 27 Jan 2020 at 01:33, Clément Leger <cleger@kalray.eu> wrote:
>
> Hi Mathieu,
>
> Thanks for your thorough review. While thinking about it,there is at least
> another option which would consist in splitting all elf specific functions into
> a separate .h file and then include it in a .c to "instantiate" the functions
> with correct types. For instance, it would look like this:
>
> #define ELF_TYPE 32
> #include "elf_functions.h"
> #undef ELF_TYPE
> #define ELF_TYPE 64
> #include "elf_functions.h"
>
> pros: More readable and type-checking ok
> cons: A bit hackish
>
> I would say this might be a better optino than my current patch.
> However, I'm not sure this kind of thing of well accepted in the kernel.

I won't claim to fully understand your suggestion above, but if it is
suspicious enough to look hackish to you than it will probably look
hackish to other people.  Nonetheless there might be a case for
exception if the approach yields clear advantages.  Can you point me
to an example somewhere in the kernel code where something similar
would have been done?

>
> Clément
>
> ----- On 24 Jan, 2020, at 22:58, Mathieu Poirier mathieu.poirier@linaro.org wrote:
>
> > On Fri, Jan 24, 2020 at 09:24:16AM +0100, Clément Leger wrote:
> >> Hi Mathieu,
> >>
> >> ----- On 24 Jan, 2020, at 01:53, Mathieu Poirier mathieu.poirier@linaro.org
> >> wrote:
> >>
> >> > Hi Clement,
> >> >
> >> > On Fri, Oct 04, 2019 at 08:42:20PM +0200, Clement Leger wrote:
> >> >> elf32 and elf64 mainly differ by their types. In order to avoid
> >> >> copy/pasting the whole loader code, generate static inline functions
> >> >> which will access values according to the elf class. It allows to keep a
> >> >> common loader basis.
> >> >> In order to accomodate both elf types sizes, the maximum size for a
> >> >> elf header member is chosen using the maximum value of both elf class.
> >> >>
> >> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
> >> >> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
> >> >> ---
> >> >> Changes in v2:
> >> >>  - Add ELF64 support in documentation
> >> >>
> >> >
> >> > First and foremost please address the complaints from checkpatch.
> >>
> >> I fixed one typo in accommodate. The other checkpatch complaint is
> >> about missing parenthesis for macros with complex values which is
> >> unfortunately not possible since I'm generating inline functions.
> >>
> >> Did you have any other one ?
> >>
> >> >
> >> >> ---
> >> >>  Documentation/remoteproc.txt               |   2 +-
> >> >>  drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
> >> >>  drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
> >> >>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
> >> >>  drivers/remoteproc/st_remoteproc.c         |   2 +-
> >> >>  include/linux/remoteproc.h                 |   4 +-
> >> >>  6 files changed, 157 insertions(+), 57 deletions(-)
> >> >>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
> >> >>
> >> >> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
> >> >> index 77fb03acdbb4..bf4f0c41ec4e 100644
> >> >> --- a/Documentation/remoteproc.txt
> >> >> +++ b/Documentation/remoteproc.txt
> >> >> @@ -230,7 +230,7 @@ in the used rings.
> >> >>  Binary Firmware Structure
> >> >>  =========================
> >> >>
> >> >> -At this point remoteproc only supports ELF32 firmware binaries. However,
> >> >> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
> >> >>  it is quite expected that other platforms/devices which we'd want to
> >> >>  support with this framework will be based on different binary formats.
> >> >>
> >> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
> >> >> b/drivers/remoteproc/remoteproc_elf_loader.c
> >> >> index b17d72ec8603..6a2d31d6092c 100644
> >> >> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> >> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> >> >> @@ -31,6 +31,7 @@
> >> >>  #include <linux/elf.h>
> >> >>
> >> >>  #include "remoteproc_internal.h"
> >> >> +#include "remoteproc_elf_loader.h"
> >> >>
> >> >>  /**
> >> >>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> >> >> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> >> firmware *fw)
> >> >>  {
> >> >>   const char *name = rproc->firmware;
> >> >>   struct device *dev = &rproc->dev;
> >> >> + /*
> >> >> +  * Elf files are beginning with the same structure. Thus, to simplify
> >> >> +  * header parsing, we can use the elf32_hdr one for both elf64 and
> >> >> +  * elf32.
> >> >> +  */
> >> >>   struct elf32_hdr *ehdr;
> >> >> + u32 elf_shdr_size;
> >> >> + u64 phoff, shoff;
> >> >>   char class;
> >> >> + u16 phnum;
> >> >>
> >> >>   if (!fw) {
> >> >>           dev_err(dev, "failed to load %s\n", name);
> >> >> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> >> firmware *fw)
> >> >
> >> > In the current code [1] fw->size is compared against the size of an elf32_hdr.
> >> > If support for elf64 is added that code needs to be modified to check for the
> >> > right header size using fw_elf_get_class().
> >>
> >> Actually, the elf32 header is smaller than the elf64 one so this check is
> >> there to ensure that we have at least a minimal elf header (elf32).
> >> And since the class is derived from the header, you better have to check the
> >> header size before accessing it.
> >>
> >> To be more clear, I could compare it to min(sizeof(struct elf32_hdr),
> >> sizeof(struct elf64_hdr)) or add a comment at least stating that since
> >> elf header contains the same fields for identification, we can use the
> >> elf32 one.
> >>
> >> >
> >> > [1]
> >> > https://elixir.bootlin.com/linux/v5.5-rc6/source/drivers/remoteproc/remoteproc_elf_loader.c#L46
> >> >
> >> >>
> >> >>   ehdr = (struct elf32_hdr *)fw->data;
> >> >>
> >> >> - /* We only support ELF32 at this point */
> >> >> + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> >> >> +         dev_err(dev, "Image is corrupted (bad magic)\n");
> >> >> +         return -EINVAL;
> >> >> + }
> >> >> +
> >> >
> >> > Is there a reason to move this check up where?  If not please bring it back to
> >> > its original location, that is below:
> >> >
> >> > "if (fw->size < ehdr->e_shoff + sizeof(structelf32_shdr))"
> >> >
> >>
> >> This is because the new check for size uses elf_shdr_size which is derived from
> >> the class. And since the class is extracted from the elf header, we need to
> >> check
> >> the header to be correct first.
> >>
> >> >>   class = ehdr->e_ident[EI_CLASS];
> >> >> - if (class != ELFCLASS32) {
> >> >> + if (class != ELFCLASS32 && class != ELFCLASS64) {
> >> >>           dev_err(dev, "Unsupported class: %d\n", class);
> >> >>           return -EINVAL;
> >> >>   }
> >> >> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> >> firmware *fw)
> >> >>           return -EINVAL;
> >> >>   }
> >> >>
> >> >> - if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
> >> >> -         dev_err(dev, "Image is too small\n");
> >> >> -         return -EINVAL;
> >> >> - }
> >> >> + phoff = elf_hdr_e_phoff(class, fw->data);
> >> >> + shoff = elf_hdr_e_shoff(class, fw->data);
> >> >> + phnum =  elf_hdr_e_phnum(class, fw->data);
> >> >> + elf_shdr_size = elf_size_of_shdr(class);
> >> >>
> >> >> - if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> >> >> -         dev_err(dev, "Image is corrupted (bad magic)\n");
> >> >> + if (fw->size < shoff + elf_shdr_size) {
> >> >> +         dev_err(dev, "Image is too small\n");
> >> >>           return -EINVAL;
> >> >>   }
> >> >>
> >> >> - if (ehdr->e_phnum == 0) {
> >> >> + if (phnum == 0) {
> >> >>           dev_err(dev, "No loadable segments\n");
> >> >>           return -EINVAL;
> >> >>   }
> >> >>
> >> >> - if (ehdr->e_phoff > fw->size) {
> >> >> + if (phoff > fw->size) {
> >> >>           dev_err(dev, "Firmware size is too small\n");
> >> >>           return -EINVAL;
> >> >>   }
> >> >>
> >> >> + dev_dbg(dev, "Firmware is an elf%d file\n",
> >> >> +         class == ELFCLASS32 ? 32 : 64);
> >> >> +
> >> >
> >> > Yes, this is useful.
> >> >
> >> >>   return 0;
> >> >>  }
> >> >>  EXPORT_SYMBOL(rproc_elf_sanity_check);
> >> >> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
> >> >>   * Note that the boot address is not a configurable property of all remote
> >> >>   * processors. Some will always boot at a specific hard-coded address.
> >> >>   */
> >> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> >> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> >> >>  {
> >> >> - struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
> >> >> -
> >> >> - return ehdr->e_entry;
> >> >> + return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
> >> >>  }
> >> >>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> >> >>
> >> >> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> >> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
> >> >>  {
> >> >>   struct device *dev = &rproc->dev;
> >> >> - struct elf32_hdr *ehdr;
> >> >> - struct elf32_phdr *phdr;
> >> >> + const void *ehdr, *phdr;
> >> >>   int i, ret = 0;
> >> >> + u16 phnum;
> >> >>   const u8 *elf_data = fw->data;
> >> >> + u8 class = fw_elf_get_class(fw);
> >> >> + u32 elf_phdr_size = elf_size_of_phdr(class);
> >> >>
> >> >> - ehdr = (struct elf32_hdr *)elf_data;
> >> >> - phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> >> >> + ehdr = elf_data;
> >> >> + phnum = elf_hdr_e_phnum(class, ehdr);
> >> >> + phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
> >> >>
> >> >>   /* go through the available ELF segments */
> >> >> - for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> >> >> -         u32 da = phdr->p_paddr;
> >> >> -         u32 memsz = phdr->p_memsz;
> >> >> -         u32 filesz = phdr->p_filesz;
> >> >> -         u32 offset = phdr->p_offset;
> >> >> + for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
> >> >> +         u64 da = elf_phdr_p_paddr(class, phdr);
> >> >> +         u64 memsz = elf_phdr_p_memsz(class, phdr);
> >> >> +         u64 filesz = elf_phdr_p_filesz(class, phdr);
> >> >> +         u64 offset = elf_phdr_p_offset(class, phdr);
> >> >> +         u32 type = elf_phdr_p_type(class, phdr);
> >> >>           void *ptr;
> >> >>
> >> >> -         if (phdr->p_type != PT_LOAD)
> >> >> +         if (type != PT_LOAD)
> >> >>                   continue;
> >> >>
> >> >> -         dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
> >> >> -                 phdr->p_type, da, memsz, filesz);
> >> >> +         dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
> >> >> +                 type, da, memsz, filesz);
> >> >>
> >> >>           if (filesz > memsz) {
> >> >> -                 dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
> >> >> +                 dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
> >> >>                           filesz, memsz);
> >> >>                   ret = -EINVAL;
> >> >>                   break;
> >> >>           }
> >> >>
> >> >>           if (offset + filesz > fw->size) {
> >> >> -                 dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
> >> >> +                 dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
> >> >>                           offset + filesz, fw->size);
> >> >>                   ret = -EINVAL;
> >> >>                   break;
> >> >> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> >> >> struct firmware *fw)
> >> >>           /* grab the kernel address for this device address */
> >> >>           ptr = rproc_da_to_va(rproc, da, memsz);
> >> >>           if (!ptr) {
> >> >> -                 dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> >> >> +                 dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
> >> >> +                         memsz);
> >> >>                   ret = -EINVAL;
> >> >>                   break;
> >> >>           }
> >> >>
> >> >>           /* put the segment where the remote processor expects it */
> >> >> -         if (phdr->p_filesz)
> >> >> -                 memcpy(ptr, elf_data + phdr->p_offset, filesz);
> >> >> +         if (filesz)
> >> >> +                 memcpy(ptr, elf_data + offset, filesz);
> >> >>
> >> >>           /*
> >> >>            * Zero out remaining memory for this segment.
> >> >> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> >> >> struct firmware *fw)
> >> >>  }
> >> >>  EXPORT_SYMBOL(rproc_elf_load_segments);
> >> >>
> >> >> -static struct elf32_shdr *
> >> >> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> >> >> +static const void *
> >> >
> >> > Not sure I understand the "const" - was the compiler complaining?
> >>
> >> It's actually caused by the fact I used a const void* shdr in the caller.
> >> I will check if this is mandatory.
> >>
> >> >
> >> >> +find_table(struct device *dev, const struct firmware *fw)
> >> >>  {
> >> >> - struct elf32_shdr *shdr;
> >> >> + const void *shdr, *name_table_shdr;
> >> >>   int i;
> >> >>   const char *name_table;
> >> >>   struct resource_table *table = NULL;
> >> >> - const u8 *elf_data = (void *)ehdr;
> >> >> + const u8 *elf_data = (void *)fw->data;
> >> >> + u8 class = fw_elf_get_class(fw);
> >> >> + size_t fw_size = fw->size;
> >> >> + const void *ehdr = elf_data;
> >> >> + u16 shnum = elf_hdr_e_shnum(class, ehdr);
> >> >> + u32 elf_shdr_size = elf_size_of_shdr(class);
> >> >> + u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
> >> >>
> >> >>   /* look for the resource table and handle it */
> >> >> - shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> >> >> - name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
> >> >> + shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
> >> >> + name_table_shdr = shdr + (shstrndx * elf_shdr_size);
> >> >> + name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
> >> >
> >> > It took me a while but I figured out what is happening here.  To save me (and
> >> > other people) from going through the same mental process every time I look at
> >> > this code, please add a comment for each of the above 3 lines.
> >>
> >> Indeed.
> >>
> >> >
> >> >>
> >> >> - for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> >> >> -         u32 size = shdr->sh_size;
> >> >> -         u32 offset = shdr->sh_offset;
> >> >> + for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
> >> >> +         u64 size = elf_shdr_sh_size(class, shdr);
> >> >> +         u64 offset = elf_shdr_sh_offset(class, shdr);
> >> >> +         u32 name = elf_shdr_sh_name(class, shdr);
> >> >>
> >> >> -         if (strcmp(name_table + shdr->sh_name, ".resource_table"))
> >> >> +         if (strcmp(name_table + name, ".resource_table"))
> >> >>                   continue;
> >> >>
> >> >>           table = (struct resource_table *)(elf_data + offset);
> >> >> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
> >> >> size_t fw_size)
> >> >>   */
> >> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
> >> >>  {
> >> >> - struct elf32_hdr *ehdr;
> >> >> - struct elf32_shdr *shdr;
> >> >> + const void *shdr;
> >> >>   struct device *dev = &rproc->dev;
> >> >>   struct resource_table *table = NULL;
> >> >>   const u8 *elf_data = fw->data;
> >> >>   size_t tablesz;
> >> >> + u8 class = fw_elf_get_class(fw);
> >> >> + u64 sh_offset;
> >> >>
> >> >> - ehdr = (struct elf32_hdr *)elf_data;
> >> >> -
> >> >> - shdr = find_table(dev, ehdr, fw->size);
> >> >> + shdr = find_table(dev, fw);
> >> >>   if (!shdr)
> >> >>           return -EINVAL;
> >> >>
> >> >> - table = (struct resource_table *)(elf_data + shdr->sh_offset);
> >> >> - tablesz = shdr->sh_size;
> >> >> + sh_offset = elf_shdr_sh_offset(class, shdr);
> >> >> + table = (struct resource_table *)(elf_data + sh_offset);
> >> >> + tablesz = elf_shdr_sh_size(class, shdr);
> >> >>
> >> >>   /*
> >> >>    * Create a copy of the resource table. When a virtio device starts
> >> >> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
> >> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> >> >>                                                  const struct firmware *fw)
> >> >>  {
> >> >> - struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> >> >> - struct elf32_shdr *shdr;
> >> >> + const void *shdr;
> >> >> + u64 sh_addr, sh_size;
> >> >> + u8 class = fw_elf_get_class(fw);
> >> >>
> >> >> - shdr = find_table(&rproc->dev, ehdr, fw->size);
> >> >> + shdr = find_table(&rproc->dev, fw);
> >> >>   if (!shdr)
> >> >>           return NULL;
> >> >>
> >> >> - return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
> >> >> + sh_addr = elf_shdr_sh_addr(class, shdr);
> >> >> + sh_size = elf_shdr_sh_size(class, shdr);
> >> >> +
> >> >> + return rproc_da_to_va(rproc, sh_addr, sh_size);
> >> >
> >> > The prototype for the above is as follow:
> >> >
> >> > void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >
> >> > But sh_size is a u64, which will cause problem that are hard to debug.  I think
> >> > it is better to move 'len' to an 8 byte type along with the refactoring of the
> >> > existing code that is implied.  I suggest to split this work in a preparatory
> >> > patch (that will still be part of this set).
> >>
> >> Nice catch ! I will do that.
> >>
> >> >
> >> >>  }
> >> >>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> >> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
> >> >> b/drivers/remoteproc/remoteproc_elf_loader.h
> >> >> new file mode 100644
> >> >> index 000000000000..fac3565734f9
> >> >> --- /dev/null
> >> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
> >> >> @@ -0,0 +1,69 @@
> >> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> >> +/*
> >> >> + * Remote processor elf loader defines
> >> >> + *
> >> >> + * Copyright (C) 2019 Kalray, Inc.
> >> >> + */
> >> >> +
> >> >> +#ifndef REMOTEPROC_ELF_LOADER_H
> >> >> +#define REMOTEPROC_ELF_LOADER_H
> >> >> +
> >> >> +#include <linux/elf.h>
> >> >> +#include <linux/types.h>
> >> >> +
> >> >> +/**
> >> >> + * fw_elf_get_class - Get elf class
> >> >> + * @fw: the ELF firmware image
> >> >> + *
> >> >> + * Note that we use and elf32_hdr to access the class since the start of the
> >> >> + * struct is the same for both elf class
> >> >> + *
> >> >> + * Return: elf class of the firmware
> >> >> + */
> >> >> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> >> >> +{
> >> >> + struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> >> >> +
> >> >> + return ehdr->e_ident[EI_CLASS];
> >> >> +}
> >> >> +
> >> >> +#define ELF_GET_FIELD(__s, __field, __type) \
> >> >> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
> >> >> +{ \
> >> >> + if (class == ELFCLASS32) \
> >> >> +         return (__type) ((const struct elf32_##__s *) arg)->__field; \
> >> >> + else \
> >> >> +         return (__type) ((const struct elf64_##__s *) arg)->__field; \
> >> >> +}
> >> >> +
> >> >> +ELF_GET_FIELD(hdr, e_entry, u64)
> >> >> +ELF_GET_FIELD(hdr, e_phnum, u16)
> >> >> +ELF_GET_FIELD(hdr, e_shnum, u16)
> >> >> +ELF_GET_FIELD(hdr, e_phoff, u64)
> >> >> +ELF_GET_FIELD(hdr, e_shoff, u64)
> >> >> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
> >> >> +
> >> >> +ELF_GET_FIELD(phdr, p_paddr, u64)
> >> >> +ELF_GET_FIELD(phdr, p_filesz, u64)
> >> >> +ELF_GET_FIELD(phdr, p_memsz, u64)
> >> >> +ELF_GET_FIELD(phdr, p_type, u32)
> >> >> +ELF_GET_FIELD(phdr, p_offset, u64)
> >> >> +
> >> >> +ELF_GET_FIELD(shdr, sh_size, u64)
> >> >> +ELF_GET_FIELD(shdr, sh_offset, u64)
> >> >> +ELF_GET_FIELD(shdr, sh_name, u32)
> >> >> +ELF_GET_FIELD(shdr, sh_addr, u64)
> >> >
> >> > I like how you did this.
> >> >
> >> >> +
> >> >> +#define ELF_STRUCT_SIZE(__s) \
> >> >> +static inline unsigned long elf_size_of_##__s(u8 class) \
> >> >> +{ \
> >> >> + if (class == ELFCLASS32)\
> >> >> +         return sizeof(struct elf32_##__s); \
> >> >> + else \
> >> >> +         return sizeof(struct elf64_##__s); \
> >> >> +}
> >> >> +
> >> >> +ELF_STRUCT_SIZE(shdr)
> >> >> +ELF_STRUCT_SIZE(phdr)
> >> >> +
> >> >> +#endif /* REMOTEPROC_ELF_LOADER_H */
> >> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
> >> >> b/drivers/remoteproc/remoteproc_internal.h
> >> >> index 45ff76a06c72..4ef745e3a1bc 100644
> >> >> --- a/drivers/remoteproc/remoteproc_internal.h
> >> >> +++ b/drivers/remoteproc/remoteproc_internal.h
> >> >> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
> >> >>  int rproc_trigger_recovery(struct rproc *rproc);
> >> >>
> >> >>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> >> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
> >> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
> >> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> >> >> diff --git a/drivers/remoteproc/st_remoteproc.c
> >> >> b/drivers/remoteproc/st_remoteproc.c
> >> >> index 51049d17b1e5..e23abd8a96b0 100644
> >> >> --- a/drivers/remoteproc/st_remoteproc.c
> >> >> +++ b/drivers/remoteproc/st_remoteproc.c
> >> >> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
> >> >>           }
> >> >>   }
> >> >>
> >> >> - dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> >> >> + dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
> >> >>
> >> >>   return 0;
> >> >>
> >> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> >> >> index 04d04709f2bd..512de9a2590c 100644
> >> >> --- a/include/linux/remoteproc.h
> >> >> +++ b/include/linux/remoteproc.h
> >> >> @@ -362,7 +362,7 @@ struct rproc_ops {
> >> >>                           struct rproc *rproc, const struct firmware *fw);
> >> >>   int (*load)(struct rproc *rproc, const struct firmware *fw);
> >> >>   int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> >> >> - u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> >> >> + u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> >> >>  };
> >> >>
> >> >>  /**
> >> >> @@ -478,7 +478,7 @@ struct rproc {
> >> >>   int num_traces;
> >> >>   struct list_head carveouts;
> >> >>   struct list_head mappings;
> >> >> - u32 bootaddr;
> >> >> + u64 bootaddr;
> >> >>   struct list_head rvdevs;
> >> >>   struct list_head subdevs;
> >> >>   struct idr notifyids;
> >> >
> >> > Please hold off before doing another respin of this patch.  While doing
> >> > something completely different I noticed TI also did some work in this area.
> >> > I'd like to take some time to look at their implementation and see if they carry
> >> > features that haven't been included here.  I intend to do this tomorrow.
> >>
> >> Ok,
> >>
> >> Thanks for your review,
> >
> > As promised I looked at what Suman had done on his side [1] to support 64-bit
> > ELF
> > files. His approach to offer the same functionality but for 64 bit in a new file
> > is quick, simple and flexible.  On the flip side it introduces code duplication,
> > something that is seriously frowned upon upstream.
> >
> > I did some soul searching in the kernel code and found very little in terms of
> > implementation that deals with both 32 and 64 bit ELF format.  The most
> > convincing approach was set forth by the MIPS guys [2].  They too have decided
> > to support both types in the same functions, but I don't see us adding an if()
> > statement (and the code duplication that comes with it) every time we need to
> > deal with file types.
> >
> > Given the above I'm in favour of moving forward with your approach.  One could
> > rightly argue the macros make the code harder to read but given the
> > alternatives, it seems to be the best solution.
> >
> > Mathieu
> >
> > [1]. https://bit.ly/2Rpmb4E
> > [2]. https://elixir.bootlin.com/linux/v5.5-rc6/source/arch/mips/kernel/elf.c#L75
> >>
> >> Clément
> >>
> >> >
> >> > Thanks,
> >> > Mathieu
> >> >
> >> >> --
> > > >> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v2] remoteproc: Add elf64 support in elf loader
  2020-01-28 17:14             ` Mathieu Poirier
@ 2020-01-29  8:55               ` Clément Leger
  2020-01-29 16:30                 ` Mathieu Poirier
  0 siblings, 1 reply; 76+ messages in thread
From: Clément Leger @ 2020-01-29  8:55 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

Ok, here is the example to be more clear:

Content of elfxx_loader.h:

int elf##ELF_TYPE##_load(...) {
	struct elf##ELF_TYPE##_shdr *shdr = data;
	...
}

Then in elf_loader.c file:

#define ELF_TYPE 32
#include "elfxx_loader.h"
#undef ELF_TYPE
#define ELF_TYPE 64
#include "elfxx_loader.h"

int elf_load(...) {
	if (class == elf64)
		elf64_load(...);
	else
		elf32_load(...);
}

This is used for syscall_table.c in arch for instance.
A macro must be defined and then the ehader is included and
"generates" code.

#undef __SYSCALL
#define __SYSCALL(nr, call)	[nr] = (call),

void *sys_call_table[__NR_syscalls] = {
	[0 ... __NR_syscalls - 1] = sys_ni_syscall,
#include <asm/unistd.h>
};

Hope this shed some light on my suggestion.

Clément

----- On 28 Jan, 2020, at 18:14, Mathieu Poirier mathieu.poirier@linaro.org wrote:

> On Mon, 27 Jan 2020 at 01:33, Clément Leger <cleger@kalray.eu> wrote:
>>
>> Hi Mathieu,
>>
>> Thanks for your thorough review. While thinking about it,there is at least
>> another option which would consist in splitting all elf specific functions into
>> a separate .h file and then include it in a .c to "instantiate" the functions
>> with correct types. For instance, it would look like this:
>>
>> #define ELF_TYPE 32
>> #include "elf_functions.h"
>> #undef ELF_TYPE
>> #define ELF_TYPE 64
>> #include "elf_functions.h"
>>
>> pros: More readable and type-checking ok
>> cons: A bit hackish
>>
>> I would say this might be a better optino than my current patch.
>> However, I'm not sure this kind of thing of well accepted in the kernel.
> 
> I won't claim to fully understand your suggestion above, but if it is
> suspicious enough to look hackish to you than it will probably look
> hackish to other people.  Nonetheless there might be a case for
> exception if the approach yields clear advantages.  Can you point me
> to an example somewhere in the kernel code where something similar
> would have been done?
> 
>>
>> Clément
>>
>> ----- On 24 Jan, 2020, at 22:58, Mathieu Poirier mathieu.poirier@linaro.org
>> wrote:
>>
>> > On Fri, Jan 24, 2020 at 09:24:16AM +0100, Clément Leger wrote:
>> >> Hi Mathieu,
>> >>
>> >> ----- On 24 Jan, 2020, at 01:53, Mathieu Poirier mathieu.poirier@linaro.org
>> >> wrote:
>> >>
>> >> > Hi Clement,
>> >> >
>> >> > On Fri, Oct 04, 2019 at 08:42:20PM +0200, Clement Leger wrote:
>> >> >> elf32 and elf64 mainly differ by their types. In order to avoid
>> >> >> copy/pasting the whole loader code, generate static inline functions
>> >> >> which will access values according to the elf class. It allows to keep a
>> >> >> common loader basis.
>> >> >> In order to accomodate both elf types sizes, the maximum size for a
>> >> >> elf header member is chosen using the maximum value of both elf class.
>> >> >>
>> >> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> >> >> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
>> >> >> ---
>> >> >> Changes in v2:
>> >> >>  - Add ELF64 support in documentation
>> >> >>
>> >> >
>> >> > First and foremost please address the complaints from checkpatch.
>> >>
>> >> I fixed one typo in accommodate. The other checkpatch complaint is
>> >> about missing parenthesis for macros with complex values which is
>> >> unfortunately not possible since I'm generating inline functions.
>> >>
>> >> Did you have any other one ?
>> >>
>> >> >
>> >> >> ---
>> >> >>  Documentation/remoteproc.txt               |   2 +-
>> >> >>  drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
>> >> >>  drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
>> >> >>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
>> >> >>  drivers/remoteproc/st_remoteproc.c         |   2 +-
>> >> >>  include/linux/remoteproc.h                 |   4 +-
>> >> >>  6 files changed, 157 insertions(+), 57 deletions(-)
>> >> >>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
>> >> >>
>> >> >> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
>> >> >> index 77fb03acdbb4..bf4f0c41ec4e 100644
>> >> >> --- a/Documentation/remoteproc.txt
>> >> >> +++ b/Documentation/remoteproc.txt
>> >> >> @@ -230,7 +230,7 @@ in the used rings.
>> >> >>  Binary Firmware Structure
>> >> >>  =========================
>> >> >>
>> >> >> -At this point remoteproc only supports ELF32 firmware binaries. However,
>> >> >> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
>> >> >>  it is quite expected that other platforms/devices which we'd want to
>> >> >>  support with this framework will be based on different binary formats.
>> >> >>
>> >> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
>> >> >> b/drivers/remoteproc/remoteproc_elf_loader.c
>> >> >> index b17d72ec8603..6a2d31d6092c 100644
>> >> >> --- a/drivers/remoteproc/remoteproc_elf_loader.c
>> >> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
>> >> >> @@ -31,6 +31,7 @@
>> >> >>  #include <linux/elf.h>
>> >> >>
>> >> >>  #include "remoteproc_internal.h"
>> >> >> +#include "remoteproc_elf_loader.h"
>> >> >>
>> >> >>  /**
>> >> >>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
>> >> >> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> >> >> firmware *fw)
>> >> >>  {
>> >> >>   const char *name = rproc->firmware;
>> >> >>   struct device *dev = &rproc->dev;
>> >> >> + /*
>> >> >> +  * Elf files are beginning with the same structure. Thus, to simplify
>> >> >> +  * header parsing, we can use the elf32_hdr one for both elf64 and
>> >> >> +  * elf32.
>> >> >> +  */
>> >> >>   struct elf32_hdr *ehdr;
>> >> >> + u32 elf_shdr_size;
>> >> >> + u64 phoff, shoff;
>> >> >>   char class;
>> >> >> + u16 phnum;
>> >> >>
>> >> >>   if (!fw) {
>> >> >>           dev_err(dev, "failed to load %s\n", name);
>> >> >> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> >> >> firmware *fw)
>> >> >
>> >> > In the current code [1] fw->size is compared against the size of an elf32_hdr.
>> >> > If support for elf64 is added that code needs to be modified to check for the
>> >> > right header size using fw_elf_get_class().
>> >>
>> >> Actually, the elf32 header is smaller than the elf64 one so this check is
>> >> there to ensure that we have at least a minimal elf header (elf32).
>> >> And since the class is derived from the header, you better have to check the
>> >> header size before accessing it.
>> >>
>> >> To be more clear, I could compare it to min(sizeof(struct elf32_hdr),
>> >> sizeof(struct elf64_hdr)) or add a comment at least stating that since
>> >> elf header contains the same fields for identification, we can use the
>> >> elf32 one.
>> >>
>> >> >
>> >> > [1]
>> >> > https://elixir.bootlin.com/linux/v5.5-rc6/source/drivers/remoteproc/remoteproc_elf_loader.c#L46
>> >> >
>> >> >>
>> >> >>   ehdr = (struct elf32_hdr *)fw->data;
>> >> >>
>> >> >> - /* We only support ELF32 at this point */
>> >> >> + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> >> >> +         dev_err(dev, "Image is corrupted (bad magic)\n");
>> >> >> +         return -EINVAL;
>> >> >> + }
>> >> >> +
>> >> >
>> >> > Is there a reason to move this check up where?  If not please bring it back to
>> >> > its original location, that is below:
>> >> >
>> >> > "if (fw->size < ehdr->e_shoff + sizeof(structelf32_shdr))"
>> >> >
>> >>
>> >> This is because the new check for size uses elf_shdr_size which is derived from
>> >> the class. And since the class is extracted from the elf header, we need to
>> >> check
>> >> the header to be correct first.
>> >>
>> >> >>   class = ehdr->e_ident[EI_CLASS];
>> >> >> - if (class != ELFCLASS32) {
>> >> >> + if (class != ELFCLASS32 && class != ELFCLASS64) {
>> >> >>           dev_err(dev, "Unsupported class: %d\n", class);
>> >> >>           return -EINVAL;
>> >> >>   }
>> >> >> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> >> >> firmware *fw)
>> >> >>           return -EINVAL;
>> >> >>   }
>> >> >>
>> >> >> - if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
>> >> >> -         dev_err(dev, "Image is too small\n");
>> >> >> -         return -EINVAL;
>> >> >> - }
>> >> >> + phoff = elf_hdr_e_phoff(class, fw->data);
>> >> >> + shoff = elf_hdr_e_shoff(class, fw->data);
>> >> >> + phnum =  elf_hdr_e_phnum(class, fw->data);
>> >> >> + elf_shdr_size = elf_size_of_shdr(class);
>> >> >>
>> >> >> - if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> >> >> -         dev_err(dev, "Image is corrupted (bad magic)\n");
>> >> >> + if (fw->size < shoff + elf_shdr_size) {
>> >> >> +         dev_err(dev, "Image is too small\n");
>> >> >>           return -EINVAL;
>> >> >>   }
>> >> >>
>> >> >> - if (ehdr->e_phnum == 0) {
>> >> >> + if (phnum == 0) {
>> >> >>           dev_err(dev, "No loadable segments\n");
>> >> >>           return -EINVAL;
>> >> >>   }
>> >> >>
>> >> >> - if (ehdr->e_phoff > fw->size) {
>> >> >> + if (phoff > fw->size) {
>> >> >>           dev_err(dev, "Firmware size is too small\n");
>> >> >>           return -EINVAL;
>> >> >>   }
>> >> >>
>> >> >> + dev_dbg(dev, "Firmware is an elf%d file\n",
>> >> >> +         class == ELFCLASS32 ? 32 : 64);
>> >> >> +
>> >> >
>> >> > Yes, this is useful.
>> >> >
>> >> >>   return 0;
>> >> >>  }
>> >> >>  EXPORT_SYMBOL(rproc_elf_sanity_check);
>> >> >> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>> >> >>   * Note that the boot address is not a configurable property of all remote
>> >> >>   * processors. Some will always boot at a specific hard-coded address.
>> >> >>   */
>> >> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> >> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> >> >>  {
>> >> >> - struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
>> >> >> -
>> >> >> - return ehdr->e_entry;
>> >> >> + return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
>> >> >>  }
>> >> >>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>> >> >>
>> >> >> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>> >> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>> >> >>  {
>> >> >>   struct device *dev = &rproc->dev;
>> >> >> - struct elf32_hdr *ehdr;
>> >> >> - struct elf32_phdr *phdr;
>> >> >> + const void *ehdr, *phdr;
>> >> >>   int i, ret = 0;
>> >> >> + u16 phnum;
>> >> >>   const u8 *elf_data = fw->data;
>> >> >> + u8 class = fw_elf_get_class(fw);
>> >> >> + u32 elf_phdr_size = elf_size_of_phdr(class);
>> >> >>
>> >> >> - ehdr = (struct elf32_hdr *)elf_data;
>> >> >> - phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
>> >> >> + ehdr = elf_data;
>> >> >> + phnum = elf_hdr_e_phnum(class, ehdr);
>> >> >> + phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
>> >> >>
>> >> >>   /* go through the available ELF segments */
>> >> >> - for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
>> >> >> -         u32 da = phdr->p_paddr;
>> >> >> -         u32 memsz = phdr->p_memsz;
>> >> >> -         u32 filesz = phdr->p_filesz;
>> >> >> -         u32 offset = phdr->p_offset;
>> >> >> + for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
>> >> >> +         u64 da = elf_phdr_p_paddr(class, phdr);
>> >> >> +         u64 memsz = elf_phdr_p_memsz(class, phdr);
>> >> >> +         u64 filesz = elf_phdr_p_filesz(class, phdr);
>> >> >> +         u64 offset = elf_phdr_p_offset(class, phdr);
>> >> >> +         u32 type = elf_phdr_p_type(class, phdr);
>> >> >>           void *ptr;
>> >> >>
>> >> >> -         if (phdr->p_type != PT_LOAD)
>> >> >> +         if (type != PT_LOAD)
>> >> >>                   continue;
>> >> >>
>> >> >> -         dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
>> >> >> -                 phdr->p_type, da, memsz, filesz);
>> >> >> +         dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
>> >> >> +                 type, da, memsz, filesz);
>> >> >>
>> >> >>           if (filesz > memsz) {
>> >> >> -                 dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
>> >> >> +                 dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
>> >> >>                           filesz, memsz);
>> >> >>                   ret = -EINVAL;
>> >> >>                   break;
>> >> >>           }
>> >> >>
>> >> >>           if (offset + filesz > fw->size) {
>> >> >> -                 dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
>> >> >> +                 dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
>> >> >>                           offset + filesz, fw->size);
>> >> >>                   ret = -EINVAL;
>> >> >>                   break;
>> >> >> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> >> >> struct firmware *fw)
>> >> >>           /* grab the kernel address for this device address */
>> >> >>           ptr = rproc_da_to_va(rproc, da, memsz);
>> >> >>           if (!ptr) {
>> >> >> -                 dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
>> >> >> +                 dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
>> >> >> +                         memsz);
>> >> >>                   ret = -EINVAL;
>> >> >>                   break;
>> >> >>           }
>> >> >>
>> >> >>           /* put the segment where the remote processor expects it */
>> >> >> -         if (phdr->p_filesz)
>> >> >> -                 memcpy(ptr, elf_data + phdr->p_offset, filesz);
>> >> >> +         if (filesz)
>> >> >> +                 memcpy(ptr, elf_data + offset, filesz);
>> >> >>
>> >> >>           /*
>> >> >>            * Zero out remaining memory for this segment.
>> >> >> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> >> >> struct firmware *fw)
>> >> >>  }
>> >> >>  EXPORT_SYMBOL(rproc_elf_load_segments);
>> >> >>
>> >> >> -static struct elf32_shdr *
>> >> >> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>> >> >> +static const void *
>> >> >
>> >> > Not sure I understand the "const" - was the compiler complaining?
>> >>
>> >> It's actually caused by the fact I used a const void* shdr in the caller.
>> >> I will check if this is mandatory.
>> >>
>> >> >
>> >> >> +find_table(struct device *dev, const struct firmware *fw)
>> >> >>  {
>> >> >> - struct elf32_shdr *shdr;
>> >> >> + const void *shdr, *name_table_shdr;
>> >> >>   int i;
>> >> >>   const char *name_table;
>> >> >>   struct resource_table *table = NULL;
>> >> >> - const u8 *elf_data = (void *)ehdr;
>> >> >> + const u8 *elf_data = (void *)fw->data;
>> >> >> + u8 class = fw_elf_get_class(fw);
>> >> >> + size_t fw_size = fw->size;
>> >> >> + const void *ehdr = elf_data;
>> >> >> + u16 shnum = elf_hdr_e_shnum(class, ehdr);
>> >> >> + u32 elf_shdr_size = elf_size_of_shdr(class);
>> >> >> + u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
>> >> >>
>> >> >>   /* look for the resource table and handle it */
>> >> >> - shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
>> >> >> - name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
>> >> >> + shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
>> >> >> + name_table_shdr = shdr + (shstrndx * elf_shdr_size);
>> >> >> + name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
>> >> >
>> >> > It took me a while but I figured out what is happening here.  To save me (and
>> >> > other people) from going through the same mental process every time I look at
>> >> > this code, please add a comment for each of the above 3 lines.
>> >>
>> >> Indeed.
>> >>
>> >> >
>> >> >>
>> >> >> - for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
>> >> >> -         u32 size = shdr->sh_size;
>> >> >> -         u32 offset = shdr->sh_offset;
>> >> >> + for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
>> >> >> +         u64 size = elf_shdr_sh_size(class, shdr);
>> >> >> +         u64 offset = elf_shdr_sh_offset(class, shdr);
>> >> >> +         u32 name = elf_shdr_sh_name(class, shdr);
>> >> >>
>> >> >> -         if (strcmp(name_table + shdr->sh_name, ".resource_table"))
>> >> >> +         if (strcmp(name_table + name, ".resource_table"))
>> >> >>                   continue;
>> >> >>
>> >> >>           table = (struct resource_table *)(elf_data + offset);
>> >> >> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
>> >> >> size_t fw_size)
>> >> >>   */
>> >> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>> >> >>  {
>> >> >> - struct elf32_hdr *ehdr;
>> >> >> - struct elf32_shdr *shdr;
>> >> >> + const void *shdr;
>> >> >>   struct device *dev = &rproc->dev;
>> >> >>   struct resource_table *table = NULL;
>> >> >>   const u8 *elf_data = fw->data;
>> >> >>   size_t tablesz;
>> >> >> + u8 class = fw_elf_get_class(fw);
>> >> >> + u64 sh_offset;
>> >> >>
>> >> >> - ehdr = (struct elf32_hdr *)elf_data;
>> >> >> -
>> >> >> - shdr = find_table(dev, ehdr, fw->size);
>> >> >> + shdr = find_table(dev, fw);
>> >> >>   if (!shdr)
>> >> >>           return -EINVAL;
>> >> >>
>> >> >> - table = (struct resource_table *)(elf_data + shdr->sh_offset);
>> >> >> - tablesz = shdr->sh_size;
>> >> >> + sh_offset = elf_shdr_sh_offset(class, shdr);
>> >> >> + table = (struct resource_table *)(elf_data + sh_offset);
>> >> >> + tablesz = elf_shdr_sh_size(class, shdr);
>> >> >>
>> >> >>   /*
>> >> >>    * Create a copy of the resource table. When a virtio device starts
>> >> >> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
>> >> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>> >> >>                                                  const struct firmware *fw)
>> >> >>  {
>> >> >> - struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> >> >> - struct elf32_shdr *shdr;
>> >> >> + const void *shdr;
>> >> >> + u64 sh_addr, sh_size;
>> >> >> + u8 class = fw_elf_get_class(fw);
>> >> >>
>> >> >> - shdr = find_table(&rproc->dev, ehdr, fw->size);
>> >> >> + shdr = find_table(&rproc->dev, fw);
>> >> >>   if (!shdr)
>> >> >>           return NULL;
>> >> >>
>> >> >> - return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
>> >> >> + sh_addr = elf_shdr_sh_addr(class, shdr);
>> >> >> + sh_size = elf_shdr_sh_size(class, shdr);
>> >> >> +
>> >> >> + return rproc_da_to_va(rproc, sh_addr, sh_size);
>> >> >
>> >> > The prototype for the above is as follow:
>> >> >
>> >> > void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >
>> >> > But sh_size is a u64, which will cause problem that are hard to debug.  I think
>> >> > it is better to move 'len' to an 8 byte type along with the refactoring of the
>> >> > existing code that is implied.  I suggest to split this work in a preparatory
>> >> > patch (that will still be part of this set).
>> >>
>> >> Nice catch ! I will do that.
>> >>
>> >> >
>> >> >>  }
>> >> >>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
>> >> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
>> >> >> b/drivers/remoteproc/remoteproc_elf_loader.h
>> >> >> new file mode 100644
>> >> >> index 000000000000..fac3565734f9
>> >> >> --- /dev/null
>> >> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
>> >> >> @@ -0,0 +1,69 @@
>> >> >> +/* SPDX-License-Identifier: GPL-2.0 */
>> >> >> +/*
>> >> >> + * Remote processor elf loader defines
>> >> >> + *
>> >> >> + * Copyright (C) 2019 Kalray, Inc.
>> >> >> + */
>> >> >> +
>> >> >> +#ifndef REMOTEPROC_ELF_LOADER_H
>> >> >> +#define REMOTEPROC_ELF_LOADER_H
>> >> >> +
>> >> >> +#include <linux/elf.h>
>> >> >> +#include <linux/types.h>
>> >> >> +
>> >> >> +/**
>> >> >> + * fw_elf_get_class - Get elf class
>> >> >> + * @fw: the ELF firmware image
>> >> >> + *
>> >> >> + * Note that we use and elf32_hdr to access the class since the start of the
>> >> >> + * struct is the same for both elf class
>> >> >> + *
>> >> >> + * Return: elf class of the firmware
>> >> >> + */
>> >> >> +static inline u8 fw_elf_get_class(const struct firmware *fw)
>> >> >> +{
>> >> >> + struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> >> >> +
>> >> >> + return ehdr->e_ident[EI_CLASS];
>> >> >> +}
>> >> >> +
>> >> >> +#define ELF_GET_FIELD(__s, __field, __type) \
>> >> >> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
>> >> >> +{ \
>> >> >> + if (class == ELFCLASS32) \
>> >> >> +         return (__type) ((const struct elf32_##__s *) arg)->__field; \
>> >> >> + else \
>> >> >> +         return (__type) ((const struct elf64_##__s *) arg)->__field; \
>> >> >> +}
>> >> >> +
>> >> >> +ELF_GET_FIELD(hdr, e_entry, u64)
>> >> >> +ELF_GET_FIELD(hdr, e_phnum, u16)
>> >> >> +ELF_GET_FIELD(hdr, e_shnum, u16)
>> >> >> +ELF_GET_FIELD(hdr, e_phoff, u64)
>> >> >> +ELF_GET_FIELD(hdr, e_shoff, u64)
>> >> >> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
>> >> >> +
>> >> >> +ELF_GET_FIELD(phdr, p_paddr, u64)
>> >> >> +ELF_GET_FIELD(phdr, p_filesz, u64)
>> >> >> +ELF_GET_FIELD(phdr, p_memsz, u64)
>> >> >> +ELF_GET_FIELD(phdr, p_type, u32)
>> >> >> +ELF_GET_FIELD(phdr, p_offset, u64)
>> >> >> +
>> >> >> +ELF_GET_FIELD(shdr, sh_size, u64)
>> >> >> +ELF_GET_FIELD(shdr, sh_offset, u64)
>> >> >> +ELF_GET_FIELD(shdr, sh_name, u32)
>> >> >> +ELF_GET_FIELD(shdr, sh_addr, u64)
>> >> >
>> >> > I like how you did this.
>> >> >
>> >> >> +
>> >> >> +#define ELF_STRUCT_SIZE(__s) \
>> >> >> +static inline unsigned long elf_size_of_##__s(u8 class) \
>> >> >> +{ \
>> >> >> + if (class == ELFCLASS32)\
>> >> >> +         return sizeof(struct elf32_##__s); \
>> >> >> + else \
>> >> >> +         return sizeof(struct elf64_##__s); \
>> >> >> +}
>> >> >> +
>> >> >> +ELF_STRUCT_SIZE(shdr)
>> >> >> +ELF_STRUCT_SIZE(phdr)
>> >> >> +
>> >> >> +#endif /* REMOTEPROC_ELF_LOADER_H */
>> >> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> >> >> b/drivers/remoteproc/remoteproc_internal.h
>> >> >> index 45ff76a06c72..4ef745e3a1bc 100644
>> >> >> --- a/drivers/remoteproc/remoteproc_internal.h
>> >> >> +++ b/drivers/remoteproc/remoteproc_internal.h
>> >> >> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>> >> >>  int rproc_trigger_recovery(struct rproc *rproc);
>> >> >>
>> >> >>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
>> >> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> >> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> >> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>> >> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>> >> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>> >> >> diff --git a/drivers/remoteproc/st_remoteproc.c
>> >> >> b/drivers/remoteproc/st_remoteproc.c
>> >> >> index 51049d17b1e5..e23abd8a96b0 100644
>> >> >> --- a/drivers/remoteproc/st_remoteproc.c
>> >> >> +++ b/drivers/remoteproc/st_remoteproc.c
>> >> >> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
>> >> >>           }
>> >> >>   }
>> >> >>
>> >> >> - dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
>> >> >> + dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>> >> >>
>> >> >>   return 0;
>> >> >>
>> >> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> >> >> index 04d04709f2bd..512de9a2590c 100644
>> >> >> --- a/include/linux/remoteproc.h
>> >> >> +++ b/include/linux/remoteproc.h
>> >> >> @@ -362,7 +362,7 @@ struct rproc_ops {
>> >> >>                           struct rproc *rproc, const struct firmware *fw);
>> >> >>   int (*load)(struct rproc *rproc, const struct firmware *fw);
>> >> >>   int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
>> >> >> - u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> >> >> + u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> >> >>  };
>> >> >>
>> >> >>  /**
>> >> >> @@ -478,7 +478,7 @@ struct rproc {
>> >> >>   int num_traces;
>> >> >>   struct list_head carveouts;
>> >> >>   struct list_head mappings;
>> >> >> - u32 bootaddr;
>> >> >> + u64 bootaddr;
>> >> >>   struct list_head rvdevs;
>> >> >>   struct list_head subdevs;
>> >> >>   struct idr notifyids;
>> >> >
>> >> > Please hold off before doing another respin of this patch.  While doing
>> >> > something completely different I noticed TI also did some work in this area.
>> >> > I'd like to take some time to look at their implementation and see if they carry
>> >> > features that haven't been included here.  I intend to do this tomorrow.
>> >>
>> >> Ok,
>> >>
>> >> Thanks for your review,
>> >
>> > As promised I looked at what Suman had done on his side [1] to support 64-bit
>> > ELF
>> > files. His approach to offer the same functionality but for 64 bit in a new file
>> > is quick, simple and flexible.  On the flip side it introduces code duplication,
>> > something that is seriously frowned upon upstream.
>> >
>> > I did some soul searching in the kernel code and found very little in terms of
>> > implementation that deals with both 32 and 64 bit ELF format.  The most
>> > convincing approach was set forth by the MIPS guys [2].  They too have decided
>> > to support both types in the same functions, but I don't see us adding an if()
>> > statement (and the code duplication that comes with it) every time we need to
>> > deal with file types.
>> >
>> > Given the above I'm in favour of moving forward with your approach.  One could
>> > rightly argue the macros make the code harder to read but given the
>> > alternatives, it seems to be the best solution.
>> >
>> > Mathieu
>> >
>> > [1]. https://bit.ly/2Rpmb4E
>> > [2]. https://elixir.bootlin.com/linux/v5.5-rc6/source/arch/mips/kernel/elf.c#L75
>> >>
>> >> Clément
>> >>
>> >> >
>> >> > Thanks,
>> >> > Mathieu
>> >> >
>> >> >> --
> > > > >> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v2] remoteproc: Add elf64 support in elf loader
  2020-01-29  8:55               ` Clément Leger
@ 2020-01-29 16:30                 ` Mathieu Poirier
  2020-02-04 14:33                   ` [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va Clement Leger
  2020-02-04 17:44                   ` [PATCH v3 0/2] remoteproc: Add elf64 support to elf loader Clement Leger
  0 siblings, 2 replies; 76+ messages in thread
From: Mathieu Poirier @ 2020-01-29 16:30 UTC (permalink / raw)
  To: Clément Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, linux-remoteproc, linux-kernel,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Wed, Jan 29, 2020 at 09:55:17AM +0100, Clément Leger wrote:
> Ok, here is the example to be more clear:
> 
> Content of elfxx_loader.h:
> 
> int elf##ELF_TYPE##_load(...) {
> 	struct elf##ELF_TYPE##_shdr *shdr = data;
> 	...
> }
> 
> Then in elf_loader.c file:
> 
> #define ELF_TYPE 32
> #include "elfxx_loader.h"
> #undef ELF_TYPE
> #define ELF_TYPE 64
> #include "elfxx_loader.h"
> 
> int elf_load(...) {
> 	if (class == elf64)
> 		elf64_load(...);
> 	else
> 		elf32_load(...);
> }
> 
> This is used for syscall_table.c in arch for instance.
> A macro must be defined and then the ehader is included and
> "generates" code.
> 
> #undef __SYSCALL
> #define __SYSCALL(nr, call)	[nr] = (call),
> 
> void *sys_call_table[__NR_syscalls] = {
> 	[0 ... __NR_syscalls - 1] = sys_ni_syscall,
> #include <asm/unistd.h>
> };
> 
> Hope this shed some light on my suggestion.

Thank you for taking the time to do this.

I fear elfxx_loader.h would become very cryptic and hard to debug.  I think your
original approach strikes the right balance between readabiliy and code
duplication. 

> 
> Clément
> 
> ----- On 28 Jan, 2020, at 18:14, Mathieu Poirier mathieu.poirier@linaro.org wrote:
> 
> > On Mon, 27 Jan 2020 at 01:33, Clément Leger <cleger@kalray.eu> wrote:
> >>
> >> Hi Mathieu,
> >>
> >> Thanks for your thorough review. While thinking about it,there is at least
> >> another option which would consist in splitting all elf specific functions into
> >> a separate .h file and then include it in a .c to "instantiate" the functions
> >> with correct types. For instance, it would look like this:
> >>
> >> #define ELF_TYPE 32
> >> #include "elf_functions.h"
> >> #undef ELF_TYPE
> >> #define ELF_TYPE 64
> >> #include "elf_functions.h"
> >>
> >> pros: More readable and type-checking ok
> >> cons: A bit hackish
> >>
> >> I would say this might be a better optino than my current patch.
> >> However, I'm not sure this kind of thing of well accepted in the kernel.
> > 
> > I won't claim to fully understand your suggestion above, but if it is
> > suspicious enough to look hackish to you than it will probably look
> > hackish to other people.  Nonetheless there might be a case for
> > exception if the approach yields clear advantages.  Can you point me
> > to an example somewhere in the kernel code where something similar
> > would have been done?
> > 
> >>
> >> Clément
> >>
> >> ----- On 24 Jan, 2020, at 22:58, Mathieu Poirier mathieu.poirier@linaro.org
> >> wrote:
> >>
> >> > On Fri, Jan 24, 2020 at 09:24:16AM +0100, Clément Leger wrote:
> >> >> Hi Mathieu,
> >> >>
> >> >> ----- On 24 Jan, 2020, at 01:53, Mathieu Poirier mathieu.poirier@linaro.org
> >> >> wrote:
> >> >>
> >> >> > Hi Clement,
> >> >> >
> >> >> > On Fri, Oct 04, 2019 at 08:42:20PM +0200, Clement Leger wrote:
> >> >> >> elf32 and elf64 mainly differ by their types. In order to avoid
> >> >> >> copy/pasting the whole loader code, generate static inline functions
> >> >> >> which will access values according to the elf class. It allows to keep a
> >> >> >> common loader basis.
> >> >> >> In order to accomodate both elf types sizes, the maximum size for a
> >> >> >> elf header member is chosen using the maximum value of both elf class.
> >> >> >>
> >> >> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
> >> >> >> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
> >> >> >> ---
> >> >> >> Changes in v2:
> >> >> >>  - Add ELF64 support in documentation
> >> >> >>
> >> >> >
> >> >> > First and foremost please address the complaints from checkpatch.
> >> >>
> >> >> I fixed one typo in accommodate. The other checkpatch complaint is
> >> >> about missing parenthesis for macros with complex values which is
> >> >> unfortunately not possible since I'm generating inline functions.
> >> >>
> >> >> Did you have any other one ?
> >> >>
> >> >> >
> >> >> >> ---
> >> >> >>  Documentation/remoteproc.txt               |   2 +-
> >> >> >>  drivers/remoteproc/remoteproc_elf_loader.c | 135 ++++++++++++++++++-----------
> >> >> >>  drivers/remoteproc/remoteproc_elf_loader.h |  69 +++++++++++++++
> >> >> >>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
> >> >> >>  drivers/remoteproc/st_remoteproc.c         |   2 +-
> >> >> >>  include/linux/remoteproc.h                 |   4 +-
> >> >> >>  6 files changed, 157 insertions(+), 57 deletions(-)
> >> >> >>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
> >> >> >>
> >> >> >> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
> >> >> >> index 77fb03acdbb4..bf4f0c41ec4e 100644
> >> >> >> --- a/Documentation/remoteproc.txt
> >> >> >> +++ b/Documentation/remoteproc.txt
> >> >> >> @@ -230,7 +230,7 @@ in the used rings.
> >> >> >>  Binary Firmware Structure
> >> >> >>  =========================
> >> >> >>
> >> >> >> -At this point remoteproc only supports ELF32 firmware binaries. However,
> >> >> >> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
> >> >> >>  it is quite expected that other platforms/devices which we'd want to
> >> >> >>  support with this framework will be based on different binary formats.
> >> >> >>
> >> >> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
> >> >> >> b/drivers/remoteproc/remoteproc_elf_loader.c
> >> >> >> index b17d72ec8603..6a2d31d6092c 100644
> >> >> >> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> >> >> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> >> >> >> @@ -31,6 +31,7 @@
> >> >> >>  #include <linux/elf.h>
> >> >> >>
> >> >> >>  #include "remoteproc_internal.h"
> >> >> >> +#include "remoteproc_elf_loader.h"
> >> >> >>
> >> >> >>  /**
> >> >> >>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> >> >> >> @@ -43,8 +44,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> >> >> firmware *fw)
> >> >> >>  {
> >> >> >>   const char *name = rproc->firmware;
> >> >> >>   struct device *dev = &rproc->dev;
> >> >> >> + /*
> >> >> >> +  * Elf files are beginning with the same structure. Thus, to simplify
> >> >> >> +  * header parsing, we can use the elf32_hdr one for both elf64 and
> >> >> >> +  * elf32.
> >> >> >> +  */
> >> >> >>   struct elf32_hdr *ehdr;
> >> >> >> + u32 elf_shdr_size;
> >> >> >> + u64 phoff, shoff;
> >> >> >>   char class;
> >> >> >> + u16 phnum;
> >> >> >>
> >> >> >>   if (!fw) {
> >> >> >>           dev_err(dev, "failed to load %s\n", name);
> >> >> >> @@ -58,9 +67,13 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> >> >> firmware *fw)
> >> >> >
> >> >> > In the current code [1] fw->size is compared against the size of an elf32_hdr.
> >> >> > If support for elf64 is added that code needs to be modified to check for the
> >> >> > right header size using fw_elf_get_class().
> >> >>
> >> >> Actually, the elf32 header is smaller than the elf64 one so this check is
> >> >> there to ensure that we have at least a minimal elf header (elf32).
> >> >> And since the class is derived from the header, you better have to check the
> >> >> header size before accessing it.
> >> >>
> >> >> To be more clear, I could compare it to min(sizeof(struct elf32_hdr),
> >> >> sizeof(struct elf64_hdr)) or add a comment at least stating that since
> >> >> elf header contains the same fields for identification, we can use the
> >> >> elf32 one.
> >> >>
> >> >> >
> >> >> > [1]
> >> >> > https://elixir.bootlin.com/linux/v5.5-rc6/source/drivers/remoteproc/remoteproc_elf_loader.c#L46
> >> >> >
> >> >> >>
> >> >> >>   ehdr = (struct elf32_hdr *)fw->data;
> >> >> >>
> >> >> >> - /* We only support ELF32 at this point */
> >> >> >> + if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> >> >> >> +         dev_err(dev, "Image is corrupted (bad magic)\n");
> >> >> >> +         return -EINVAL;
> >> >> >> + }
> >> >> >> +
> >> >> >
> >> >> > Is there a reason to move this check up where?  If not please bring it back to
> >> >> > its original location, that is below:
> >> >> >
> >> >> > "if (fw->size < ehdr->e_shoff + sizeof(structelf32_shdr))"
> >> >> >
> >> >>
> >> >> This is because the new check for size uses elf_shdr_size which is derived from
> >> >> the class. And since the class is extracted from the elf header, we need to
> >> >> check
> >> >> the header to be correct first.
> >> >>
> >> >> >>   class = ehdr->e_ident[EI_CLASS];
> >> >> >> - if (class != ELFCLASS32) {
> >> >> >> + if (class != ELFCLASS32 && class != ELFCLASS64) {
> >> >> >>           dev_err(dev, "Unsupported class: %d\n", class);
> >> >> >>           return -EINVAL;
> >> >> >>   }
> >> >> >> @@ -75,26 +88,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> >> >> firmware *fw)
> >> >> >>           return -EINVAL;
> >> >> >>   }
> >> >> >>
> >> >> >> - if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
> >> >> >> -         dev_err(dev, "Image is too small\n");
> >> >> >> -         return -EINVAL;
> >> >> >> - }
> >> >> >> + phoff = elf_hdr_e_phoff(class, fw->data);
> >> >> >> + shoff = elf_hdr_e_shoff(class, fw->data);
> >> >> >> + phnum =  elf_hdr_e_phnum(class, fw->data);
> >> >> >> + elf_shdr_size = elf_size_of_shdr(class);
> >> >> >>
> >> >> >> - if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> >> >> >> -         dev_err(dev, "Image is corrupted (bad magic)\n");
> >> >> >> + if (fw->size < shoff + elf_shdr_size) {
> >> >> >> +         dev_err(dev, "Image is too small\n");
> >> >> >>           return -EINVAL;
> >> >> >>   }
> >> >> >>
> >> >> >> - if (ehdr->e_phnum == 0) {
> >> >> >> + if (phnum == 0) {
> >> >> >>           dev_err(dev, "No loadable segments\n");
> >> >> >>           return -EINVAL;
> >> >> >>   }
> >> >> >>
> >> >> >> - if (ehdr->e_phoff > fw->size) {
> >> >> >> + if (phoff > fw->size) {
> >> >> >>           dev_err(dev, "Firmware size is too small\n");
> >> >> >>           return -EINVAL;
> >> >> >>   }
> >> >> >>
> >> >> >> + dev_dbg(dev, "Firmware is an elf%d file\n",
> >> >> >> +         class == ELFCLASS32 ? 32 : 64);
> >> >> >> +
> >> >> >
> >> >> > Yes, this is useful.
> >> >> >
> >> >> >>   return 0;
> >> >> >>  }
> >> >> >>  EXPORT_SYMBOL(rproc_elf_sanity_check);
> >> >> >> @@ -110,11 +126,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
> >> >> >>   * Note that the boot address is not a configurable property of all remote
> >> >> >>   * processors. Some will always boot at a specific hard-coded address.
> >> >> >>   */
> >> >> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> >> >> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> >> >> >>  {
> >> >> >> - struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
> >> >> >> -
> >> >> >> - return ehdr->e_entry;
> >> >> >> + return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
> >> >> >>  }
> >> >> >>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> >> >> >>
> >> >> >> @@ -145,37 +159,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> >> >> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
> >> >> >>  {
> >> >> >>   struct device *dev = &rproc->dev;
> >> >> >> - struct elf32_hdr *ehdr;
> >> >> >> - struct elf32_phdr *phdr;
> >> >> >> + const void *ehdr, *phdr;
> >> >> >>   int i, ret = 0;
> >> >> >> + u16 phnum;
> >> >> >>   const u8 *elf_data = fw->data;
> >> >> >> + u8 class = fw_elf_get_class(fw);
> >> >> >> + u32 elf_phdr_size = elf_size_of_phdr(class);
> >> >> >>
> >> >> >> - ehdr = (struct elf32_hdr *)elf_data;
> >> >> >> - phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> >> >> >> + ehdr = elf_data;
> >> >> >> + phnum = elf_hdr_e_phnum(class, ehdr);
> >> >> >> + phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
> >> >> >>
> >> >> >>   /* go through the available ELF segments */
> >> >> >> - for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> >> >> >> -         u32 da = phdr->p_paddr;
> >> >> >> -         u32 memsz = phdr->p_memsz;
> >> >> >> -         u32 filesz = phdr->p_filesz;
> >> >> >> -         u32 offset = phdr->p_offset;
> >> >> >> + for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
> >> >> >> +         u64 da = elf_phdr_p_paddr(class, phdr);
> >> >> >> +         u64 memsz = elf_phdr_p_memsz(class, phdr);
> >> >> >> +         u64 filesz = elf_phdr_p_filesz(class, phdr);
> >> >> >> +         u64 offset = elf_phdr_p_offset(class, phdr);
> >> >> >> +         u32 type = elf_phdr_p_type(class, phdr);
> >> >> >>           void *ptr;
> >> >> >>
> >> >> >> -         if (phdr->p_type != PT_LOAD)
> >> >> >> +         if (type != PT_LOAD)
> >> >> >>                   continue;
> >> >> >>
> >> >> >> -         dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
> >> >> >> -                 phdr->p_type, da, memsz, filesz);
> >> >> >> +         dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
> >> >> >> +                 type, da, memsz, filesz);
> >> >> >>
> >> >> >>           if (filesz > memsz) {
> >> >> >> -                 dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
> >> >> >> +                 dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
> >> >> >>                           filesz, memsz);
> >> >> >>                   ret = -EINVAL;
> >> >> >>                   break;
> >> >> >>           }
> >> >> >>
> >> >> >>           if (offset + filesz > fw->size) {
> >> >> >> -                 dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
> >> >> >> +                 dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
> >> >> >>                           offset + filesz, fw->size);
> >> >> >>                   ret = -EINVAL;
> >> >> >>                   break;
> >> >> >> @@ -184,14 +202,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> >> >> >> struct firmware *fw)
> >> >> >>           /* grab the kernel address for this device address */
> >> >> >>           ptr = rproc_da_to_va(rproc, da, memsz);
> >> >> >>           if (!ptr) {
> >> >> >> -                 dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> >> >> >> +                 dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
> >> >> >> +                         memsz);
> >> >> >>                   ret = -EINVAL;
> >> >> >>                   break;
> >> >> >>           }
> >> >> >>
> >> >> >>           /* put the segment where the remote processor expects it */
> >> >> >> -         if (phdr->p_filesz)
> >> >> >> -                 memcpy(ptr, elf_data + phdr->p_offset, filesz);
> >> >> >> +         if (filesz)
> >> >> >> +                 memcpy(ptr, elf_data + offset, filesz);
> >> >> >>
> >> >> >>           /*
> >> >> >>            * Zero out remaining memory for this segment.
> >> >> >> @@ -208,24 +227,32 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> >> >> >> struct firmware *fw)
> >> >> >>  }
> >> >> >>  EXPORT_SYMBOL(rproc_elf_load_segments);
> >> >> >>
> >> >> >> -static struct elf32_shdr *
> >> >> >> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> >> >> >> +static const void *
> >> >> >
> >> >> > Not sure I understand the "const" - was the compiler complaining?
> >> >>
> >> >> It's actually caused by the fact I used a const void* shdr in the caller.
> >> >> I will check if this is mandatory.
> >> >>
> >> >> >
> >> >> >> +find_table(struct device *dev, const struct firmware *fw)
> >> >> >>  {
> >> >> >> - struct elf32_shdr *shdr;
> >> >> >> + const void *shdr, *name_table_shdr;
> >> >> >>   int i;
> >> >> >>   const char *name_table;
> >> >> >>   struct resource_table *table = NULL;
> >> >> >> - const u8 *elf_data = (void *)ehdr;
> >> >> >> + const u8 *elf_data = (void *)fw->data;
> >> >> >> + u8 class = fw_elf_get_class(fw);
> >> >> >> + size_t fw_size = fw->size;
> >> >> >> + const void *ehdr = elf_data;
> >> >> >> + u16 shnum = elf_hdr_e_shnum(class, ehdr);
> >> >> >> + u32 elf_shdr_size = elf_size_of_shdr(class);
> >> >> >> + u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
> >> >> >>
> >> >> >>   /* look for the resource table and handle it */
> >> >> >> - shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> >> >> >> - name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
> >> >> >> + shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
> >> >> >> + name_table_shdr = shdr + (shstrndx * elf_shdr_size);
> >> >> >> + name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
> >> >> >
> >> >> > It took me a while but I figured out what is happening here.  To save me (and
> >> >> > other people) from going through the same mental process every time I look at
> >> >> > this code, please add a comment for each of the above 3 lines.
> >> >>
> >> >> Indeed.
> >> >>
> >> >> >
> >> >> >>
> >> >> >> - for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> >> >> >> -         u32 size = shdr->sh_size;
> >> >> >> -         u32 offset = shdr->sh_offset;
> >> >> >> + for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
> >> >> >> +         u64 size = elf_shdr_sh_size(class, shdr);
> >> >> >> +         u64 offset = elf_shdr_sh_offset(class, shdr);
> >> >> >> +         u32 name = elf_shdr_sh_name(class, shdr);
> >> >> >>
> >> >> >> -         if (strcmp(name_table + shdr->sh_name, ".resource_table"))
> >> >> >> +         if (strcmp(name_table + name, ".resource_table"))
> >> >> >>                   continue;
> >> >> >>
> >> >> >>           table = (struct resource_table *)(elf_data + offset);
> >> >> >> @@ -279,21 +306,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
> >> >> >> size_t fw_size)
> >> >> >>   */
> >> >> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
> >> >> >>  {
> >> >> >> - struct elf32_hdr *ehdr;
> >> >> >> - struct elf32_shdr *shdr;
> >> >> >> + const void *shdr;
> >> >> >>   struct device *dev = &rproc->dev;
> >> >> >>   struct resource_table *table = NULL;
> >> >> >>   const u8 *elf_data = fw->data;
> >> >> >>   size_t tablesz;
> >> >> >> + u8 class = fw_elf_get_class(fw);
> >> >> >> + u64 sh_offset;
> >> >> >>
> >> >> >> - ehdr = (struct elf32_hdr *)elf_data;
> >> >> >> -
> >> >> >> - shdr = find_table(dev, ehdr, fw->size);
> >> >> >> + shdr = find_table(dev, fw);
> >> >> >>   if (!shdr)
> >> >> >>           return -EINVAL;
> >> >> >>
> >> >> >> - table = (struct resource_table *)(elf_data + shdr->sh_offset);
> >> >> >> - tablesz = shdr->sh_size;
> >> >> >> + sh_offset = elf_shdr_sh_offset(class, shdr);
> >> >> >> + table = (struct resource_table *)(elf_data + sh_offset);
> >> >> >> + tablesz = elf_shdr_sh_size(class, shdr);
> >> >> >>
> >> >> >>   /*
> >> >> >>    * Create a copy of the resource table. When a virtio device starts
> >> >> >> @@ -326,13 +353,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
> >> >> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> >> >> >>                                                  const struct firmware *fw)
> >> >> >>  {
> >> >> >> - struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> >> >> >> - struct elf32_shdr *shdr;
> >> >> >> + const void *shdr;
> >> >> >> + u64 sh_addr, sh_size;
> >> >> >> + u8 class = fw_elf_get_class(fw);
> >> >> >>
> >> >> >> - shdr = find_table(&rproc->dev, ehdr, fw->size);
> >> >> >> + shdr = find_table(&rproc->dev, fw);
> >> >> >>   if (!shdr)
> >> >> >>           return NULL;
> >> >> >>
> >> >> >> - return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
> >> >> >> + sh_addr = elf_shdr_sh_addr(class, shdr);
> >> >> >> + sh_size = elf_shdr_sh_size(class, shdr);
> >> >> >> +
> >> >> >> + return rproc_da_to_va(rproc, sh_addr, sh_size);
> >> >> >
> >> >> > The prototype for the above is as follow:
> >> >> >
> >> >> > void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >
> >> >> > But sh_size is a u64, which will cause problem that are hard to debug.  I think
> >> >> > it is better to move 'len' to an 8 byte type along with the refactoring of the
> >> >> > existing code that is implied.  I suggest to split this work in a preparatory
> >> >> > patch (that will still be part of this set).
> >> >>
> >> >> Nice catch ! I will do that.
> >> >>
> >> >> >
> >> >> >>  }
> >> >> >>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> >> >> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
> >> >> >> b/drivers/remoteproc/remoteproc_elf_loader.h
> >> >> >> new file mode 100644
> >> >> >> index 000000000000..fac3565734f9
> >> >> >> --- /dev/null
> >> >> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
> >> >> >> @@ -0,0 +1,69 @@
> >> >> >> +/* SPDX-License-Identifier: GPL-2.0 */
> >> >> >> +/*
> >> >> >> + * Remote processor elf loader defines
> >> >> >> + *
> >> >> >> + * Copyright (C) 2019 Kalray, Inc.
> >> >> >> + */
> >> >> >> +
> >> >> >> +#ifndef REMOTEPROC_ELF_LOADER_H
> >> >> >> +#define REMOTEPROC_ELF_LOADER_H
> >> >> >> +
> >> >> >> +#include <linux/elf.h>
> >> >> >> +#include <linux/types.h>
> >> >> >> +
> >> >> >> +/**
> >> >> >> + * fw_elf_get_class - Get elf class
> >> >> >> + * @fw: the ELF firmware image
> >> >> >> + *
> >> >> >> + * Note that we use and elf32_hdr to access the class since the start of the
> >> >> >> + * struct is the same for both elf class
> >> >> >> + *
> >> >> >> + * Return: elf class of the firmware
> >> >> >> + */
> >> >> >> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> >> >> >> +{
> >> >> >> + struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> >> >> >> +
> >> >> >> + return ehdr->e_ident[EI_CLASS];
> >> >> >> +}
> >> >> >> +
> >> >> >> +#define ELF_GET_FIELD(__s, __field, __type) \
> >> >> >> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
> >> >> >> +{ \
> >> >> >> + if (class == ELFCLASS32) \
> >> >> >> +         return (__type) ((const struct elf32_##__s *) arg)->__field; \
> >> >> >> + else \
> >> >> >> +         return (__type) ((const struct elf64_##__s *) arg)->__field; \
> >> >> >> +}
> >> >> >> +
> >> >> >> +ELF_GET_FIELD(hdr, e_entry, u64)
> >> >> >> +ELF_GET_FIELD(hdr, e_phnum, u16)
> >> >> >> +ELF_GET_FIELD(hdr, e_shnum, u16)
> >> >> >> +ELF_GET_FIELD(hdr, e_phoff, u64)
> >> >> >> +ELF_GET_FIELD(hdr, e_shoff, u64)
> >> >> >> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
> >> >> >> +
> >> >> >> +ELF_GET_FIELD(phdr, p_paddr, u64)
> >> >> >> +ELF_GET_FIELD(phdr, p_filesz, u64)
> >> >> >> +ELF_GET_FIELD(phdr, p_memsz, u64)
> >> >> >> +ELF_GET_FIELD(phdr, p_type, u32)
> >> >> >> +ELF_GET_FIELD(phdr, p_offset, u64)
> >> >> >> +
> >> >> >> +ELF_GET_FIELD(shdr, sh_size, u64)
> >> >> >> +ELF_GET_FIELD(shdr, sh_offset, u64)
> >> >> >> +ELF_GET_FIELD(shdr, sh_name, u32)
> >> >> >> +ELF_GET_FIELD(shdr, sh_addr, u64)
> >> >> >
> >> >> > I like how you did this.
> >> >> >
> >> >> >> +
> >> >> >> +#define ELF_STRUCT_SIZE(__s) \
> >> >> >> +static inline unsigned long elf_size_of_##__s(u8 class) \
> >> >> >> +{ \
> >> >> >> + if (class == ELFCLASS32)\
> >> >> >> +         return sizeof(struct elf32_##__s); \
> >> >> >> + else \
> >> >> >> +         return sizeof(struct elf64_##__s); \
> >> >> >> +}
> >> >> >> +
> >> >> >> +ELF_STRUCT_SIZE(shdr)
> >> >> >> +ELF_STRUCT_SIZE(phdr)
> >> >> >> +
> >> >> >> +#endif /* REMOTEPROC_ELF_LOADER_H */
> >> >> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
> >> >> >> b/drivers/remoteproc/remoteproc_internal.h
> >> >> >> index 45ff76a06c72..4ef745e3a1bc 100644
> >> >> >> --- a/drivers/remoteproc/remoteproc_internal.h
> >> >> >> +++ b/drivers/remoteproc/remoteproc_internal.h
> >> >> >> @@ -63,7 +63,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
> >> >> >>  int rproc_trigger_recovery(struct rproc *rproc);
> >> >> >>
> >> >> >>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> >> >> >> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >> >> >> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >> >> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
> >> >> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
> >> >> >>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> >> >> >> diff --git a/drivers/remoteproc/st_remoteproc.c
> >> >> >> b/drivers/remoteproc/st_remoteproc.c
> >> >> >> index 51049d17b1e5..e23abd8a96b0 100644
> >> >> >> --- a/drivers/remoteproc/st_remoteproc.c
> >> >> >> +++ b/drivers/remoteproc/st_remoteproc.c
> >> >> >> @@ -193,7 +193,7 @@ static int st_rproc_start(struct rproc *rproc)
> >> >> >>           }
> >> >> >>   }
> >> >> >>
> >> >> >> - dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> >> >> >> + dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
> >> >> >>
> >> >> >>   return 0;
> >> >> >>
> >> >> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> >> >> >> index 04d04709f2bd..512de9a2590c 100644
> >> >> >> --- a/include/linux/remoteproc.h
> >> >> >> +++ b/include/linux/remoteproc.h
> >> >> >> @@ -362,7 +362,7 @@ struct rproc_ops {
> >> >> >>                           struct rproc *rproc, const struct firmware *fw);
> >> >> >>   int (*load)(struct rproc *rproc, const struct firmware *fw);
> >> >> >>   int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> >> >> >> - u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> >> >> >> + u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> >> >> >>  };
> >> >> >>
> >> >> >>  /**
> >> >> >> @@ -478,7 +478,7 @@ struct rproc {
> >> >> >>   int num_traces;
> >> >> >>   struct list_head carveouts;
> >> >> >>   struct list_head mappings;
> >> >> >> - u32 bootaddr;
> >> >> >> + u64 bootaddr;
> >> >> >>   struct list_head rvdevs;
> >> >> >>   struct list_head subdevs;
> >> >> >>   struct idr notifyids;
> >> >> >
> >> >> > Please hold off before doing another respin of this patch.  While doing
> >> >> > something completely different I noticed TI also did some work in this area.
> >> >> > I'd like to take some time to look at their implementation and see if they carry
> >> >> > features that haven't been included here.  I intend to do this tomorrow.
> >> >>
> >> >> Ok,
> >> >>
> >> >> Thanks for your review,
> >> >
> >> > As promised I looked at what Suman had done on his side [1] to support 64-bit
> >> > ELF
> >> > files. His approach to offer the same functionality but for 64 bit in a new file
> >> > is quick, simple and flexible.  On the flip side it introduces code duplication,
> >> > something that is seriously frowned upon upstream.
> >> >
> >> > I did some soul searching in the kernel code and found very little in terms of
> >> > implementation that deals with both 32 and 64 bit ELF format.  The most
> >> > convincing approach was set forth by the MIPS guys [2].  They too have decided
> >> > to support both types in the same functions, but I don't see us adding an if()
> >> > statement (and the code duplication that comes with it) every time we need to
> >> > deal with file types.
> >> >
> >> > Given the above I'm in favour of moving forward with your approach.  One could
> >> > rightly argue the macros make the code harder to read but given the
> >> > alternatives, it seems to be the best solution.
> >> >
> >> > Mathieu
> >> >
> >> > [1]. https://bit.ly/2Rpmb4E
> >> > [2]. https://elixir.bootlin.com/linux/v5.5-rc6/source/arch/mips/kernel/elf.c#L75
> >> >>
> >> >> Clément
> >> >>
> >> >> >
> >> >> > Thanks,
> >> >> > Mathieu
> >> >> >
> >> >> >> --
> > > > > >> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va
  2020-01-29 16:30                 ` Mathieu Poirier
@ 2020-02-04 14:33                   ` Clement Leger
  2020-02-04 14:33                     ` [PATCH v2 2/2] remoteproc: Add elf64 support in elf loader Clement Leger
  2020-02-04 16:27                     ` [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va Arnaud POULIQUEN
  2020-02-04 17:44                   ` [PATCH v3 0/2] remoteproc: Add elf64 support to elf loader Clement Leger
  1 sibling, 2 replies; 76+ messages in thread
From: Clement Leger @ 2020-02-04 14:33 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

With upcoming changes in elf loader for elf64 support, section size will
be a u64. When used with da_to_va, this will potentially lead to
overflow if using the current "int" type for len argument. Change
da_to_va prototype to use a u64 for len and fix all users of this
function.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
V2:
 - Change len type from int to u64

 drivers/remoteproc/imx_rproc.c           | 5 +++--
 drivers/remoteproc/keystone_remoteproc.c | 2 +-
 drivers/remoteproc/qcom_q6v5_adsp.c      | 2 +-
 drivers/remoteproc/qcom_q6v5_mss.c       | 2 +-
 drivers/remoteproc/qcom_q6v5_pas.c       | 2 +-
 drivers/remoteproc/qcom_q6v5_wcss.c      | 2 +-
 drivers/remoteproc/qcom_wcnss.c          | 2 +-
 drivers/remoteproc/remoteproc_core.c     | 2 +-
 drivers/remoteproc/remoteproc_internal.h | 2 +-
 drivers/remoteproc/st_slim_rproc.c       | 2 +-
 drivers/remoteproc/wkup_m3_rproc.c       | 2 +-
 include/linux/remoteproc.h               | 2 +-
 12 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 3e72b6f38d4b..7ec79be5eb5d 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -208,7 +208,7 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
 	return -ENOENT;
 }
 
-static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct imx_rproc *priv = rproc->priv;
 	void *va = NULL;
@@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 		}
 	}
 
-	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
+	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n", da, len,
+		va);
 
 	return va;
 }
diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
index 5c4658f00b3d..25c01df47eba 100644
--- a/drivers/remoteproc/keystone_remoteproc.c
+++ b/drivers/remoteproc/keystone_remoteproc.c
@@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
  * can be used either by the remoteproc core for loading (when using kernel
  * remoteproc loader), or by any rpmsg bus drivers.
  */
-static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct keystone_rproc *ksproc = rproc->priv;
 	void __iomem *va = NULL;
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index e953886b2eb7..7518e67a49e5 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index 471128a2e723..248febde6fc1 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct q6v5 *qproc = rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index db4b3c4bacd7..cf2cd609c90d 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
index f93e1e4a1cc0..3a6b82a16961 100644
--- a/drivers/remoteproc/qcom_q6v5_wcss.c
+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
@@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct q6v5_wcss *wcss = rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index dc135754bb9c..f893219e45a8 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 307df98347ba..9e6d3c6a60ee 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
  * here the output of the DMA API for the carveouts, which should be more
  * correct.
  */
-void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct rproc_mem_entry *carveout;
 	void *ptr = NULL;
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 493ef9262411..004867061721 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
 void rproc_free_vring(struct rproc_vring *rvring);
 int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
 
-void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
+void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
 phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
index 04492fead3c8..2fd14afb3157 100644
--- a/drivers/remoteproc/st_slim_rproc.c
+++ b/drivers/remoteproc/st_slim_rproc.c
@@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct st_slim_rproc *slim_rproc = rproc->priv;
 	void *va = NULL;
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
index 3984e585c847..0e8082948489 100644
--- a/drivers/remoteproc/wkup_m3_rproc.c
+++ b/drivers/remoteproc/wkup_m3_rproc.c
@@ -80,7 +80,7 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct wkup_m3_rproc *wkupm3 = rproc->priv;
 	void *va = NULL;
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 16ad66683ad0..f84bd5fe0211 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -374,7 +374,7 @@ struct rproc_ops {
 	int (*start)(struct rproc *rproc);
 	int (*stop)(struct rproc *rproc);
 	void (*kick)(struct rproc *rproc, int vqid);
-	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
+	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
 	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
 	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
 			  int offset, int avail);
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v2 2/2] remoteproc: Add elf64 support in elf loader
  2020-02-04 14:33                   ` [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va Clement Leger
@ 2020-02-04 14:33                     ` Clement Leger
  2020-02-04 16:27                     ` [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va Arnaud POULIQUEN
  1 sibling, 0 replies; 76+ messages in thread
From: Clement Leger @ 2020-02-04 14:33 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clément Leger

From: Clément Leger <cleger@kalray.eu>

elf32 and elf64 mainly differ by their types. In order to avoid
copy/pasting the whole loader code, generate static inline functions
which will access values according to the elf class. It allows to keep a
common loader basis.
In order to accommodate both elf types sizes, the maximum size for a
elf header member is chosen using the maximum value of both elf class.

Signed-off-by: Clement Leger <cleger@kalray.eu>
Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
---
V2:
 - Add check for elf64 header size
 - Add comments for name table parsing
 - Fix typo in "accommodate"

 Documentation/remoteproc.txt               |   2 +-
 drivers/remoteproc/remoteproc_elf_loader.c | 147 ++++++++++++++++++-----------
 drivers/remoteproc/remoteproc_elf_loader.h |  69 ++++++++++++++
 drivers/remoteproc/remoteproc_internal.h   |   2 +-
 drivers/remoteproc/st_remoteproc.c         |   2 +-
 include/linux/remoteproc.h                 |   4 +-
 6 files changed, 167 insertions(+), 59 deletions(-)
 create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h

diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
index 03c3d2e568b0..2be1147256e0 100644
--- a/Documentation/remoteproc.txt
+++ b/Documentation/remoteproc.txt
@@ -230,7 +230,7 @@ in the used rings.
 Binary Firmware Structure
 =========================
 
-At this point remoteproc only supports ELF32 firmware binaries. However,
+At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
 it is quite expected that other platforms/devices which we'd want to
 support with this framework will be based on different binary formats.
 
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 606aae166eba..21fd2b2fe5ae 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -23,6 +23,7 @@
 #include <linux/elf.h>
 
 #include "remoteproc_internal.h"
+#include "remoteproc_elf_loader.h"
 
 /**
  * rproc_elf_sanity_check() - Sanity Check ELF firmware image
@@ -35,8 +36,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 {
 	const char *name = rproc->firmware;
 	struct device *dev = &rproc->dev;
+	/*
+	 * Elf files are beginning with the same structure. Thus, to simplify
+	 * header parsing, we can use the elf32_hdr one for both elf64 and
+	 * elf32.
+	 */
 	struct elf32_hdr *ehdr;
+	u32 elf_shdr_size;
+	u64 phoff, shoff;
 	char class;
+	u16 phnum;
 
 	if (!fw) {
 		dev_err(dev, "failed to load %s\n", name);
@@ -50,13 +59,22 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 
 	ehdr = (struct elf32_hdr *)fw->data;
 
-	/* We only support ELF32 at this point */
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(dev, "Image is corrupted (bad magic)\n");
+		return -EINVAL;
+	}
+
 	class = ehdr->e_ident[EI_CLASS];
-	if (class != ELFCLASS32) {
+	if (class != ELFCLASS32 && class != ELFCLASS64) {
 		dev_err(dev, "Unsupported class: %d\n", class);
 		return -EINVAL;
 	}
 
+	if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
+		dev_err(dev, "elf64 header is too small\n");
+		return -EINVAL;
+	}
+
 	/* We assume the firmware has the same endianness as the host */
 # ifdef __LITTLE_ENDIAN
 	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
@@ -67,26 +85,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 		return -EINVAL;
 	}
 
-	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
-		dev_err(dev, "Image is too small\n");
-		return -EINVAL;
-	}
+	phoff = elf_hdr_e_phoff(class, fw->data);
+	shoff = elf_hdr_e_shoff(class, fw->data);
+	phnum =  elf_hdr_e_phnum(class, fw->data);
+	elf_shdr_size = elf_size_of_shdr(class);
 
-	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(dev, "Image is corrupted (bad magic)\n");
+	if (fw->size < shoff + elf_shdr_size) {
+		dev_err(dev, "Image is too small\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phnum == 0) {
+	if (phnum == 0) {
 		dev_err(dev, "No loadable segments\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phoff > fw->size) {
+	if (phoff > fw->size) {
 		dev_err(dev, "Firmware size is too small\n");
 		return -EINVAL;
 	}
 
+	dev_dbg(dev, "Firmware is an elf%d file\n",
+		class == ELFCLASS32 ? 32 : 64);
+
 	return 0;
 }
 EXPORT_SYMBOL(rproc_elf_sanity_check);
@@ -102,11 +123,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
  * Note that the boot address is not a configurable property of all remote
  * processors. Some will always boot at a specific hard-coded address.
  */
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
-
-	return ehdr->e_entry;
+	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
 }
 EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 
@@ -137,37 +156,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 {
 	struct device *dev = &rproc->dev;
-	struct elf32_hdr *ehdr;
-	struct elf32_phdr *phdr;
+	const void *ehdr, *phdr;
 	int i, ret = 0;
+	u16 phnum;
 	const u8 *elf_data = fw->data;
+	u8 class = fw_elf_get_class(fw);
+	u32 elf_phdr_size = elf_size_of_phdr(class);
 
-	ehdr = (struct elf32_hdr *)elf_data;
-	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+	ehdr = elf_data;
+	phnum = elf_hdr_e_phnum(class, ehdr);
+	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
 
 	/* go through the available ELF segments */
-	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-		u32 da = phdr->p_paddr;
-		u32 memsz = phdr->p_memsz;
-		u32 filesz = phdr->p_filesz;
-		u32 offset = phdr->p_offset;
+	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
+		u64 da = elf_phdr_p_paddr(class, phdr);
+		u64 memsz = elf_phdr_p_memsz(class, phdr);
+		u64 filesz = elf_phdr_p_filesz(class, phdr);
+		u64 offset = elf_phdr_p_offset(class, phdr);
+		u32 type = elf_phdr_p_type(class, phdr);
 		void *ptr;
 
-		if (phdr->p_type != PT_LOAD)
+		if (type != PT_LOAD)
 			continue;
 
-		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-			phdr->p_type, da, memsz, filesz);
+		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
+			type, da, memsz, filesz);
 
 		if (filesz > memsz) {
-			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
 				filesz, memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		if (offset + filesz > fw->size) {
-			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
+			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
 				offset + filesz, fw->size);
 			ret = -EINVAL;
 			break;
@@ -176,14 +199,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 		/* grab the kernel address for this device address */
 		ptr = rproc_da_to_va(rproc, da, memsz);
 		if (!ptr) {
-			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
+				memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		/* put the segment where the remote processor expects it */
-		if (phdr->p_filesz)
-			memcpy(ptr, elf_data + phdr->p_offset, filesz);
+		if (filesz)
+			memcpy(ptr, elf_data + offset, filesz);
 
 		/*
 		 * Zero out remaining memory for this segment.
@@ -200,24 +224,35 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 }
 EXPORT_SYMBOL(rproc_elf_load_segments);
 
-static struct elf32_shdr *
-find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
+static const void *
+find_table(struct device *dev, const struct firmware *fw)
 {
-	struct elf32_shdr *shdr;
+	const void *shdr, *name_table_shdr;
 	int i;
 	const char *name_table;
 	struct resource_table *table = NULL;
-	const u8 *elf_data = (void *)ehdr;
+	const u8 *elf_data = (void *)fw->data;
+	u8 class = fw_elf_get_class(fw);
+	size_t fw_size = fw->size;
+	const void *ehdr = elf_data;
+	u16 shnum = elf_hdr_e_shnum(class, ehdr);
+	u32 elf_shdr_size = elf_size_of_shdr(class);
+	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
 
 	/* look for the resource table and handle it */
-	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
-	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
-
-	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
-		u32 size = shdr->sh_size;
-		u32 offset = shdr->sh_offset;
-
-		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+	/* First, get the section header according to the elf class */
+	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
+	/* Compute name table section header entry in shdr array */
+	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
+	/* Finally, compute the name table section address in elf */
+	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
+
+	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
+		u64 size = elf_shdr_sh_size(class, shdr);
+		u64 offset = elf_shdr_sh_offset(class, shdr);
+		u32 name = elf_shdr_sh_name(class, shdr);
+
+		if (strcmp(name_table + name, ".resource_table"))
 			continue;
 
 		table = (struct resource_table *)(elf_data + offset);
@@ -270,21 +305,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
  */
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr;
-	struct elf32_shdr *shdr;
+	const void *shdr;
 	struct device *dev = &rproc->dev;
 	struct resource_table *table = NULL;
 	const u8 *elf_data = fw->data;
 	size_t tablesz;
+	u8 class = fw_elf_get_class(fw);
+	u64 sh_offset;
 
-	ehdr = (struct elf32_hdr *)elf_data;
-
-	shdr = find_table(dev, ehdr, fw->size);
+	shdr = find_table(dev, fw);
 	if (!shdr)
 		return -EINVAL;
 
-	table = (struct resource_table *)(elf_data + shdr->sh_offset);
-	tablesz = shdr->sh_size;
+	sh_offset = elf_shdr_sh_offset(class, shdr);
+	table = (struct resource_table *)(elf_data + sh_offset);
+	tablesz = elf_shdr_sh_size(class, shdr);
 
 	/*
 	 * Create a copy of the resource table. When a virtio device starts
@@ -317,13 +352,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 						       const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
-	struct elf32_shdr *shdr;
+	const void *shdr;
+	u64 sh_addr, sh_size;
+	u8 class = fw_elf_get_class(fw);
 
-	shdr = find_table(&rproc->dev, ehdr, fw->size);
+	shdr = find_table(&rproc->dev, fw);
 	if (!shdr)
 		return NULL;
 
-	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
+	sh_addr = elf_shdr_sh_addr(class, shdr);
+	sh_size = elf_shdr_sh_size(class, shdr);
+
+	return rproc_da_to_va(rproc, sh_addr, sh_size);
 }
 EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
diff --git a/drivers/remoteproc/remoteproc_elf_loader.h b/drivers/remoteproc/remoteproc_elf_loader.h
new file mode 100644
index 000000000000..fac3565734f9
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_elf_loader.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Remote processor elf loader defines
+ *
+ * Copyright (C) 2019 Kalray, Inc.
+ */
+
+#ifndef REMOTEPROC_ELF_LOADER_H
+#define REMOTEPROC_ELF_LOADER_H
+
+#include <linux/elf.h>
+#include <linux/types.h>
+
+/**
+ * fw_elf_get_class - Get elf class
+ * @fw: the ELF firmware image
+ *
+ * Note that we use and elf32_hdr to access the class since the start of the
+ * struct is the same for both elf class
+ *
+ * Return: elf class of the firmware
+ */
+static inline u8 fw_elf_get_class(const struct firmware *fw)
+{
+	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
+
+	return ehdr->e_ident[EI_CLASS];
+}
+
+#define ELF_GET_FIELD(__s, __field, __type) \
+static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
+{ \
+	if (class == ELFCLASS32) \
+		return (__type) ((const struct elf32_##__s *) arg)->__field; \
+	else \
+		return (__type) ((const struct elf64_##__s *) arg)->__field; \
+}
+
+ELF_GET_FIELD(hdr, e_entry, u64)
+ELF_GET_FIELD(hdr, e_phnum, u16)
+ELF_GET_FIELD(hdr, e_shnum, u16)
+ELF_GET_FIELD(hdr, e_phoff, u64)
+ELF_GET_FIELD(hdr, e_shoff, u64)
+ELF_GET_FIELD(hdr, e_shstrndx, u16)
+
+ELF_GET_FIELD(phdr, p_paddr, u64)
+ELF_GET_FIELD(phdr, p_filesz, u64)
+ELF_GET_FIELD(phdr, p_memsz, u64)
+ELF_GET_FIELD(phdr, p_type, u32)
+ELF_GET_FIELD(phdr, p_offset, u64)
+
+ELF_GET_FIELD(shdr, sh_size, u64)
+ELF_GET_FIELD(shdr, sh_offset, u64)
+ELF_GET_FIELD(shdr, sh_name, u32)
+ELF_GET_FIELD(shdr, sh_addr, u64)
+
+#define ELF_STRUCT_SIZE(__s) \
+static inline unsigned long elf_size_of_##__s(u8 class) \
+{ \
+	if (class == ELFCLASS32)\
+		return sizeof(struct elf32_##__s); \
+	else \
+		return sizeof(struct elf64_##__s); \
+}
+
+ELF_STRUCT_SIZE(shdr)
+ELF_STRUCT_SIZE(phdr)
+
+#endif /* REMOTEPROC_ELF_LOADER_H */
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 004867061721..eeb26434220e 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
 int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index ee13d23b43a9..a3268d95a50e 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
 		}
 	}
 
-	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
+	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
 
 	return 0;
 
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index f84bd5fe0211..82cebca9344c 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -382,7 +382,7 @@ struct rproc_ops {
 				struct rproc *rproc, const struct firmware *fw);
 	int (*load)(struct rproc *rproc, const struct firmware *fw);
 	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
-	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
 };
 
 /**
@@ -498,7 +498,7 @@ struct rproc {
 	int num_traces;
 	struct list_head carveouts;
 	struct list_head mappings;
-	u32 bootaddr;
+	u64 bootaddr;
 	struct list_head rvdevs;
 	struct list_head subdevs;
 	struct idr notifyids;
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va
  2020-02-04 14:33                   ` [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va Clement Leger
  2020-02-04 14:33                     ` [PATCH v2 2/2] remoteproc: Add elf64 support in elf loader Clement Leger
@ 2020-02-04 16:27                     ` Arnaud POULIQUEN
  2020-02-04 17:10                       ` Clément Leger
  1 sibling, 1 reply; 76+ messages in thread
From: Arnaud POULIQUEN @ 2020-02-04 16:27 UTC (permalink / raw)
  To: Clement Leger, Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet,
	Shawn Guo, Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Loic PALLARDY, s-anna,
	Mathieu Poirier

Hi Clément,

Is it v2 or V3? 
I also suggest you add a cover letter when you post more than one patch in a thread.

On 2/4/20 3:33 PM, Clement Leger wrote:
> With upcoming changes in elf loader for elf64 support, section size will
> be a u64. When used with da_to_va, this will potentially lead to
> overflow if using the current "int" type for len argument. Change
> da_to_va prototype to use a u64 for len and fix all users of this
> function.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>
> ---
> V2:
>  - Change len type from int to u64
> 
>  drivers/remoteproc/imx_rproc.c           | 5 +++--
>  drivers/remoteproc/keystone_remoteproc.c | 2 +-
>  drivers/remoteproc/qcom_q6v5_adsp.c      | 2 +-
>  drivers/remoteproc/qcom_q6v5_mss.c       | 2 +-
>  drivers/remoteproc/qcom_q6v5_pas.c       | 2 +-
>  drivers/remoteproc/qcom_q6v5_wcss.c      | 2 +-
>  drivers/remoteproc/qcom_wcnss.c          | 2 +-
>  drivers/remoteproc/remoteproc_core.c     | 2 +-
>  drivers/remoteproc/remoteproc_internal.h | 2 +-
>  drivers/remoteproc/st_slim_rproc.c       | 2 +-
>  drivers/remoteproc/wkup_m3_rproc.c       | 2 +-
>  include/linux/remoteproc.h               | 2 +-
>  12 files changed, 14 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 3e72b6f38d4b..7ec79be5eb5d 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -208,7 +208,7 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
>  	return -ENOENT;
>  }
>  
> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
I wonder if you could use size_t instead?
Does it make sense for 32-bit system to have a physical address space higher?
it's an open question I won't pretend to have the answer...:)
 

>  {
>  	struct imx_rproc *priv = rproc->priv;
>  	void *va = NULL;
> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
len type to update

Regards,
Arnaud
>  		}
>  	}
>  
> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n", da, len,
> +		va);
>  
>  	return va;
>  }
> diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
> index 5c4658f00b3d..25c01df47eba 100644
> --- a/drivers/remoteproc/keystone_remoteproc.c
> +++ b/drivers/remoteproc/keystone_remoteproc.c
> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
>   * can be used either by the remoteproc core for loading (when using kernel
>   * remoteproc loader), or by any rpmsg bus drivers.
>   */
> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct keystone_rproc *ksproc = rproc->priv;
>  	void __iomem *va = NULL;
> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
> index e953886b2eb7..7518e67a49e5 100644
> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
> index 471128a2e723..248febde6fc1 100644
> --- a/drivers/remoteproc/qcom_q6v5_mss.c
> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct q6v5 *qproc = rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
> index db4b3c4bacd7..cf2cd609c90d 100644
> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
> index f93e1e4a1cc0..3a6b82a16961 100644
> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct q6v5_wcss *wcss = rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> index dc135754bb9c..f893219e45a8 100644
> --- a/drivers/remoteproc/qcom_wcnss.c
> +++ b/drivers/remoteproc/qcom_wcnss.c
> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 307df98347ba..9e6d3c6a60ee 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>   * here the output of the DMA API for the carveouts, which should be more
>   * correct.
>   */
> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct rproc_mem_entry *carveout;
>  	void *ptr = NULL;
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 493ef9262411..004867061721 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>  void rproc_free_vring(struct rproc_vring *rvring);
>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>  
> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>  int rproc_trigger_recovery(struct rproc *rproc);
>  
> diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
> index 04492fead3c8..2fd14afb3157 100644
> --- a/drivers/remoteproc/st_slim_rproc.c
> +++ b/drivers/remoteproc/st_slim_rproc.c
> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct st_slim_rproc *slim_rproc = rproc->priv;
>  	void *va = NULL;
> diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
> index 3984e585c847..0e8082948489 100644
> --- a/drivers/remoteproc/wkup_m3_rproc.c
> +++ b/drivers/remoteproc/wkup_m3_rproc.c
> @@ -80,7 +80,7 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
>  	void *va = NULL;
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 16ad66683ad0..f84bd5fe0211 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -374,7 +374,7 @@ struct rproc_ops {
>  	int (*start)(struct rproc *rproc);
>  	int (*stop)(struct rproc *rproc);
>  	void (*kick)(struct rproc *rproc, int vqid);
> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
> +	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
>  			  int offset, int avail);
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va
  2020-02-04 16:27                     ` [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va Arnaud POULIQUEN
@ 2020-02-04 17:10                       ` Clément Leger
  2020-02-04 17:42                         ` Arnaud POULIQUEN
  0 siblings, 1 reply; 76+ messages in thread
From: Clément Leger @ 2020-02-04 17:10 UTC (permalink / raw)
  To: Arnaud Pouliquen
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Loic PALLARDY, s-anna, Mathieu Poirier

Hi Arnaud,

My bad, I thought it was only V1.
I will resend it as a V3 with a cover letter.

----- On 4 Feb, 2020, at 17:27, Arnaud Pouliquen arnaud.pouliquen@st.com wrote:

> Hi Clément,
> 
> Is it v2 or V3?
> I also suggest you add a cover letter when you post more than one patch in a
> thread.
> 
> On 2/4/20 3:33 PM, Clement Leger wrote:
>> With upcoming changes in elf loader for elf64 support, section size will
>> be a u64. When used with da_to_va, this will potentially lead to
>> overflow if using the current "int" type for len argument. Change
>> da_to_va prototype to use a u64 for len and fix all users of this
>> function.
>> 
>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> ---
>> V2:
>>  - Change len type from int to u64
>> 
>>  drivers/remoteproc/imx_rproc.c           | 5 +++--
>>  drivers/remoteproc/keystone_remoteproc.c | 2 +-
>>  drivers/remoteproc/qcom_q6v5_adsp.c      | 2 +-
>>  drivers/remoteproc/qcom_q6v5_mss.c       | 2 +-
>>  drivers/remoteproc/qcom_q6v5_pas.c       | 2 +-
>>  drivers/remoteproc/qcom_q6v5_wcss.c      | 2 +-
>>  drivers/remoteproc/qcom_wcnss.c          | 2 +-
>>  drivers/remoteproc/remoteproc_core.c     | 2 +-
>>  drivers/remoteproc/remoteproc_internal.h | 2 +-
>>  drivers/remoteproc/st_slim_rproc.c       | 2 +-
>>  drivers/remoteproc/wkup_m3_rproc.c       | 2 +-
>>  include/linux/remoteproc.h               | 2 +-
>>  12 files changed, 14 insertions(+), 13 deletions(-)
>> 
>> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
>> index 3e72b6f38d4b..7ec79be5eb5d 100644
>> --- a/drivers/remoteproc/imx_rproc.c
>> +++ b/drivers/remoteproc/imx_rproc.c
>> @@ -208,7 +208,7 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64
>> da,
>>  	return -ENOENT;
>>  }
>>  
>> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> I wonder if you could use size_t instead?

I wondered too but size_t is a unsigned int on 32 bits system. So if they load
a elf64 binary (which might be in 32bits zone), the segment size will be
a u64 type.

> Does it make sense for 32-bit system to have a physical address space higher?
> it's an open question I won't pretend to have the answer...:)

I agree that it does not make a lot of sense... But when we discussed it in
OpenAMP WG, it was mentionned that this should be supported. 

> 
> 
>>  {
>>  	struct imx_rproc *priv = rproc->priv;
>>  	void *va = NULL;
>> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da,
>> int len)
> len type to update

I missed this one and I will double check all other callers

Thanks,

Clément. 

> 
> Regards,
> Arnaud
>>  		}
>>  	}
>>  
>> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
>> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n", da, len,
>> +		va);
>>  
>>  	return va;
>>  }
>> diff --git a/drivers/remoteproc/keystone_remoteproc.c
>> b/drivers/remoteproc/keystone_remoteproc.c
>> index 5c4658f00b3d..25c01df47eba 100644
>> --- a/drivers/remoteproc/keystone_remoteproc.c
>> +++ b/drivers/remoteproc/keystone_remoteproc.c
>> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int
>> vqid)
>>   * can be used either by the remoteproc core for loading (when using kernel
>>   * remoteproc loader), or by any rpmsg bus drivers.
>>   */
>> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct keystone_rproc *ksproc = rproc->priv;
>>  	void __iomem *va = NULL;
>> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c
>> b/drivers/remoteproc/qcom_q6v5_adsp.c
>> index e953886b2eb7..7518e67a49e5 100644
>> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
>> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
>> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>>  	return ret;
>>  }
>>  
>> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>>  	int offset;
>> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c
>> b/drivers/remoteproc/qcom_q6v5_mss.c
>> index 471128a2e723..248febde6fc1 100644
>> --- a/drivers/remoteproc/qcom_q6v5_mss.c
>> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
>> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>>  	return 0;
>>  }
>>  
>> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct q6v5 *qproc = rproc->priv;
>>  	int offset;
>> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c
>> b/drivers/remoteproc/qcom_q6v5_pas.c
>> index db4b3c4bacd7..cf2cd609c90d 100644
>> --- a/drivers/remoteproc/qcom_q6v5_pas.c
>> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
>> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>>  	return ret;
>>  }
>>  
>> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>>  	int offset;
>> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c
>> b/drivers/remoteproc/qcom_q6v5_wcss.c
>> index f93e1e4a1cc0..3a6b82a16961 100644
>> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
>> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
>> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>>  	return 0;
>>  }
>>  
>> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct q6v5_wcss *wcss = rproc->priv;
>>  	int offset;
>> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
>> index dc135754bb9c..f893219e45a8 100644
>> --- a/drivers/remoteproc/qcom_wcnss.c
>> +++ b/drivers/remoteproc/qcom_wcnss.c
>> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>>  	return ret;
>>  }
>>  
>> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>>  	int offset;
>> diff --git a/drivers/remoteproc/remoteproc_core.c
>> b/drivers/remoteproc/remoteproc_core.c
>> index 307df98347ba..9e6d3c6a60ee 100644
>> --- a/drivers/remoteproc/remoteproc_core.c
>> +++ b/drivers/remoteproc/remoteproc_core.c
>> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>>   * here the output of the DMA API for the carveouts, which should be more
>>   * correct.
>>   */
>> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct rproc_mem_entry *carveout;
>>  	void *ptr = NULL;
>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> b/drivers/remoteproc/remoteproc_internal.h
>> index 493ef9262411..004867061721 100644
>> --- a/drivers/remoteproc/remoteproc_internal.h
>> +++ b/drivers/remoteproc/remoteproc_internal.h
>> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>>  void rproc_free_vring(struct rproc_vring *rvring);
>>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>>  
>> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
>> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
>>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>>  int rproc_trigger_recovery(struct rproc *rproc);
>>  
>> diff --git a/drivers/remoteproc/st_slim_rproc.c
>> b/drivers/remoteproc/st_slim_rproc.c
>> index 04492fead3c8..2fd14afb3157 100644
>> --- a/drivers/remoteproc/st_slim_rproc.c
>> +++ b/drivers/remoteproc/st_slim_rproc.c
>> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>>  	return 0;
>>  }
>>  
>> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct st_slim_rproc *slim_rproc = rproc->priv;
>>  	void *va = NULL;
>> diff --git a/drivers/remoteproc/wkup_m3_rproc.c
>> b/drivers/remoteproc/wkup_m3_rproc.c
>> index 3984e585c847..0e8082948489 100644
>> --- a/drivers/remoteproc/wkup_m3_rproc.c
>> +++ b/drivers/remoteproc/wkup_m3_rproc.c
>> @@ -80,7 +80,7 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>>  	return 0;
>>  }
>>  
>> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
>>  	void *va = NULL;
>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> index 16ad66683ad0..f84bd5fe0211 100644
>> --- a/include/linux/remoteproc.h
>> +++ b/include/linux/remoteproc.h
>> @@ -374,7 +374,7 @@ struct rproc_ops {
>>  	int (*start)(struct rproc *rproc);
>>  	int (*stop)(struct rproc *rproc);
>>  	void (*kick)(struct rproc *rproc, int vqid);
>> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
>> +	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
>>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
>>  			  int offset, int avail);

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va
  2020-02-04 17:10                       ` Clément Leger
@ 2020-02-04 17:42                         ` Arnaud POULIQUEN
  0 siblings, 0 replies; 76+ messages in thread
From: Arnaud POULIQUEN @ 2020-02-04 17:42 UTC (permalink / raw)
  To: Clément Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Loic PALLARDY, s-anna, Mathieu Poirier



On 2/4/20 6:10 PM, Clément Leger wrote:
> Hi Arnaud,
> 
> My bad, I thought it was only V1.
> I will resend it as a V3 with a cover letter.
> 
> ----- On 4 Feb, 2020, at 17:27, Arnaud Pouliquen arnaud.pouliquen@st.com wrote:
> 
>> Hi Clément,
>>
>> Is it v2 or V3?
>> I also suggest you add a cover letter when you post more than one patch in a
>> thread.
>>
>> On 2/4/20 3:33 PM, Clement Leger wrote:
>>> With upcoming changes in elf loader for elf64 support, section size will
>>> be a u64. When used with da_to_va, this will potentially lead to
>>> overflow if using the current "int" type for len argument. Change
>>> da_to_va prototype to use a u64 for len and fix all users of this
>>> function.
>>>
>>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>>> ---
>>> V2:
>>>  - Change len type from int to u64
>>>
>>>  drivers/remoteproc/imx_rproc.c           | 5 +++--
>>>  drivers/remoteproc/keystone_remoteproc.c | 2 +-
>>>  drivers/remoteproc/qcom_q6v5_adsp.c      | 2 +-
>>>  drivers/remoteproc/qcom_q6v5_mss.c       | 2 +-
>>>  drivers/remoteproc/qcom_q6v5_pas.c       | 2 +-
>>>  drivers/remoteproc/qcom_q6v5_wcss.c      | 2 +-
>>>  drivers/remoteproc/qcom_wcnss.c          | 2 +-
>>>  drivers/remoteproc/remoteproc_core.c     | 2 +-
>>>  drivers/remoteproc/remoteproc_internal.h | 2 +-
>>>  drivers/remoteproc/st_slim_rproc.c       | 2 +-
>>>  drivers/remoteproc/wkup_m3_rproc.c       | 2 +-
>>>  include/linux/remoteproc.h               | 2 +-
>>>  12 files changed, 14 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
>>> index 3e72b6f38d4b..7ec79be5eb5d 100644
>>> --- a/drivers/remoteproc/imx_rproc.c
>>> +++ b/drivers/remoteproc/imx_rproc.c
>>> @@ -208,7 +208,7 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64
>>> da,
>>>  	return -ENOENT;
>>>  }
>>>  
>>> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> I wonder if you could use size_t instead?
> 
> I wondered too but size_t is a unsigned int on 32 bits system. So if they load
> a elf64 binary (which might be in 32bits zone), the segment size will be
> a u64 type.
If we consider that 32-bit processor can not address a memory space size higher than sizeof(size_t), this could be solved by adding a test and a cast.
> 
>> Does it make sense for 32-bit system to have a physical address space higher?
>> it's an open question I won't pretend to have the answer...:)
> 
> I agree that it does not make a lot of sense... But when we discussed it in
> OpenAMP WG, it was mentionned that this should be supported. 
My apologize, i don't remember the discussion around the size.
So if a requirement exists and size_t does not fit, let's use u64.
Nevertheless i'm interested to know the rational, if you remember...

Regards
Arnaud
> 
>>
>>
>>>  {
>>>  	struct imx_rproc *priv = rproc->priv;
>>>  	void *va = NULL;
>>> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da,
>>> int len)
>> len type to update
> 
> I missed this one and I will double check all other callers
> 
> Thanks,
> 
> Clément. 
> 
>>
>> Regards,
>> Arnaud
>>>  		}
>>>  	}
>>>  
>>> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
>>> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n", da, len,
>>> +		va);
>>>  
>>>  	return va;
>>>  }
>>> diff --git a/drivers/remoteproc/keystone_remoteproc.c
>>> b/drivers/remoteproc/keystone_remoteproc.c
>>> index 5c4658f00b3d..25c01df47eba 100644
>>> --- a/drivers/remoteproc/keystone_remoteproc.c
>>> +++ b/drivers/remoteproc/keystone_remoteproc.c
>>> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int
>>> vqid)
>>>   * can be used either by the remoteproc core for loading (when using kernel
>>>   * remoteproc loader), or by any rpmsg bus drivers.
>>>   */
>>> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct keystone_rproc *ksproc = rproc->priv;
>>>  	void __iomem *va = NULL;
>>> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c
>>> b/drivers/remoteproc/qcom_q6v5_adsp.c
>>> index e953886b2eb7..7518e67a49e5 100644
>>> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
>>> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
>>> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>>>  	return ret;
>>>  }
>>>  
>>> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>>>  	int offset;
>>> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c
>>> b/drivers/remoteproc/qcom_q6v5_mss.c
>>> index 471128a2e723..248febde6fc1 100644
>>> --- a/drivers/remoteproc/qcom_q6v5_mss.c
>>> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
>>> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>>>  	return 0;
>>>  }
>>>  
>>> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct q6v5 *qproc = rproc->priv;
>>>  	int offset;
>>> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c
>>> b/drivers/remoteproc/qcom_q6v5_pas.c
>>> index db4b3c4bacd7..cf2cd609c90d 100644
>>> --- a/drivers/remoteproc/qcom_q6v5_pas.c
>>> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
>>> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>>>  	return ret;
>>>  }
>>>  
>>> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>>>  	int offset;
>>> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c
>>> b/drivers/remoteproc/qcom_q6v5_wcss.c
>>> index f93e1e4a1cc0..3a6b82a16961 100644
>>> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
>>> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
>>> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>>>  	return 0;
>>>  }
>>>  
>>> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct q6v5_wcss *wcss = rproc->priv;
>>>  	int offset;
>>> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
>>> index dc135754bb9c..f893219e45a8 100644
>>> --- a/drivers/remoteproc/qcom_wcnss.c
>>> +++ b/drivers/remoteproc/qcom_wcnss.c
>>> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>>>  	return ret;
>>>  }
>>>  
>>> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>>>  	int offset;
>>> diff --git a/drivers/remoteproc/remoteproc_core.c
>>> b/drivers/remoteproc/remoteproc_core.c
>>> index 307df98347ba..9e6d3c6a60ee 100644
>>> --- a/drivers/remoteproc/remoteproc_core.c
>>> +++ b/drivers/remoteproc/remoteproc_core.c
>>> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>>>   * here the output of the DMA API for the carveouts, which should be more
>>>   * correct.
>>>   */
>>> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct rproc_mem_entry *carveout;
>>>  	void *ptr = NULL;
>>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>>> b/drivers/remoteproc/remoteproc_internal.h
>>> index 493ef9262411..004867061721 100644
>>> --- a/drivers/remoteproc/remoteproc_internal.h
>>> +++ b/drivers/remoteproc/remoteproc_internal.h
>>> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>>>  void rproc_free_vring(struct rproc_vring *rvring);
>>>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>>>  
>>> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
>>> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
>>>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>>>  int rproc_trigger_recovery(struct rproc *rproc);
>>>  
>>> diff --git a/drivers/remoteproc/st_slim_rproc.c
>>> b/drivers/remoteproc/st_slim_rproc.c
>>> index 04492fead3c8..2fd14afb3157 100644
>>> --- a/drivers/remoteproc/st_slim_rproc.c
>>> +++ b/drivers/remoteproc/st_slim_rproc.c
>>> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>>>  	return 0;
>>>  }
>>>  
>>> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct st_slim_rproc *slim_rproc = rproc->priv;
>>>  	void *va = NULL;
>>> diff --git a/drivers/remoteproc/wkup_m3_rproc.c
>>> b/drivers/remoteproc/wkup_m3_rproc.c
>>> index 3984e585c847..0e8082948489 100644
>>> --- a/drivers/remoteproc/wkup_m3_rproc.c
>>> +++ b/drivers/remoteproc/wkup_m3_rproc.c
>>> @@ -80,7 +80,7 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>>>  	return 0;
>>>  }
>>>  
>>> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
>>>  	void *va = NULL;
>>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>>> index 16ad66683ad0..f84bd5fe0211 100644
>>> --- a/include/linux/remoteproc.h
>>> +++ b/include/linux/remoteproc.h
>>> @@ -374,7 +374,7 @@ struct rproc_ops {
>>>  	int (*start)(struct rproc *rproc);
>>>  	int (*stop)(struct rproc *rproc);
>>>  	void (*kick)(struct rproc *rproc, int vqid);
>>> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
>>> +	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
>>>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>>>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
>>>  			  int offset, int avail);

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v3 0/2] remoteproc: Add elf64 support to elf loader
  2020-01-29 16:30                 ` Mathieu Poirier
  2020-02-04 14:33                   ` [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va Clement Leger
@ 2020-02-04 17:44                   ` Clement Leger
  2020-02-04 17:44                     ` [PATCH v3 1/2] remoteproc: Use u64 len for da_to_va Clement Leger
  2020-02-04 17:44                     ` [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader Clement Leger
  1 sibling, 2 replies; 76+ messages in thread
From: Clement Leger @ 2020-02-04 17:44 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

This serie add support for elf64 in remoteproc elf loader. 
First patch modifies the type of len argument (in da_to_va) in order
to allow loading elf64 segment with a u64 size.
Second patch is the actual modification in the elf loader to support
elf64 type by using a set of generic macros.

Changes from V2:
 - da_to_va len type changed from int to u64
 - Add check for elf64 header size
 - Add comments for name table parsing
 - Fix typo in "accommodate"

Clement Leger (2):
  remoteproc: Use u64 len for da_to_va
  remoteproc: Add elf64 support in elf loader

 Documentation/remoteproc.txt               |   2 +-
 drivers/remoteproc/imx_rproc.c             |   9 +-
 drivers/remoteproc/keystone_remoteproc.c   |   2 +-
 drivers/remoteproc/qcom_q6v5_adsp.c        |   2 +-
 drivers/remoteproc/qcom_q6v5_mss.c         |   2 +-
 drivers/remoteproc/qcom_q6v5_pas.c         |   2 +-
 drivers/remoteproc/qcom_q6v5_wcss.c        |   2 +-
 drivers/remoteproc/qcom_wcnss.c            |   2 +-
 drivers/remoteproc/remoteproc_core.c       |   2 +-
 drivers/remoteproc/remoteproc_elf_loader.c | 147 ++++++++++++++++++-----------
 drivers/remoteproc/remoteproc_elf_loader.h |  69 ++++++++++++++
 drivers/remoteproc/remoteproc_internal.h   |   4 +-
 drivers/remoteproc/st_remoteproc.c         |   2 +-
 drivers/remoteproc/st_slim_rproc.c         |   4 +-
 drivers/remoteproc/wkup_m3_rproc.c         |   2 +-
 include/linux/remoteproc.h                 |   6 +-
 16 files changed, 184 insertions(+), 75 deletions(-)
 create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h

-- 
2.15.0.276.g89ea799


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v3 1/2] remoteproc: Use u64 len for da_to_va
  2020-02-04 17:44                   ` [PATCH v3 0/2] remoteproc: Add elf64 support to elf loader Clement Leger
@ 2020-02-04 17:44                     ` Clement Leger
  2020-02-05 21:06                       ` Mathieu Poirier
  2020-02-04 17:44                     ` [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader Clement Leger
  1 sibling, 1 reply; 76+ messages in thread
From: Clement Leger @ 2020-02-04 17:44 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

With upcoming changes in elf loader for elf64 support, section size will
be a u64. When used with da_to_va, this will potentially lead to
overflow if using the current "int" type for len argument. Change
da_to_va prototype to use a u64 for len and fix all users of this
function.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/imx_rproc.c           | 9 +++++----
 drivers/remoteproc/keystone_remoteproc.c | 2 +-
 drivers/remoteproc/qcom_q6v5_adsp.c      | 2 +-
 drivers/remoteproc/qcom_q6v5_mss.c       | 2 +-
 drivers/remoteproc/qcom_q6v5_pas.c       | 2 +-
 drivers/remoteproc/qcom_q6v5_wcss.c      | 2 +-
 drivers/remoteproc/qcom_wcnss.c          | 2 +-
 drivers/remoteproc/remoteproc_core.c     | 2 +-
 drivers/remoteproc/remoteproc_internal.h | 2 +-
 drivers/remoteproc/st_slim_rproc.c       | 4 ++--
 drivers/remoteproc/wkup_m3_rproc.c       | 2 +-
 include/linux/remoteproc.h               | 2 +-
 12 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 3e72b6f38d4b..1e895d5cf918 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
 }
 
 static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
-			       int len, u64 *sys)
+			       u64 len, u64 *sys)
 {
 	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
 	int i;
@@ -203,12 +203,12 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
 		}
 	}
 
-	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
+	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
 		 da, len);
 	return -ENOENT;
 }
 
-static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct imx_rproc *priv = rproc->priv;
 	void *va = NULL;
@@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 		}
 	}
 
-	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
+	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
+		da, len, va);
 
 	return va;
 }
diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
index 5c4658f00b3d..25c01df47eba 100644
--- a/drivers/remoteproc/keystone_remoteproc.c
+++ b/drivers/remoteproc/keystone_remoteproc.c
@@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
  * can be used either by the remoteproc core for loading (when using kernel
  * remoteproc loader), or by any rpmsg bus drivers.
  */
-static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct keystone_rproc *ksproc = rproc->priv;
 	void __iomem *va = NULL;
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index e953886b2eb7..7518e67a49e5 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index 471128a2e723..248febde6fc1 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct q6v5 *qproc = rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index db4b3c4bacd7..cf2cd609c90d 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
index f93e1e4a1cc0..3a6b82a16961 100644
--- a/drivers/remoteproc/qcom_q6v5_wcss.c
+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
@@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct q6v5_wcss *wcss = rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index dc135754bb9c..f893219e45a8 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 307df98347ba..9e6d3c6a60ee 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
  * here the output of the DMA API for the carveouts, which should be more
  * correct.
  */
-void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct rproc_mem_entry *carveout;
 	void *ptr = NULL;
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 493ef9262411..004867061721 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
 void rproc_free_vring(struct rproc_vring *rvring);
 int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
 
-void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
+void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
 phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
index 04492fead3c8..fc01cd879b60 100644
--- a/drivers/remoteproc/st_slim_rproc.c
+++ b/drivers/remoteproc/st_slim_rproc.c
@@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct st_slim_rproc *slim_rproc = rproc->priv;
 	void *va = NULL;
@@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 		}
 	}
 
-	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
+	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
 		da, len, va);
 
 	return va;
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
index 3984e585c847..0e8082948489 100644
--- a/drivers/remoteproc/wkup_m3_rproc.c
+++ b/drivers/remoteproc/wkup_m3_rproc.c
@@ -80,7 +80,7 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct wkup_m3_rproc *wkupm3 = rproc->priv;
 	void *va = NULL;
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 16ad66683ad0..f84bd5fe0211 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -374,7 +374,7 @@ struct rproc_ops {
 	int (*start)(struct rproc *rproc);
 	int (*stop)(struct rproc *rproc);
 	void (*kick)(struct rproc *rproc, int vqid);
-	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
+	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
 	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
 	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
 			  int offset, int avail);
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader
  2020-02-04 17:44                   ` [PATCH v3 0/2] remoteproc: Add elf64 support to elf loader Clement Leger
  2020-02-04 17:44                     ` [PATCH v3 1/2] remoteproc: Use u64 len for da_to_va Clement Leger
@ 2020-02-04 17:44                     ` Clement Leger
  2020-02-05 22:49                       ` Mathieu Poirier
  1 sibling, 1 reply; 76+ messages in thread
From: Clement Leger @ 2020-02-04 17:44 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

elf32 and elf64 mainly differ by their types. In order to avoid
copy/pasting the whole loader code, generate static inline functions
which will access values according to the elf class. It allows to keep a
common loader basis.
In order to accommodate both elf types sizes, the maximum size for a
elf header member is chosen using the maximum value of both elf class.

Signed-off-by: Clement Leger <cleger@kalray.eu>
Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
---
 Documentation/remoteproc.txt               |   2 +-
 drivers/remoteproc/remoteproc_elf_loader.c | 147 ++++++++++++++++++-----------
 drivers/remoteproc/remoteproc_elf_loader.h |  69 ++++++++++++++
 drivers/remoteproc/remoteproc_internal.h   |   2 +-
 drivers/remoteproc/st_remoteproc.c         |   2 +-
 include/linux/remoteproc.h                 |   4 +-
 6 files changed, 167 insertions(+), 59 deletions(-)
 create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h

diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
index 03c3d2e568b0..2be1147256e0 100644
--- a/Documentation/remoteproc.txt
+++ b/Documentation/remoteproc.txt
@@ -230,7 +230,7 @@ in the used rings.
 Binary Firmware Structure
 =========================
 
-At this point remoteproc only supports ELF32 firmware binaries. However,
+At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
 it is quite expected that other platforms/devices which we'd want to
 support with this framework will be based on different binary formats.
 
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 606aae166eba..21fd2b2fe5ae 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -23,6 +23,7 @@
 #include <linux/elf.h>
 
 #include "remoteproc_internal.h"
+#include "remoteproc_elf_loader.h"
 
 /**
  * rproc_elf_sanity_check() - Sanity Check ELF firmware image
@@ -35,8 +36,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 {
 	const char *name = rproc->firmware;
 	struct device *dev = &rproc->dev;
+	/*
+	 * Elf files are beginning with the same structure. Thus, to simplify
+	 * header parsing, we can use the elf32_hdr one for both elf64 and
+	 * elf32.
+	 */
 	struct elf32_hdr *ehdr;
+	u32 elf_shdr_size;
+	u64 phoff, shoff;
 	char class;
+	u16 phnum;
 
 	if (!fw) {
 		dev_err(dev, "failed to load %s\n", name);
@@ -50,13 +59,22 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 
 	ehdr = (struct elf32_hdr *)fw->data;
 
-	/* We only support ELF32 at this point */
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(dev, "Image is corrupted (bad magic)\n");
+		return -EINVAL;
+	}
+
 	class = ehdr->e_ident[EI_CLASS];
-	if (class != ELFCLASS32) {
+	if (class != ELFCLASS32 && class != ELFCLASS64) {
 		dev_err(dev, "Unsupported class: %d\n", class);
 		return -EINVAL;
 	}
 
+	if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
+		dev_err(dev, "elf64 header is too small\n");
+		return -EINVAL;
+	}
+
 	/* We assume the firmware has the same endianness as the host */
 # ifdef __LITTLE_ENDIAN
 	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
@@ -67,26 +85,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 		return -EINVAL;
 	}
 
-	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
-		dev_err(dev, "Image is too small\n");
-		return -EINVAL;
-	}
+	phoff = elf_hdr_e_phoff(class, fw->data);
+	shoff = elf_hdr_e_shoff(class, fw->data);
+	phnum =  elf_hdr_e_phnum(class, fw->data);
+	elf_shdr_size = elf_size_of_shdr(class);
 
-	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(dev, "Image is corrupted (bad magic)\n");
+	if (fw->size < shoff + elf_shdr_size) {
+		dev_err(dev, "Image is too small\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phnum == 0) {
+	if (phnum == 0) {
 		dev_err(dev, "No loadable segments\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phoff > fw->size) {
+	if (phoff > fw->size) {
 		dev_err(dev, "Firmware size is too small\n");
 		return -EINVAL;
 	}
 
+	dev_dbg(dev, "Firmware is an elf%d file\n",
+		class == ELFCLASS32 ? 32 : 64);
+
 	return 0;
 }
 EXPORT_SYMBOL(rproc_elf_sanity_check);
@@ -102,11 +123,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
  * Note that the boot address is not a configurable property of all remote
  * processors. Some will always boot at a specific hard-coded address.
  */
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
-
-	return ehdr->e_entry;
+	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
 }
 EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 
@@ -137,37 +156,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 {
 	struct device *dev = &rproc->dev;
-	struct elf32_hdr *ehdr;
-	struct elf32_phdr *phdr;
+	const void *ehdr, *phdr;
 	int i, ret = 0;
+	u16 phnum;
 	const u8 *elf_data = fw->data;
+	u8 class = fw_elf_get_class(fw);
+	u32 elf_phdr_size = elf_size_of_phdr(class);
 
-	ehdr = (struct elf32_hdr *)elf_data;
-	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+	ehdr = elf_data;
+	phnum = elf_hdr_e_phnum(class, ehdr);
+	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
 
 	/* go through the available ELF segments */
-	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-		u32 da = phdr->p_paddr;
-		u32 memsz = phdr->p_memsz;
-		u32 filesz = phdr->p_filesz;
-		u32 offset = phdr->p_offset;
+	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
+		u64 da = elf_phdr_p_paddr(class, phdr);
+		u64 memsz = elf_phdr_p_memsz(class, phdr);
+		u64 filesz = elf_phdr_p_filesz(class, phdr);
+		u64 offset = elf_phdr_p_offset(class, phdr);
+		u32 type = elf_phdr_p_type(class, phdr);
 		void *ptr;
 
-		if (phdr->p_type != PT_LOAD)
+		if (type != PT_LOAD)
 			continue;
 
-		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-			phdr->p_type, da, memsz, filesz);
+		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
+			type, da, memsz, filesz);
 
 		if (filesz > memsz) {
-			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
 				filesz, memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		if (offset + filesz > fw->size) {
-			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
+			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
 				offset + filesz, fw->size);
 			ret = -EINVAL;
 			break;
@@ -176,14 +199,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 		/* grab the kernel address for this device address */
 		ptr = rproc_da_to_va(rproc, da, memsz);
 		if (!ptr) {
-			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
+				memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		/* put the segment where the remote processor expects it */
-		if (phdr->p_filesz)
-			memcpy(ptr, elf_data + phdr->p_offset, filesz);
+		if (filesz)
+			memcpy(ptr, elf_data + offset, filesz);
 
 		/*
 		 * Zero out remaining memory for this segment.
@@ -200,24 +224,35 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 }
 EXPORT_SYMBOL(rproc_elf_load_segments);
 
-static struct elf32_shdr *
-find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
+static const void *
+find_table(struct device *dev, const struct firmware *fw)
 {
-	struct elf32_shdr *shdr;
+	const void *shdr, *name_table_shdr;
 	int i;
 	const char *name_table;
 	struct resource_table *table = NULL;
-	const u8 *elf_data = (void *)ehdr;
+	const u8 *elf_data = (void *)fw->data;
+	u8 class = fw_elf_get_class(fw);
+	size_t fw_size = fw->size;
+	const void *ehdr = elf_data;
+	u16 shnum = elf_hdr_e_shnum(class, ehdr);
+	u32 elf_shdr_size = elf_size_of_shdr(class);
+	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
 
 	/* look for the resource table and handle it */
-	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
-	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
-
-	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
-		u32 size = shdr->sh_size;
-		u32 offset = shdr->sh_offset;
-
-		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+	/* First, get the section header according to the elf class */
+	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
+	/* Compute name table section header entry in shdr array */
+	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
+	/* Finally, compute the name table section address in elf */
+	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
+
+	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
+		u64 size = elf_shdr_sh_size(class, shdr);
+		u64 offset = elf_shdr_sh_offset(class, shdr);
+		u32 name = elf_shdr_sh_name(class, shdr);
+
+		if (strcmp(name_table + name, ".resource_table"))
 			continue;
 
 		table = (struct resource_table *)(elf_data + offset);
@@ -270,21 +305,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
  */
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr;
-	struct elf32_shdr *shdr;
+	const void *shdr;
 	struct device *dev = &rproc->dev;
 	struct resource_table *table = NULL;
 	const u8 *elf_data = fw->data;
 	size_t tablesz;
+	u8 class = fw_elf_get_class(fw);
+	u64 sh_offset;
 
-	ehdr = (struct elf32_hdr *)elf_data;
-
-	shdr = find_table(dev, ehdr, fw->size);
+	shdr = find_table(dev, fw);
 	if (!shdr)
 		return -EINVAL;
 
-	table = (struct resource_table *)(elf_data + shdr->sh_offset);
-	tablesz = shdr->sh_size;
+	sh_offset = elf_shdr_sh_offset(class, shdr);
+	table = (struct resource_table *)(elf_data + sh_offset);
+	tablesz = elf_shdr_sh_size(class, shdr);
 
 	/*
 	 * Create a copy of the resource table. When a virtio device starts
@@ -317,13 +352,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 						       const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
-	struct elf32_shdr *shdr;
+	const void *shdr;
+	u64 sh_addr, sh_size;
+	u8 class = fw_elf_get_class(fw);
 
-	shdr = find_table(&rproc->dev, ehdr, fw->size);
+	shdr = find_table(&rproc->dev, fw);
 	if (!shdr)
 		return NULL;
 
-	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
+	sh_addr = elf_shdr_sh_addr(class, shdr);
+	sh_size = elf_shdr_sh_size(class, shdr);
+
+	return rproc_da_to_va(rproc, sh_addr, sh_size);
 }
 EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
diff --git a/drivers/remoteproc/remoteproc_elf_loader.h b/drivers/remoteproc/remoteproc_elf_loader.h
new file mode 100644
index 000000000000..fac3565734f9
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_elf_loader.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Remote processor elf loader defines
+ *
+ * Copyright (C) 2019 Kalray, Inc.
+ */
+
+#ifndef REMOTEPROC_ELF_LOADER_H
+#define REMOTEPROC_ELF_LOADER_H
+
+#include <linux/elf.h>
+#include <linux/types.h>
+
+/**
+ * fw_elf_get_class - Get elf class
+ * @fw: the ELF firmware image
+ *
+ * Note that we use and elf32_hdr to access the class since the start of the
+ * struct is the same for both elf class
+ *
+ * Return: elf class of the firmware
+ */
+static inline u8 fw_elf_get_class(const struct firmware *fw)
+{
+	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
+
+	return ehdr->e_ident[EI_CLASS];
+}
+
+#define ELF_GET_FIELD(__s, __field, __type) \
+static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
+{ \
+	if (class == ELFCLASS32) \
+		return (__type) ((const struct elf32_##__s *) arg)->__field; \
+	else \
+		return (__type) ((const struct elf64_##__s *) arg)->__field; \
+}
+
+ELF_GET_FIELD(hdr, e_entry, u64)
+ELF_GET_FIELD(hdr, e_phnum, u16)
+ELF_GET_FIELD(hdr, e_shnum, u16)
+ELF_GET_FIELD(hdr, e_phoff, u64)
+ELF_GET_FIELD(hdr, e_shoff, u64)
+ELF_GET_FIELD(hdr, e_shstrndx, u16)
+
+ELF_GET_FIELD(phdr, p_paddr, u64)
+ELF_GET_FIELD(phdr, p_filesz, u64)
+ELF_GET_FIELD(phdr, p_memsz, u64)
+ELF_GET_FIELD(phdr, p_type, u32)
+ELF_GET_FIELD(phdr, p_offset, u64)
+
+ELF_GET_FIELD(shdr, sh_size, u64)
+ELF_GET_FIELD(shdr, sh_offset, u64)
+ELF_GET_FIELD(shdr, sh_name, u32)
+ELF_GET_FIELD(shdr, sh_addr, u64)
+
+#define ELF_STRUCT_SIZE(__s) \
+static inline unsigned long elf_size_of_##__s(u8 class) \
+{ \
+	if (class == ELFCLASS32)\
+		return sizeof(struct elf32_##__s); \
+	else \
+		return sizeof(struct elf64_##__s); \
+}
+
+ELF_STRUCT_SIZE(shdr)
+ELF_STRUCT_SIZE(phdr)
+
+#endif /* REMOTEPROC_ELF_LOADER_H */
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 004867061721..eeb26434220e 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
 int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index ee13d23b43a9..a3268d95a50e 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
 		}
 	}
 
-	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
+	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
 
 	return 0;
 
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index f84bd5fe0211..82cebca9344c 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -382,7 +382,7 @@ struct rproc_ops {
 				struct rproc *rproc, const struct firmware *fw);
 	int (*load)(struct rproc *rproc, const struct firmware *fw);
 	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
-	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
 };
 
 /**
@@ -498,7 +498,7 @@ struct rproc {
 	int num_traces;
 	struct list_head carveouts;
 	struct list_head mappings;
-	u32 bootaddr;
+	u64 bootaddr;
 	struct list_head rvdevs;
 	struct list_head subdevs;
 	struct idr notifyids;
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [PATCH v3 1/2] remoteproc: Use u64 len for da_to_va
  2020-02-04 17:44                     ` [PATCH v3 1/2] remoteproc: Use u64 len for da_to_va Clement Leger
@ 2020-02-05 21:06                       ` Mathieu Poirier
  0 siblings, 0 replies; 76+ messages in thread
From: Mathieu Poirier @ 2020-02-05 21:06 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

Hi Clement,

On Tue, Feb 04, 2020 at 06:44:11PM +0100, Clement Leger wrote:
> With upcoming changes in elf loader for elf64 support, section size will
> be a u64. When used with da_to_va, this will potentially lead to
> overflow if using the current "int" type for len argument. Change
> da_to_va prototype to use a u64 for len and fix all users of this
> function.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>
> ---
>  drivers/remoteproc/imx_rproc.c           | 9 +++++----
>  drivers/remoteproc/keystone_remoteproc.c | 2 +-
>  drivers/remoteproc/qcom_q6v5_adsp.c      | 2 +-
>  drivers/remoteproc/qcom_q6v5_mss.c       | 2 +-
>  drivers/remoteproc/qcom_q6v5_pas.c       | 2 +-
>  drivers/remoteproc/qcom_q6v5_wcss.c      | 2 +-
>  drivers/remoteproc/qcom_wcnss.c          | 2 +-
>  drivers/remoteproc/remoteproc_core.c     | 2 +-
>  drivers/remoteproc/remoteproc_internal.h | 2 +-
>  drivers/remoteproc/st_slim_rproc.c       | 4 ++--
>  drivers/remoteproc/wkup_m3_rproc.c       | 2 +-
>  include/linux/remoteproc.h               | 2 +-
>  12 files changed, 17 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 3e72b6f38d4b..1e895d5cf918 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
>  }
>  
>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
> -			       int len, u64 *sys)
> +			       u64 len, u64 *sys)
>  {
>  	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
>  	int i;
> @@ -203,12 +203,12 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
>  		}
>  	}
>  
> -	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
> +	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
>  		 da, len);
>  	return -ENOENT;
>  }
>  
> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct imx_rproc *priv = rproc->priv;
>  	void *va = NULL;

The condition "if (len <= 0)" at the beginning of the function needs to be
fixed.  


> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  		}
>  	}
>  
> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
> +		da, len, va);
>  
>  	return va;
>  }
> diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
> index 5c4658f00b3d..25c01df47eba 100644
> --- a/drivers/remoteproc/keystone_remoteproc.c
> +++ b/drivers/remoteproc/keystone_remoteproc.c
> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
>   * can be used either by the remoteproc core for loading (when using kernel
>   * remoteproc loader), or by any rpmsg bus drivers.
>   */
> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {

Same comment as above.

>  	struct keystone_rproc *ksproc = rproc->priv;
>  	void __iomem *va = NULL;
> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
> index e953886b2eb7..7518e67a49e5 100644
> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
> index 471128a2e723..248febde6fc1 100644
> --- a/drivers/remoteproc/qcom_q6v5_mss.c
> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct q6v5 *qproc = rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
> index db4b3c4bacd7..cf2cd609c90d 100644
> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
> index f93e1e4a1cc0..3a6b82a16961 100644
> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct q6v5_wcss *wcss = rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> index dc135754bb9c..f893219e45a8 100644
> --- a/drivers/remoteproc/qcom_wcnss.c
> +++ b/drivers/remoteproc/qcom_wcnss.c
> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 307df98347ba..9e6d3c6a60ee 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>   * here the output of the DMA API for the carveouts, which should be more
>   * correct.
>   */
> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct rproc_mem_entry *carveout;
>  	void *ptr = NULL;
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 493ef9262411..004867061721 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>  void rproc_free_vring(struct rproc_vring *rvring);
>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>  
> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>  int rproc_trigger_recovery(struct rproc *rproc);
>  
> diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
> index 04492fead3c8..fc01cd879b60 100644
> --- a/drivers/remoteproc/st_slim_rproc.c
> +++ b/drivers/remoteproc/st_slim_rproc.c
> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct st_slim_rproc *slim_rproc = rproc->priv;
>  	void *va = NULL;
> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  		}
>  	}
>  
> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
>  		da, len, va);
>  
>  	return va;
> diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
> index 3984e585c847..0e8082948489 100644
> --- a/drivers/remoteproc/wkup_m3_rproc.c
> +++ b/drivers/remoteproc/wkup_m3_rproc.c
> @@ -80,7 +80,7 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {

Same comment as above.

>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
>  	void *va = NULL;
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 16ad66683ad0..f84bd5fe0211 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -374,7 +374,7 @@ struct rproc_ops {
>  	int (*start)(struct rproc *rproc);
>  	int (*stop)(struct rproc *rproc);
>  	void (*kick)(struct rproc *rproc, int vqid);
> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
> +	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
>  			  int offset, int avail);
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader
  2020-02-04 17:44                     ` [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader Clement Leger
@ 2020-02-05 22:49                       ` Mathieu Poirier
  2020-02-06  8:37                         ` Clément Leger
  0 siblings, 1 reply; 76+ messages in thread
From: Mathieu Poirier @ 2020-02-05 22:49 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Tue, Feb 04, 2020 at 06:44:12PM +0100, Clement Leger wrote:
> elf32 and elf64 mainly differ by their types. In order to avoid
> copy/pasting the whole loader code, generate static inline functions
> which will access values according to the elf class. It allows to keep a
> common loader basis.
> In order to accommodate both elf types sizes, the maximum size for a
> elf header member is chosen using the maximum value of both elf class.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>
> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
> ---
>  Documentation/remoteproc.txt               |   2 +-
>  drivers/remoteproc/remoteproc_elf_loader.c | 147 ++++++++++++++++++-----------
>  drivers/remoteproc/remoteproc_elf_loader.h |  69 ++++++++++++++
>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
>  drivers/remoteproc/st_remoteproc.c         |   2 +-
>  include/linux/remoteproc.h                 |   4 +-
>  6 files changed, 167 insertions(+), 59 deletions(-)
>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
> 
> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
> index 03c3d2e568b0..2be1147256e0 100644
> --- a/Documentation/remoteproc.txt
> +++ b/Documentation/remoteproc.txt
> @@ -230,7 +230,7 @@ in the used rings.
>  Binary Firmware Structure
>  =========================
>  
> -At this point remoteproc only supports ELF32 firmware binaries. However,
> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
>  it is quite expected that other platforms/devices which we'd want to
>  support with this framework will be based on different binary formats.
>  
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index 606aae166eba..21fd2b2fe5ae 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -23,6 +23,7 @@
>  #include <linux/elf.h>
>  
>  #include "remoteproc_internal.h"
> +#include "remoteproc_elf_loader.h"
>  
>  /**
>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> @@ -35,8 +36,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
>  {
>  	const char *name = rproc->firmware;
>  	struct device *dev = &rproc->dev;
> +	/*
> +	 * Elf files are beginning with the same structure. Thus, to simplify
> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
> +	 * elf32.
> +	 */
>  	struct elf32_hdr *ehdr;
> +	u32 elf_shdr_size;
> +	u64 phoff, shoff;
>  	char class;
> +	u16 phnum;
>  
>  	if (!fw) {
>  		dev_err(dev, "failed to load %s\n", name);
> @@ -50,13 +59,22 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
>  
>  	ehdr = (struct elf32_hdr *)fw->data;
>  
> -	/* We only support ELF32 at this point */
> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> +		dev_err(dev, "Image is corrupted (bad magic)\n");
> +		return -EINVAL;
> +	}
> +
>  	class = ehdr->e_ident[EI_CLASS];
> -	if (class != ELFCLASS32) {
> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
>  		dev_err(dev, "Unsupported class: %d\n", class);
>  		return -EINVAL;
>  	}
>  
> +	if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
> +		dev_err(dev, "elf64 header is too small\n");
> +		return -EINVAL;
> +	}
> +
>  	/* We assume the firmware has the same endianness as the host */
>  # ifdef __LITTLE_ENDIAN
>  	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
> @@ -67,26 +85,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
>  		return -EINVAL;
>  	}
>  
> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
> -		dev_err(dev, "Image is too small\n");
> -		return -EINVAL;
> -	}
> +	phoff = elf_hdr_e_phoff(class, fw->data);
> +	shoff = elf_hdr_e_shoff(class, fw->data);
> +	phnum =  elf_hdr_e_phnum(class, fw->data);
> +	elf_shdr_size = elf_size_of_shdr(class);
>  
> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> -		dev_err(dev, "Image is corrupted (bad magic)\n");
> +	if (fw->size < shoff + elf_shdr_size) {
> +		dev_err(dev, "Image is too small\n");
>  		return -EINVAL;
>  	}
>  
> -	if (ehdr->e_phnum == 0) {
> +	if (phnum == 0) {
>  		dev_err(dev, "No loadable segments\n");
>  		return -EINVAL;
>  	}
>  
> -	if (ehdr->e_phoff > fw->size) {
> +	if (phoff > fw->size) {
>  		dev_err(dev, "Firmware size is too small\n");
>  		return -EINVAL;
>  	}
>  
> +	dev_dbg(dev, "Firmware is an elf%d file\n",
> +		class == ELFCLASS32 ? 32 : 64);
> +
>  	return 0;
>  }
>  EXPORT_SYMBOL(rproc_elf_sanity_check);
> @@ -102,11 +123,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>   * Note that the boot address is not a configurable property of all remote
>   * processors. Some will always boot at a specific hard-coded address.
>   */
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>  {
> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
> -
> -	return ehdr->e_entry;
> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
>  }
>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>  
> @@ -137,37 +156,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  {
>  	struct device *dev = &rproc->dev;
> -	struct elf32_hdr *ehdr;
> -	struct elf32_phdr *phdr;
> +	const void *ehdr, *phdr;
>  	int i, ret = 0;
> +	u16 phnum;
>  	const u8 *elf_data = fw->data;
> +	u8 class = fw_elf_get_class(fw);
> +	u32 elf_phdr_size = elf_size_of_phdr(class);
>  
> -	ehdr = (struct elf32_hdr *)elf_data;
> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> +	ehdr = elf_data;
> +	phnum = elf_hdr_e_phnum(class, ehdr);
> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
>  
>  	/* go through the available ELF segments */
> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> -		u32 da = phdr->p_paddr;
> -		u32 memsz = phdr->p_memsz;
> -		u32 filesz = phdr->p_filesz;
> -		u32 offset = phdr->p_offset;
> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
> +		u64 da = elf_phdr_p_paddr(class, phdr);
> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
> +		u64 offset = elf_phdr_p_offset(class, phdr);
> +		u32 type = elf_phdr_p_type(class, phdr);
>  		void *ptr;
>  
> -		if (phdr->p_type != PT_LOAD)
> +		if (type != PT_LOAD)
>  			continue;
>  
> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
> -			phdr->p_type, da, memsz, filesz);
> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
> +			type, da, memsz, filesz);
>  
>  		if (filesz > memsz) {
> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
>  				filesz, memsz);
>  			ret = -EINVAL;
>  			break;
>  		}
>  
>  		if (offset + filesz > fw->size) {
> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
>  				offset + filesz, fw->size);
>  			ret = -EINVAL;
>  			break;
> @@ -176,14 +199,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  		/* grab the kernel address for this device address */
>  		ptr = rproc_da_to_va(rproc, da, memsz);
>  		if (!ptr) {
> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
> +				memsz);
>  			ret = -EINVAL;
>  			break;
>  		}
>  
>  		/* put the segment where the remote processor expects it */
> -		if (phdr->p_filesz)
> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
> +		if (filesz)
> +			memcpy(ptr, elf_data + offset, filesz);
>  
>  		/*
>  		 * Zero out remaining memory for this segment.
> @@ -200,24 +224,35 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  }
>  EXPORT_SYMBOL(rproc_elf_load_segments);
>  
> -static struct elf32_shdr *
> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> +static const void *
> +find_table(struct device *dev, const struct firmware *fw)
>  {
> -	struct elf32_shdr *shdr;
> +	const void *shdr, *name_table_shdr;
>  	int i;
>  	const char *name_table;
>  	struct resource_table *table = NULL;
> -	const u8 *elf_data = (void *)ehdr;
> +	const u8 *elf_data = (void *)fw->data;
> +	u8 class = fw_elf_get_class(fw);
> +	size_t fw_size = fw->size;
> +	const void *ehdr = elf_data;
> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
> +	u32 elf_shdr_size = elf_size_of_shdr(class);
> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
>  
>  	/* look for the resource table and handle it */
> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
> -
> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> -		u32 size = shdr->sh_size;
> -		u32 offset = shdr->sh_offset;
> -
> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
> +	/* First, get the section header according to the elf class */
> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
> +	/* Compute name table section header entry in shdr array */
> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
> +	/* Finally, compute the name table section address in elf */
> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
> +
> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
> +		u64 size = elf_shdr_sh_size(class, shdr);
> +		u64 offset = elf_shdr_sh_offset(class, shdr);
> +		u32 name = elf_shdr_sh_name(class, shdr);
> +
> +		if (strcmp(name_table + name, ".resource_table"))
>  			continue;
>  
>  		table = (struct resource_table *)(elf_data + offset);
> @@ -270,21 +305,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>   */
>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>  {
> -	struct elf32_hdr *ehdr;
> -	struct elf32_shdr *shdr;
> +	const void *shdr;
>  	struct device *dev = &rproc->dev;
>  	struct resource_table *table = NULL;
>  	const u8 *elf_data = fw->data;
>  	size_t tablesz;
> +	u8 class = fw_elf_get_class(fw);
> +	u64 sh_offset;
>  
> -	ehdr = (struct elf32_hdr *)elf_data;
> -
> -	shdr = find_table(dev, ehdr, fw->size);
> +	shdr = find_table(dev, fw);
>  	if (!shdr)
>  		return -EINVAL;
>  
> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
> -	tablesz = shdr->sh_size;
> +	sh_offset = elf_shdr_sh_offset(class, shdr);
> +	table = (struct resource_table *)(elf_data + sh_offset);
> +	tablesz = elf_shdr_sh_size(class, shdr);
>  
>  	/*
>  	 * Create a copy of the resource table. When a virtio device starts
> @@ -317,13 +352,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>  						       const struct firmware *fw)
>  {
> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> -	struct elf32_shdr *shdr;
> +	const void *shdr;
> +	u64 sh_addr, sh_size;
> +	u8 class = fw_elf_get_class(fw);
>  
> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
> +	shdr = find_table(&rproc->dev, fw);
>  	if (!shdr)
>  		return NULL;
>  
> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
> +	sh_addr = elf_shdr_sh_addr(class, shdr);
> +	sh_size = elf_shdr_sh_size(class, shdr);
> +
> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
>  }
>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h b/drivers/remoteproc/remoteproc_elf_loader.h
> new file mode 100644
> index 000000000000..fac3565734f9
> --- /dev/null
> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
> @@ -0,0 +1,69 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Remote processor elf loader defines
> + *
> + * Copyright (C) 2019 Kalray, Inc.
> + */
> +
> +#ifndef REMOTEPROC_ELF_LOADER_H
> +#define REMOTEPROC_ELF_LOADER_H
> +
> +#include <linux/elf.h>
> +#include <linux/types.h>
> +
> +/**
> + * fw_elf_get_class - Get elf class
> + * @fw: the ELF firmware image
> + *
> + * Note that we use and elf32_hdr to access the class since the start of the
> + * struct is the same for both elf class
> + *
> + * Return: elf class of the firmware
> + */
> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> +{
> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> +
> +	return ehdr->e_ident[EI_CLASS];
> +}
> +
> +#define ELF_GET_FIELD(__s, __field, __type) \
> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
> +{ \
> +	if (class == ELFCLASS32) \
> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
> +	else \
> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
> +}
> +
> +ELF_GET_FIELD(hdr, e_entry, u64)
> +ELF_GET_FIELD(hdr, e_phnum, u16)
> +ELF_GET_FIELD(hdr, e_shnum, u16)
> +ELF_GET_FIELD(hdr, e_phoff, u64)
> +ELF_GET_FIELD(hdr, e_shoff, u64)
> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
> +
> +ELF_GET_FIELD(phdr, p_paddr, u64)
> +ELF_GET_FIELD(phdr, p_filesz, u64)
> +ELF_GET_FIELD(phdr, p_memsz, u64)
> +ELF_GET_FIELD(phdr, p_type, u32)
> +ELF_GET_FIELD(phdr, p_offset, u64)
> +
> +ELF_GET_FIELD(shdr, sh_size, u64)
> +ELF_GET_FIELD(shdr, sh_offset, u64)
> +ELF_GET_FIELD(shdr, sh_name, u32)
> +ELF_GET_FIELD(shdr, sh_addr, u64)
> +
> +#define ELF_STRUCT_SIZE(__s) \
> +static inline unsigned long elf_size_of_##__s(u8 class) \
> +{ \
> +	if (class == ELFCLASS32)\
> +		return sizeof(struct elf32_##__s); \
> +	else \
> +		return sizeof(struct elf64_##__s); \
> +}
> +
> +ELF_STRUCT_SIZE(shdr)
> +ELF_STRUCT_SIZE(phdr)
> +
> +#endif /* REMOTEPROC_ELF_LOADER_H */
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 004867061721..eeb26434220e 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>  int rproc_trigger_recovery(struct rproc *rproc);
>  
>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
> index ee13d23b43a9..a3268d95a50e 100644
> --- a/drivers/remoteproc/st_remoteproc.c
> +++ b/drivers/remoteproc/st_remoteproc.c
> @@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
>  		}
>  	}
>  
> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>  
>  	return 0;
>  
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index f84bd5fe0211..82cebca9344c 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -382,7 +382,7 @@ struct rproc_ops {
>  				struct rproc *rproc, const struct firmware *fw);
>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>  };
>  
>  /**
> @@ -498,7 +498,7 @@ struct rproc {
>  	int num_traces;
>  	struct list_head carveouts;
>  	struct list_head mappings;
> -	u32 bootaddr;
> +	u64 bootaddr;

That will cause problems for rproc_coredump()[1] and fixing it properly 
likely means that a 32 or 64 elf should be generated based on the type of image
that was loaded.  This is also true if ->p_vaddr and ->p_paddr (also in the same
function) are to be handled properly.

I'm interested in your opinion on this.

Thanks,
Mathieu

[1]. https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1600

>  	struct list_head rvdevs;
>  	struct list_head subdevs;
>  	struct idr notifyids;
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader
  2020-02-05 22:49                       ` Mathieu Poirier
@ 2020-02-06  8:37                         ` Clément Leger
  2020-02-06 15:05                           ` Clément Leger
  0 siblings, 1 reply; 76+ messages in thread
From: Clément Leger @ 2020-02-06  8:37 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

Hi Mathieu,

----- On 5 Feb, 2020, at 23:49, Mathieu Poirier mathieu.poirier@linaro.org wrote:

> On Tue, Feb 04, 2020 at 06:44:12PM +0100, Clement Leger wrote:
>> elf32 and elf64 mainly differ by their types. In order to avoid
>> copy/pasting the whole loader code, generate static inline functions
>> which will access values according to the elf class. It allows to keep a
>> common loader basis.
>> In order to accommodate both elf types sizes, the maximum size for a
>> elf header member is chosen using the maximum value of both elf class.
>> 
>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
>> ---
>>  Documentation/remoteproc.txt               |   2 +-
>>  drivers/remoteproc/remoteproc_elf_loader.c | 147 ++++++++++++++++++-----------
>>  drivers/remoteproc/remoteproc_elf_loader.h |  69 ++++++++++++++
>>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
>>  drivers/remoteproc/st_remoteproc.c         |   2 +-
>>  include/linux/remoteproc.h                 |   4 +-
>>  6 files changed, 167 insertions(+), 59 deletions(-)
>>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
>> 
>> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
>> index 03c3d2e568b0..2be1147256e0 100644
>> --- a/Documentation/remoteproc.txt
>> +++ b/Documentation/remoteproc.txt
>> @@ -230,7 +230,7 @@ in the used rings.
>>  Binary Firmware Structure
>>  =========================
>>  
>> -At this point remoteproc only supports ELF32 firmware binaries. However,
>> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
>>  it is quite expected that other platforms/devices which we'd want to
>>  support with this framework will be based on different binary formats.
>>  
>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
>> b/drivers/remoteproc/remoteproc_elf_loader.c
>> index 606aae166eba..21fd2b2fe5ae 100644
>> --- a/drivers/remoteproc/remoteproc_elf_loader.c
>> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
>> @@ -23,6 +23,7 @@
>>  #include <linux/elf.h>
>>  
>>  #include "remoteproc_internal.h"
>> +#include "remoteproc_elf_loader.h"
>>  
>>  /**
>>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
>> @@ -35,8 +36,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> firmware *fw)
>>  {
>>  	const char *name = rproc->firmware;
>>  	struct device *dev = &rproc->dev;
>> +	/*
>> +	 * Elf files are beginning with the same structure. Thus, to simplify
>> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
>> +	 * elf32.
>> +	 */
>>  	struct elf32_hdr *ehdr;
>> +	u32 elf_shdr_size;
>> +	u64 phoff, shoff;
>>  	char class;
>> +	u16 phnum;
>>  
>>  	if (!fw) {
>>  		dev_err(dev, "failed to load %s\n", name);
>> @@ -50,13 +59,22 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> firmware *fw)
>>  
>>  	ehdr = (struct elf32_hdr *)fw->data;
>>  
>> -	/* We only support ELF32 at this point */
>> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> +		dev_err(dev, "Image is corrupted (bad magic)\n");
>> +		return -EINVAL;
>> +	}
>> +
>>  	class = ehdr->e_ident[EI_CLASS];
>> -	if (class != ELFCLASS32) {
>> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
>>  		dev_err(dev, "Unsupported class: %d\n", class);
>>  		return -EINVAL;
>>  	}
>>  
>> +	if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
>> +		dev_err(dev, "elf64 header is too small\n");
>> +		return -EINVAL;
>> +	}
>> +
>>  	/* We assume the firmware has the same endianness as the host */
>>  # ifdef __LITTLE_ENDIAN
>>  	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
>> @@ -67,26 +85,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> firmware *fw)
>>  		return -EINVAL;
>>  	}
>>  
>> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
>> -		dev_err(dev, "Image is too small\n");
>> -		return -EINVAL;
>> -	}
>> +	phoff = elf_hdr_e_phoff(class, fw->data);
>> +	shoff = elf_hdr_e_shoff(class, fw->data);
>> +	phnum =  elf_hdr_e_phnum(class, fw->data);
>> +	elf_shdr_size = elf_size_of_shdr(class);
>>  
>> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> -		dev_err(dev, "Image is corrupted (bad magic)\n");
>> +	if (fw->size < shoff + elf_shdr_size) {
>> +		dev_err(dev, "Image is too small\n");
>>  		return -EINVAL;
>>  	}
>>  
>> -	if (ehdr->e_phnum == 0) {
>> +	if (phnum == 0) {
>>  		dev_err(dev, "No loadable segments\n");
>>  		return -EINVAL;
>>  	}
>>  
>> -	if (ehdr->e_phoff > fw->size) {
>> +	if (phoff > fw->size) {
>>  		dev_err(dev, "Firmware size is too small\n");
>>  		return -EINVAL;
>>  	}
>>  
>> +	dev_dbg(dev, "Firmware is an elf%d file\n",
>> +		class == ELFCLASS32 ? 32 : 64);
>> +
>>  	return 0;
>>  }
>>  EXPORT_SYMBOL(rproc_elf_sanity_check);
>> @@ -102,11 +123,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>>   * Note that the boot address is not a configurable property of all remote
>>   * processors. Some will always boot at a specific hard-coded address.
>>   */
>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>>  {
>> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
>> -
>> -	return ehdr->e_entry;
>> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
>>  }
>>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>>  
>> @@ -137,37 +156,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>>  {
>>  	struct device *dev = &rproc->dev;
>> -	struct elf32_hdr *ehdr;
>> -	struct elf32_phdr *phdr;
>> +	const void *ehdr, *phdr;
>>  	int i, ret = 0;
>> +	u16 phnum;
>>  	const u8 *elf_data = fw->data;
>> +	u8 class = fw_elf_get_class(fw);
>> +	u32 elf_phdr_size = elf_size_of_phdr(class);
>>  
>> -	ehdr = (struct elf32_hdr *)elf_data;
>> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
>> +	ehdr = elf_data;
>> +	phnum = elf_hdr_e_phnum(class, ehdr);
>> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
>>  
>>  	/* go through the available ELF segments */
>> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
>> -		u32 da = phdr->p_paddr;
>> -		u32 memsz = phdr->p_memsz;
>> -		u32 filesz = phdr->p_filesz;
>> -		u32 offset = phdr->p_offset;
>> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
>> +		u64 da = elf_phdr_p_paddr(class, phdr);
>> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
>> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
>> +		u64 offset = elf_phdr_p_offset(class, phdr);
>> +		u32 type = elf_phdr_p_type(class, phdr);
>>  		void *ptr;
>>  
>> -		if (phdr->p_type != PT_LOAD)
>> +		if (type != PT_LOAD)
>>  			continue;
>>  
>> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
>> -			phdr->p_type, da, memsz, filesz);
>> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
>> +			type, da, memsz, filesz);
>>  
>>  		if (filesz > memsz) {
>> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
>> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
>>  				filesz, memsz);
>>  			ret = -EINVAL;
>>  			break;
>>  		}
>>  
>>  		if (offset + filesz > fw->size) {
>> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
>> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
>>  				offset + filesz, fw->size);
>>  			ret = -EINVAL;
>>  			break;
>> @@ -176,14 +199,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> struct firmware *fw)
>>  		/* grab the kernel address for this device address */
>>  		ptr = rproc_da_to_va(rproc, da, memsz);
>>  		if (!ptr) {
>> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
>> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
>> +				memsz);
>>  			ret = -EINVAL;
>>  			break;
>>  		}
>>  
>>  		/* put the segment where the remote processor expects it */
>> -		if (phdr->p_filesz)
>> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
>> +		if (filesz)
>> +			memcpy(ptr, elf_data + offset, filesz);
>>  
>>  		/*
>>  		 * Zero out remaining memory for this segment.
>> @@ -200,24 +224,35 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> struct firmware *fw)
>>  }
>>  EXPORT_SYMBOL(rproc_elf_load_segments);
>>  
>> -static struct elf32_shdr *
>> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>> +static const void *
>> +find_table(struct device *dev, const struct firmware *fw)
>>  {
>> -	struct elf32_shdr *shdr;
>> +	const void *shdr, *name_table_shdr;
>>  	int i;
>>  	const char *name_table;
>>  	struct resource_table *table = NULL;
>> -	const u8 *elf_data = (void *)ehdr;
>> +	const u8 *elf_data = (void *)fw->data;
>> +	u8 class = fw_elf_get_class(fw);
>> +	size_t fw_size = fw->size;
>> +	const void *ehdr = elf_data;
>> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
>> +	u32 elf_shdr_size = elf_size_of_shdr(class);
>> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
>>  
>>  	/* look for the resource table and handle it */
>> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
>> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
>> -
>> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
>> -		u32 size = shdr->sh_size;
>> -		u32 offset = shdr->sh_offset;
>> -
>> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
>> +	/* First, get the section header according to the elf class */
>> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
>> +	/* Compute name table section header entry in shdr array */
>> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
>> +	/* Finally, compute the name table section address in elf */
>> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
>> +
>> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
>> +		u64 size = elf_shdr_sh_size(class, shdr);
>> +		u64 offset = elf_shdr_sh_offset(class, shdr);
>> +		u32 name = elf_shdr_sh_name(class, shdr);
>> +
>> +		if (strcmp(name_table + name, ".resource_table"))
>>  			continue;
>>  
>>  		table = (struct resource_table *)(elf_data + offset);
>> @@ -270,21 +305,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
>> size_t fw_size)
>>   */
>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>>  {
>> -	struct elf32_hdr *ehdr;
>> -	struct elf32_shdr *shdr;
>> +	const void *shdr;
>>  	struct device *dev = &rproc->dev;
>>  	struct resource_table *table = NULL;
>>  	const u8 *elf_data = fw->data;
>>  	size_t tablesz;
>> +	u8 class = fw_elf_get_class(fw);
>> +	u64 sh_offset;
>>  
>> -	ehdr = (struct elf32_hdr *)elf_data;
>> -
>> -	shdr = find_table(dev, ehdr, fw->size);
>> +	shdr = find_table(dev, fw);
>>  	if (!shdr)
>>  		return -EINVAL;
>>  
>> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
>> -	tablesz = shdr->sh_size;
>> +	sh_offset = elf_shdr_sh_offset(class, shdr);
>> +	table = (struct resource_table *)(elf_data + sh_offset);
>> +	tablesz = elf_shdr_sh_size(class, shdr);
>>  
>>  	/*
>>  	 * Create a copy of the resource table. When a virtio device starts
>> @@ -317,13 +352,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>>  						       const struct firmware *fw)
>>  {
>> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> -	struct elf32_shdr *shdr;
>> +	const void *shdr;
>> +	u64 sh_addr, sh_size;
>> +	u8 class = fw_elf_get_class(fw);
>>  
>> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
>> +	shdr = find_table(&rproc->dev, fw);
>>  	if (!shdr)
>>  		return NULL;
>>  
>> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
>> +	sh_addr = elf_shdr_sh_addr(class, shdr);
>> +	sh_size = elf_shdr_sh_size(class, shdr);
>> +
>> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
>>  }
>>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
>> b/drivers/remoteproc/remoteproc_elf_loader.h
>> new file mode 100644
>> index 000000000000..fac3565734f9
>> --- /dev/null
>> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
>> @@ -0,0 +1,69 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +/*
>> + * Remote processor elf loader defines
>> + *
>> + * Copyright (C) 2019 Kalray, Inc.
>> + */
>> +
>> +#ifndef REMOTEPROC_ELF_LOADER_H
>> +#define REMOTEPROC_ELF_LOADER_H
>> +
>> +#include <linux/elf.h>
>> +#include <linux/types.h>
>> +
>> +/**
>> + * fw_elf_get_class - Get elf class
>> + * @fw: the ELF firmware image
>> + *
>> + * Note that we use and elf32_hdr to access the class since the start of the
>> + * struct is the same for both elf class
>> + *
>> + * Return: elf class of the firmware
>> + */
>> +static inline u8 fw_elf_get_class(const struct firmware *fw)
>> +{
>> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> +
>> +	return ehdr->e_ident[EI_CLASS];
>> +}
>> +
>> +#define ELF_GET_FIELD(__s, __field, __type) \
>> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
>> +{ \
>> +	if (class == ELFCLASS32) \
>> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
>> +	else \
>> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
>> +}
>> +
>> +ELF_GET_FIELD(hdr, e_entry, u64)
>> +ELF_GET_FIELD(hdr, e_phnum, u16)
>> +ELF_GET_FIELD(hdr, e_shnum, u16)
>> +ELF_GET_FIELD(hdr, e_phoff, u64)
>> +ELF_GET_FIELD(hdr, e_shoff, u64)
>> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
>> +
>> +ELF_GET_FIELD(phdr, p_paddr, u64)
>> +ELF_GET_FIELD(phdr, p_filesz, u64)
>> +ELF_GET_FIELD(phdr, p_memsz, u64)
>> +ELF_GET_FIELD(phdr, p_type, u32)
>> +ELF_GET_FIELD(phdr, p_offset, u64)
>> +
>> +ELF_GET_FIELD(shdr, sh_size, u64)
>> +ELF_GET_FIELD(shdr, sh_offset, u64)
>> +ELF_GET_FIELD(shdr, sh_name, u32)
>> +ELF_GET_FIELD(shdr, sh_addr, u64)
>> +
>> +#define ELF_STRUCT_SIZE(__s) \
>> +static inline unsigned long elf_size_of_##__s(u8 class) \
>> +{ \
>> +	if (class == ELFCLASS32)\
>> +		return sizeof(struct elf32_##__s); \
>> +	else \
>> +		return sizeof(struct elf64_##__s); \
>> +}
>> +
>> +ELF_STRUCT_SIZE(shdr)
>> +ELF_STRUCT_SIZE(phdr)
>> +
>> +#endif /* REMOTEPROC_ELF_LOADER_H */
>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> b/drivers/remoteproc/remoteproc_internal.h
>> index 004867061721..eeb26434220e 100644
>> --- a/drivers/remoteproc/remoteproc_internal.h
>> +++ b/drivers/remoteproc/remoteproc_internal.h
>> @@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>>  int rproc_trigger_recovery(struct rproc *rproc);
>>  
>>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>> diff --git a/drivers/remoteproc/st_remoteproc.c
>> b/drivers/remoteproc/st_remoteproc.c
>> index ee13d23b43a9..a3268d95a50e 100644
>> --- a/drivers/remoteproc/st_remoteproc.c
>> +++ b/drivers/remoteproc/st_remoteproc.c
>> @@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
>>  		}
>>  	}
>>  
>> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
>> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>>  
>>  	return 0;
>>  
>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> index f84bd5fe0211..82cebca9344c 100644
>> --- a/include/linux/remoteproc.h
>> +++ b/include/linux/remoteproc.h
>> @@ -382,7 +382,7 @@ struct rproc_ops {
>>  				struct rproc *rproc, const struct firmware *fw);
>>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
>>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
>> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>>  };
>>  
>>  /**
>> @@ -498,7 +498,7 @@ struct rproc {
>>  	int num_traces;
>>  	struct list_head carveouts;
>>  	struct list_head mappings;
>> -	u32 bootaddr;
>> +	u64 bootaddr;
> 
> That will cause problems for rproc_coredump()[1] and fixing it properly
> likely means that a 32 or 64 elf should be generated based on the type of image
> that was loaded.  This is also true if ->p_vaddr and ->p_paddr (also in the same
> function) are to be handled properly.
> 
> I'm interested in your opinion on this.

Indeed, you are right !

I'm "afraid" I will have to fix that !
Most sane thing to do is to dump an elf with the input elf class.
I will make a V4 with a patch for that.

Thanks,

Clément

> 
> Thanks,
> Mathieu
> 
> [1].
> https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1600
> 
>>  	struct list_head rvdevs;
>>  	struct list_head subdevs;
>>  	struct idr notifyids;
>> --
>> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader
  2020-02-06  8:37                         ` Clément Leger
@ 2020-02-06 15:05                           ` Clément Leger
  2020-02-06 17:48                             ` Mathieu Poirier
  0 siblings, 1 reply; 76+ messages in thread
From: Clément Leger @ 2020-02-06 15:05 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

Hi Mathieu,

----- On 6 Feb, 2020, at 09:37, Clément Leger cleger@kalray.eu wrote:

> Hi Mathieu,
> 
> ----- On 5 Feb, 2020, at 23:49, Mathieu Poirier mathieu.poirier@linaro.org
> wrote:
> 
>> On Tue, Feb 04, 2020 at 06:44:12PM +0100, Clement Leger wrote:
>>> elf32 and elf64 mainly differ by their types. In order to avoid
>>> copy/pasting the whole loader code, generate static inline functions
>>> which will access values according to the elf class. It allows to keep a
>>> common loader basis.
>>> In order to accommodate both elf types sizes, the maximum size for a
>>> elf header member is chosen using the maximum value of both elf class.
>>> 
>>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>>> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
>>> ---
>>>  Documentation/remoteproc.txt               |   2 +-
>>>  drivers/remoteproc/remoteproc_elf_loader.c | 147 ++++++++++++++++++-----------
>>>  drivers/remoteproc/remoteproc_elf_loader.h |  69 ++++++++++++++
>>>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
>>>  drivers/remoteproc/st_remoteproc.c         |   2 +-
>>>  include/linux/remoteproc.h                 |   4 +-
>>>  6 files changed, 167 insertions(+), 59 deletions(-)
>>>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
>>> 
>>> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
>>> index 03c3d2e568b0..2be1147256e0 100644
>>> --- a/Documentation/remoteproc.txt
>>> +++ b/Documentation/remoteproc.txt
>>> @@ -230,7 +230,7 @@ in the used rings.
>>>  Binary Firmware Structure
>>>  =========================
>>>  
>>> -At this point remoteproc only supports ELF32 firmware binaries. However,
>>> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
>>>  it is quite expected that other platforms/devices which we'd want to
>>>  support with this framework will be based on different binary formats.
>>>  
>>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
>>> b/drivers/remoteproc/remoteproc_elf_loader.c
>>> index 606aae166eba..21fd2b2fe5ae 100644
>>> --- a/drivers/remoteproc/remoteproc_elf_loader.c
>>> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
>>> @@ -23,6 +23,7 @@
>>>  #include <linux/elf.h>
>>>  
>>>  #include "remoteproc_internal.h"
>>> +#include "remoteproc_elf_loader.h"
>>>  
>>>  /**
>>>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
>>> @@ -35,8 +36,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>>> firmware *fw)
>>>  {
>>>  	const char *name = rproc->firmware;
>>>  	struct device *dev = &rproc->dev;
>>> +	/*
>>> +	 * Elf files are beginning with the same structure. Thus, to simplify
>>> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
>>> +	 * elf32.
>>> +	 */
>>>  	struct elf32_hdr *ehdr;
>>> +	u32 elf_shdr_size;
>>> +	u64 phoff, shoff;
>>>  	char class;
>>> +	u16 phnum;
>>>  
>>>  	if (!fw) {
>>>  		dev_err(dev, "failed to load %s\n", name);
>>> @@ -50,13 +59,22 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>>> firmware *fw)
>>>  
>>>  	ehdr = (struct elf32_hdr *)fw->data;
>>>  
>>> -	/* We only support ELF32 at this point */
>>> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>>> +		dev_err(dev, "Image is corrupted (bad magic)\n");
>>> +		return -EINVAL;
>>> +	}
>>> +
>>>  	class = ehdr->e_ident[EI_CLASS];
>>> -	if (class != ELFCLASS32) {
>>> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
>>>  		dev_err(dev, "Unsupported class: %d\n", class);
>>>  		return -EINVAL;
>>>  	}
>>>  
>>> +	if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
>>> +		dev_err(dev, "elf64 header is too small\n");
>>> +		return -EINVAL;
>>> +	}
>>> +
>>>  	/* We assume the firmware has the same endianness as the host */
>>>  # ifdef __LITTLE_ENDIAN
>>>  	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
>>> @@ -67,26 +85,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>>> firmware *fw)
>>>  		return -EINVAL;
>>>  	}
>>>  
>>> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
>>> -		dev_err(dev, "Image is too small\n");
>>> -		return -EINVAL;
>>> -	}
>>> +	phoff = elf_hdr_e_phoff(class, fw->data);
>>> +	shoff = elf_hdr_e_shoff(class, fw->data);
>>> +	phnum =  elf_hdr_e_phnum(class, fw->data);
>>> +	elf_shdr_size = elf_size_of_shdr(class);
>>>  
>>> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>>> -		dev_err(dev, "Image is corrupted (bad magic)\n");
>>> +	if (fw->size < shoff + elf_shdr_size) {
>>> +		dev_err(dev, "Image is too small\n");
>>>  		return -EINVAL;
>>>  	}
>>>  
>>> -	if (ehdr->e_phnum == 0) {
>>> +	if (phnum == 0) {
>>>  		dev_err(dev, "No loadable segments\n");
>>>  		return -EINVAL;
>>>  	}
>>>  
>>> -	if (ehdr->e_phoff > fw->size) {
>>> +	if (phoff > fw->size) {
>>>  		dev_err(dev, "Firmware size is too small\n");
>>>  		return -EINVAL;
>>>  	}
>>>  
>>> +	dev_dbg(dev, "Firmware is an elf%d file\n",
>>> +		class == ELFCLASS32 ? 32 : 64);
>>> +
>>>  	return 0;
>>>  }
>>>  EXPORT_SYMBOL(rproc_elf_sanity_check);
>>> @@ -102,11 +123,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>>>   * Note that the boot address is not a configurable property of all remote
>>>   * processors. Some will always boot at a specific hard-coded address.
>>>   */
>>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>>>  {
>>> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
>>> -
>>> -	return ehdr->e_entry;
>>> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
>>>  }
>>>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>>>  
>>> @@ -137,37 +156,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>>>  {
>>>  	struct device *dev = &rproc->dev;
>>> -	struct elf32_hdr *ehdr;
>>> -	struct elf32_phdr *phdr;
>>> +	const void *ehdr, *phdr;
>>>  	int i, ret = 0;
>>> +	u16 phnum;
>>>  	const u8 *elf_data = fw->data;
>>> +	u8 class = fw_elf_get_class(fw);
>>> +	u32 elf_phdr_size = elf_size_of_phdr(class);
>>>  
>>> -	ehdr = (struct elf32_hdr *)elf_data;
>>> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
>>> +	ehdr = elf_data;
>>> +	phnum = elf_hdr_e_phnum(class, ehdr);
>>> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
>>>  
>>>  	/* go through the available ELF segments */
>>> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
>>> -		u32 da = phdr->p_paddr;
>>> -		u32 memsz = phdr->p_memsz;
>>> -		u32 filesz = phdr->p_filesz;
>>> -		u32 offset = phdr->p_offset;
>>> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
>>> +		u64 da = elf_phdr_p_paddr(class, phdr);
>>> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
>>> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
>>> +		u64 offset = elf_phdr_p_offset(class, phdr);
>>> +		u32 type = elf_phdr_p_type(class, phdr);
>>>  		void *ptr;
>>>  
>>> -		if (phdr->p_type != PT_LOAD)
>>> +		if (type != PT_LOAD)
>>>  			continue;
>>>  
>>> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
>>> -			phdr->p_type, da, memsz, filesz);
>>> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
>>> +			type, da, memsz, filesz);
>>>  
>>>  		if (filesz > memsz) {
>>> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
>>> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
>>>  				filesz, memsz);
>>>  			ret = -EINVAL;
>>>  			break;
>>>  		}
>>>  
>>>  		if (offset + filesz > fw->size) {
>>> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
>>> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
>>>  				offset + filesz, fw->size);
>>>  			ret = -EINVAL;
>>>  			break;
>>> @@ -176,14 +199,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>>> struct firmware *fw)
>>>  		/* grab the kernel address for this device address */
>>>  		ptr = rproc_da_to_va(rproc, da, memsz);
>>>  		if (!ptr) {
>>> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
>>> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
>>> +				memsz);
>>>  			ret = -EINVAL;
>>>  			break;
>>>  		}
>>>  
>>>  		/* put the segment where the remote processor expects it */
>>> -		if (phdr->p_filesz)
>>> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
>>> +		if (filesz)
>>> +			memcpy(ptr, elf_data + offset, filesz);
>>>  
>>>  		/*
>>>  		 * Zero out remaining memory for this segment.
>>> @@ -200,24 +224,35 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>>> struct firmware *fw)
>>>  }
>>>  EXPORT_SYMBOL(rproc_elf_load_segments);
>>>  
>>> -static struct elf32_shdr *
>>> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>>> +static const void *
>>> +find_table(struct device *dev, const struct firmware *fw)
>>>  {
>>> -	struct elf32_shdr *shdr;
>>> +	const void *shdr, *name_table_shdr;
>>>  	int i;
>>>  	const char *name_table;
>>>  	struct resource_table *table = NULL;
>>> -	const u8 *elf_data = (void *)ehdr;
>>> +	const u8 *elf_data = (void *)fw->data;
>>> +	u8 class = fw_elf_get_class(fw);
>>> +	size_t fw_size = fw->size;
>>> +	const void *ehdr = elf_data;
>>> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
>>> +	u32 elf_shdr_size = elf_size_of_shdr(class);
>>> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
>>>  
>>>  	/* look for the resource table and handle it */
>>> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
>>> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
>>> -
>>> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
>>> -		u32 size = shdr->sh_size;
>>> -		u32 offset = shdr->sh_offset;
>>> -
>>> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
>>> +	/* First, get the section header according to the elf class */
>>> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
>>> +	/* Compute name table section header entry in shdr array */
>>> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
>>> +	/* Finally, compute the name table section address in elf */
>>> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
>>> +
>>> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
>>> +		u64 size = elf_shdr_sh_size(class, shdr);
>>> +		u64 offset = elf_shdr_sh_offset(class, shdr);
>>> +		u32 name = elf_shdr_sh_name(class, shdr);
>>> +
>>> +		if (strcmp(name_table + name, ".resource_table"))
>>>  			continue;
>>>  
>>>  		table = (struct resource_table *)(elf_data + offset);
>>> @@ -270,21 +305,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
>>> size_t fw_size)
>>>   */
>>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>>>  {
>>> -	struct elf32_hdr *ehdr;
>>> -	struct elf32_shdr *shdr;
>>> +	const void *shdr;
>>>  	struct device *dev = &rproc->dev;
>>>  	struct resource_table *table = NULL;
>>>  	const u8 *elf_data = fw->data;
>>>  	size_t tablesz;
>>> +	u8 class = fw_elf_get_class(fw);
>>> +	u64 sh_offset;
>>>  
>>> -	ehdr = (struct elf32_hdr *)elf_data;
>>> -
>>> -	shdr = find_table(dev, ehdr, fw->size);
>>> +	shdr = find_table(dev, fw);
>>>  	if (!shdr)
>>>  		return -EINVAL;
>>>  
>>> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
>>> -	tablesz = shdr->sh_size;
>>> +	sh_offset = elf_shdr_sh_offset(class, shdr);
>>> +	table = (struct resource_table *)(elf_data + sh_offset);
>>> +	tablesz = elf_shdr_sh_size(class, shdr);
>>>  
>>>  	/*
>>>  	 * Create a copy of the resource table. When a virtio device starts
>>> @@ -317,13 +352,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
>>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>>>  						       const struct firmware *fw)
>>>  {
>>> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>>> -	struct elf32_shdr *shdr;
>>> +	const void *shdr;
>>> +	u64 sh_addr, sh_size;
>>> +	u8 class = fw_elf_get_class(fw);
>>>  
>>> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
>>> +	shdr = find_table(&rproc->dev, fw);
>>>  	if (!shdr)
>>>  		return NULL;
>>>  
>>> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
>>> +	sh_addr = elf_shdr_sh_addr(class, shdr);
>>> +	sh_size = elf_shdr_sh_size(class, shdr);
>>> +
>>> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
>>>  }
>>>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
>>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
>>> b/drivers/remoteproc/remoteproc_elf_loader.h
>>> new file mode 100644
>>> index 000000000000..fac3565734f9
>>> --- /dev/null
>>> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
>>> @@ -0,0 +1,69 @@
>>> +/* SPDX-License-Identifier: GPL-2.0 */
>>> +/*
>>> + * Remote processor elf loader defines
>>> + *
>>> + * Copyright (C) 2019 Kalray, Inc.
>>> + */
>>> +
>>> +#ifndef REMOTEPROC_ELF_LOADER_H
>>> +#define REMOTEPROC_ELF_LOADER_H
>>> +
>>> +#include <linux/elf.h>
>>> +#include <linux/types.h>
>>> +
>>> +/**
>>> + * fw_elf_get_class - Get elf class
>>> + * @fw: the ELF firmware image
>>> + *
>>> + * Note that we use and elf32_hdr to access the class since the start of the
>>> + * struct is the same for both elf class
>>> + *
>>> + * Return: elf class of the firmware
>>> + */
>>> +static inline u8 fw_elf_get_class(const struct firmware *fw)
>>> +{
>>> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>>> +
>>> +	return ehdr->e_ident[EI_CLASS];
>>> +}
>>> +
>>> +#define ELF_GET_FIELD(__s, __field, __type) \
>>> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
>>> +{ \
>>> +	if (class == ELFCLASS32) \
>>> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
>>> +	else \
>>> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
>>> +}
>>> +
>>> +ELF_GET_FIELD(hdr, e_entry, u64)
>>> +ELF_GET_FIELD(hdr, e_phnum, u16)
>>> +ELF_GET_FIELD(hdr, e_shnum, u16)
>>> +ELF_GET_FIELD(hdr, e_phoff, u64)
>>> +ELF_GET_FIELD(hdr, e_shoff, u64)
>>> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
>>> +
>>> +ELF_GET_FIELD(phdr, p_paddr, u64)
>>> +ELF_GET_FIELD(phdr, p_filesz, u64)
>>> +ELF_GET_FIELD(phdr, p_memsz, u64)
>>> +ELF_GET_FIELD(phdr, p_type, u32)
>>> +ELF_GET_FIELD(phdr, p_offset, u64)
>>> +
>>> +ELF_GET_FIELD(shdr, sh_size, u64)
>>> +ELF_GET_FIELD(shdr, sh_offset, u64)
>>> +ELF_GET_FIELD(shdr, sh_name, u32)
>>> +ELF_GET_FIELD(shdr, sh_addr, u64)
>>> +
>>> +#define ELF_STRUCT_SIZE(__s) \
>>> +static inline unsigned long elf_size_of_##__s(u8 class) \
>>> +{ \
>>> +	if (class == ELFCLASS32)\
>>> +		return sizeof(struct elf32_##__s); \
>>> +	else \
>>> +		return sizeof(struct elf64_##__s); \
>>> +}
>>> +
>>> +ELF_STRUCT_SIZE(shdr)
>>> +ELF_STRUCT_SIZE(phdr)
>>> +
>>> +#endif /* REMOTEPROC_ELF_LOADER_H */
>>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>>> b/drivers/remoteproc/remoteproc_internal.h
>>> index 004867061721..eeb26434220e 100644
>>> --- a/drivers/remoteproc/remoteproc_internal.h
>>> +++ b/drivers/remoteproc/remoteproc_internal.h
>>> @@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>>>  int rproc_trigger_recovery(struct rproc *rproc);
>>>  
>>>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
>>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>>> diff --git a/drivers/remoteproc/st_remoteproc.c
>>> b/drivers/remoteproc/st_remoteproc.c
>>> index ee13d23b43a9..a3268d95a50e 100644
>>> --- a/drivers/remoteproc/st_remoteproc.c
>>> +++ b/drivers/remoteproc/st_remoteproc.c
>>> @@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
>>>  		}
>>>  	}
>>>  
>>> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
>>> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>>>  
>>>  	return 0;
>>>  
>>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>>> index f84bd5fe0211..82cebca9344c 100644
>>> --- a/include/linux/remoteproc.h
>>> +++ b/include/linux/remoteproc.h
>>> @@ -382,7 +382,7 @@ struct rproc_ops {
>>>  				struct rproc *rproc, const struct firmware *fw);
>>>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
>>>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
>>> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>>> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>>>  };
>>>  
>>>  /**
>>> @@ -498,7 +498,7 @@ struct rproc {
>>>  	int num_traces;
>>>  	struct list_head carveouts;
>>>  	struct list_head mappings;
>>> -	u32 bootaddr;
>>> +	u64 bootaddr;
>> 
>> That will cause problems for rproc_coredump()[1] and fixing it properly
>> likely means that a 32 or 64 elf should be generated based on the type of image
>> that was loaded.  This is also true if ->p_vaddr and ->p_paddr (also in the same
>> function) are to be handled properly.
>> 
>> I'm interested in your opinion on this.
> 
> Indeed, you are right !
> 
> I'm "afraid" I will have to fix that !
> Most sane thing to do is to dump an elf with the input elf class.
> I will make a V4 with a patch for that.
> 

Actually, this does not seems directly related to elf loading.
The coredump mecanism dumps segment that have been registered
using rproc_coredump_add_*_segment and this is not done directly
by the elf loader.
I'm not 100% sure but the coredump elf format is not tied to
any machine (EM_NONE) and as a special type (ET_CORE) so the elf
type is probably not relevant adn elf64 would be generic.
If some coredump user could speak for that part, that would be
nice !

If needed, then we could add a rproc_coredump_set_format() function
to specify various parameters (machine, elf type, lsb/msb, etc).

Let me know what you think about it.

Clément

> Thanks,
> 
> Clément
> 
>> 
>> Thanks,
>> Mathieu
>> 
>> [1].
>> https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1600
>> 
>>>  	struct list_head rvdevs;
>>>  	struct list_head subdevs;
>>>  	struct idr notifyids;
>>> --
> >> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader
  2020-02-06 15:05                           ` Clément Leger
@ 2020-02-06 17:48                             ` Mathieu Poirier
  2020-02-07  7:57                               ` Clément Leger
  0 siblings, 1 reply; 76+ messages in thread
From: Mathieu Poirier @ 2020-02-06 17:48 UTC (permalink / raw)
  To: Clément Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Thu, Feb 06, 2020 at 04:05:44PM +0100, Clément Leger wrote:
> Hi Mathieu,
> 
> ----- On 6 Feb, 2020, at 09:37, Clément Leger cleger@kalray.eu wrote:
> 
> > Hi Mathieu,
> > 
> > ----- On 5 Feb, 2020, at 23:49, Mathieu Poirier mathieu.poirier@linaro.org
> > wrote:
> > 
> >> On Tue, Feb 04, 2020 at 06:44:12PM +0100, Clement Leger wrote:
> >>> elf32 and elf64 mainly differ by their types. In order to avoid
> >>> copy/pasting the whole loader code, generate static inline functions
> >>> which will access values according to the elf class. It allows to keep a
> >>> common loader basis.
> >>> In order to accommodate both elf types sizes, the maximum size for a
> >>> elf header member is chosen using the maximum value of both elf class.
> >>> 
> >>> Signed-off-by: Clement Leger <cleger@kalray.eu>
> >>> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
> >>> ---
> >>>  Documentation/remoteproc.txt               |   2 +-
> >>>  drivers/remoteproc/remoteproc_elf_loader.c | 147 ++++++++++++++++++-----------
> >>>  drivers/remoteproc/remoteproc_elf_loader.h |  69 ++++++++++++++
> >>>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
> >>>  drivers/remoteproc/st_remoteproc.c         |   2 +-
> >>>  include/linux/remoteproc.h                 |   4 +-
> >>>  6 files changed, 167 insertions(+), 59 deletions(-)
> >>>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
> >>> 
> >>> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
> >>> index 03c3d2e568b0..2be1147256e0 100644
> >>> --- a/Documentation/remoteproc.txt
> >>> +++ b/Documentation/remoteproc.txt
> >>> @@ -230,7 +230,7 @@ in the used rings.
> >>>  Binary Firmware Structure
> >>>  =========================
> >>>  
> >>> -At this point remoteproc only supports ELF32 firmware binaries. However,
> >>> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
> >>>  it is quite expected that other platforms/devices which we'd want to
> >>>  support with this framework will be based on different binary formats.
> >>>  
> >>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
> >>> b/drivers/remoteproc/remoteproc_elf_loader.c
> >>> index 606aae166eba..21fd2b2fe5ae 100644
> >>> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> >>> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> >>> @@ -23,6 +23,7 @@
> >>>  #include <linux/elf.h>
> >>>  
> >>>  #include "remoteproc_internal.h"
> >>> +#include "remoteproc_elf_loader.h"
> >>>  
> >>>  /**
> >>>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> >>> @@ -35,8 +36,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >>> firmware *fw)
> >>>  {
> >>>  	const char *name = rproc->firmware;
> >>>  	struct device *dev = &rproc->dev;
> >>> +	/*
> >>> +	 * Elf files are beginning with the same structure. Thus, to simplify
> >>> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
> >>> +	 * elf32.
> >>> +	 */
> >>>  	struct elf32_hdr *ehdr;
> >>> +	u32 elf_shdr_size;
> >>> +	u64 phoff, shoff;
> >>>  	char class;
> >>> +	u16 phnum;
> >>>  
> >>>  	if (!fw) {
> >>>  		dev_err(dev, "failed to load %s\n", name);
> >>> @@ -50,13 +59,22 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >>> firmware *fw)
> >>>  
> >>>  	ehdr = (struct elf32_hdr *)fw->data;
> >>>  
> >>> -	/* We only support ELF32 at this point */
> >>> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> >>> +		dev_err(dev, "Image is corrupted (bad magic)\n");
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>>  	class = ehdr->e_ident[EI_CLASS];
> >>> -	if (class != ELFCLASS32) {
> >>> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
> >>>  		dev_err(dev, "Unsupported class: %d\n", class);
> >>>  		return -EINVAL;
> >>>  	}
> >>>  
> >>> +	if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
> >>> +		dev_err(dev, "elf64 header is too small\n");
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>>  	/* We assume the firmware has the same endianness as the host */
> >>>  # ifdef __LITTLE_ENDIAN
> >>>  	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
> >>> @@ -67,26 +85,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >>> firmware *fw)
> >>>  		return -EINVAL;
> >>>  	}
> >>>  
> >>> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
> >>> -		dev_err(dev, "Image is too small\n");
> >>> -		return -EINVAL;
> >>> -	}
> >>> +	phoff = elf_hdr_e_phoff(class, fw->data);
> >>> +	shoff = elf_hdr_e_shoff(class, fw->data);
> >>> +	phnum =  elf_hdr_e_phnum(class, fw->data);
> >>> +	elf_shdr_size = elf_size_of_shdr(class);
> >>>  
> >>> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
> >>> -		dev_err(dev, "Image is corrupted (bad magic)\n");
> >>> +	if (fw->size < shoff + elf_shdr_size) {
> >>> +		dev_err(dev, "Image is too small\n");
> >>>  		return -EINVAL;
> >>>  	}
> >>>  
> >>> -	if (ehdr->e_phnum == 0) {
> >>> +	if (phnum == 0) {
> >>>  		dev_err(dev, "No loadable segments\n");
> >>>  		return -EINVAL;
> >>>  	}
> >>>  
> >>> -	if (ehdr->e_phoff > fw->size) {
> >>> +	if (phoff > fw->size) {
> >>>  		dev_err(dev, "Firmware size is too small\n");
> >>>  		return -EINVAL;
> >>>  	}
> >>>  
> >>> +	dev_dbg(dev, "Firmware is an elf%d file\n",
> >>> +		class == ELFCLASS32 ? 32 : 64);
> >>> +
> >>>  	return 0;
> >>>  }
> >>>  EXPORT_SYMBOL(rproc_elf_sanity_check);
> >>> @@ -102,11 +123,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
> >>>   * Note that the boot address is not a configurable property of all remote
> >>>   * processors. Some will always boot at a specific hard-coded address.
> >>>   */
> >>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> >>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> >>>  {
> >>> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
> >>> -
> >>> -	return ehdr->e_entry;
> >>> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
> >>>  }
> >>>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> >>>  
> >>> @@ -137,37 +156,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
> >>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
> >>>  {
> >>>  	struct device *dev = &rproc->dev;
> >>> -	struct elf32_hdr *ehdr;
> >>> -	struct elf32_phdr *phdr;
> >>> +	const void *ehdr, *phdr;
> >>>  	int i, ret = 0;
> >>> +	u16 phnum;
> >>>  	const u8 *elf_data = fw->data;
> >>> +	u8 class = fw_elf_get_class(fw);
> >>> +	u32 elf_phdr_size = elf_size_of_phdr(class);
> >>>  
> >>> -	ehdr = (struct elf32_hdr *)elf_data;
> >>> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
> >>> +	ehdr = elf_data;
> >>> +	phnum = elf_hdr_e_phnum(class, ehdr);
> >>> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
> >>>  
> >>>  	/* go through the available ELF segments */
> >>> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
> >>> -		u32 da = phdr->p_paddr;
> >>> -		u32 memsz = phdr->p_memsz;
> >>> -		u32 filesz = phdr->p_filesz;
> >>> -		u32 offset = phdr->p_offset;
> >>> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
> >>> +		u64 da = elf_phdr_p_paddr(class, phdr);
> >>> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
> >>> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
> >>> +		u64 offset = elf_phdr_p_offset(class, phdr);
> >>> +		u32 type = elf_phdr_p_type(class, phdr);
> >>>  		void *ptr;
> >>>  
> >>> -		if (phdr->p_type != PT_LOAD)
> >>> +		if (type != PT_LOAD)
> >>>  			continue;
> >>>  
> >>> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
> >>> -			phdr->p_type, da, memsz, filesz);
> >>> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
> >>> +			type, da, memsz, filesz);
> >>>  
> >>>  		if (filesz > memsz) {
> >>> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
> >>> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
> >>>  				filesz, memsz);
> >>>  			ret = -EINVAL;
> >>>  			break;
> >>>  		}
> >>>  
> >>>  		if (offset + filesz > fw->size) {
> >>> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
> >>> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
> >>>  				offset + filesz, fw->size);
> >>>  			ret = -EINVAL;
> >>>  			break;
> >>> @@ -176,14 +199,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> >>> struct firmware *fw)
> >>>  		/* grab the kernel address for this device address */
> >>>  		ptr = rproc_da_to_va(rproc, da, memsz);
> >>>  		if (!ptr) {
> >>> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> >>> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
> >>> +				memsz);
> >>>  			ret = -EINVAL;
> >>>  			break;
> >>>  		}
> >>>  
> >>>  		/* put the segment where the remote processor expects it */
> >>> -		if (phdr->p_filesz)
> >>> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
> >>> +		if (filesz)
> >>> +			memcpy(ptr, elf_data + offset, filesz);
> >>>  
> >>>  		/*
> >>>  		 * Zero out remaining memory for this segment.
> >>> @@ -200,24 +224,35 @@ int rproc_elf_load_segments(struct rproc *rproc, const
> >>> struct firmware *fw)
> >>>  }
> >>>  EXPORT_SYMBOL(rproc_elf_load_segments);
> >>>  
> >>> -static struct elf32_shdr *
> >>> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> >>> +static const void *
> >>> +find_table(struct device *dev, const struct firmware *fw)
> >>>  {
> >>> -	struct elf32_shdr *shdr;
> >>> +	const void *shdr, *name_table_shdr;
> >>>  	int i;
> >>>  	const char *name_table;
> >>>  	struct resource_table *table = NULL;
> >>> -	const u8 *elf_data = (void *)ehdr;
> >>> +	const u8 *elf_data = (void *)fw->data;
> >>> +	u8 class = fw_elf_get_class(fw);
> >>> +	size_t fw_size = fw->size;
> >>> +	const void *ehdr = elf_data;
> >>> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
> >>> +	u32 elf_shdr_size = elf_size_of_shdr(class);
> >>> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
> >>>  
> >>>  	/* look for the resource table and handle it */
> >>> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> >>> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
> >>> -
> >>> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> >>> -		u32 size = shdr->sh_size;
> >>> -		u32 offset = shdr->sh_offset;
> >>> -
> >>> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
> >>> +	/* First, get the section header according to the elf class */
> >>> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
> >>> +	/* Compute name table section header entry in shdr array */
> >>> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
> >>> +	/* Finally, compute the name table section address in elf */
> >>> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
> >>> +
> >>> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
> >>> +		u64 size = elf_shdr_sh_size(class, shdr);
> >>> +		u64 offset = elf_shdr_sh_offset(class, shdr);
> >>> +		u32 name = elf_shdr_sh_name(class, shdr);
> >>> +
> >>> +		if (strcmp(name_table + name, ".resource_table"))
> >>>  			continue;
> >>>  
> >>>  		table = (struct resource_table *)(elf_data + offset);
> >>> @@ -270,21 +305,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
> >>> size_t fw_size)
> >>>   */
> >>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
> >>>  {
> >>> -	struct elf32_hdr *ehdr;
> >>> -	struct elf32_shdr *shdr;
> >>> +	const void *shdr;
> >>>  	struct device *dev = &rproc->dev;
> >>>  	struct resource_table *table = NULL;
> >>>  	const u8 *elf_data = fw->data;
> >>>  	size_t tablesz;
> >>> +	u8 class = fw_elf_get_class(fw);
> >>> +	u64 sh_offset;
> >>>  
> >>> -	ehdr = (struct elf32_hdr *)elf_data;
> >>> -
> >>> -	shdr = find_table(dev, ehdr, fw->size);
> >>> +	shdr = find_table(dev, fw);
> >>>  	if (!shdr)
> >>>  		return -EINVAL;
> >>>  
> >>> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
> >>> -	tablesz = shdr->sh_size;
> >>> +	sh_offset = elf_shdr_sh_offset(class, shdr);
> >>> +	table = (struct resource_table *)(elf_data + sh_offset);
> >>> +	tablesz = elf_shdr_sh_size(class, shdr);
> >>>  
> >>>  	/*
> >>>  	 * Create a copy of the resource table. When a virtio device starts
> >>> @@ -317,13 +352,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
> >>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> >>>  						       const struct firmware *fw)
> >>>  {
> >>> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> >>> -	struct elf32_shdr *shdr;
> >>> +	const void *shdr;
> >>> +	u64 sh_addr, sh_size;
> >>> +	u8 class = fw_elf_get_class(fw);
> >>>  
> >>> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
> >>> +	shdr = find_table(&rproc->dev, fw);
> >>>  	if (!shdr)
> >>>  		return NULL;
> >>>  
> >>> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
> >>> +	sh_addr = elf_shdr_sh_addr(class, shdr);
> >>> +	sh_size = elf_shdr_sh_size(class, shdr);
> >>> +
> >>> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
> >>>  }
> >>>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> >>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
> >>> b/drivers/remoteproc/remoteproc_elf_loader.h
> >>> new file mode 100644
> >>> index 000000000000..fac3565734f9
> >>> --- /dev/null
> >>> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
> >>> @@ -0,0 +1,69 @@
> >>> +/* SPDX-License-Identifier: GPL-2.0 */
> >>> +/*
> >>> + * Remote processor elf loader defines
> >>> + *
> >>> + * Copyright (C) 2019 Kalray, Inc.
> >>> + */
> >>> +
> >>> +#ifndef REMOTEPROC_ELF_LOADER_H
> >>> +#define REMOTEPROC_ELF_LOADER_H
> >>> +
> >>> +#include <linux/elf.h>
> >>> +#include <linux/types.h>
> >>> +
> >>> +/**
> >>> + * fw_elf_get_class - Get elf class
> >>> + * @fw: the ELF firmware image
> >>> + *
> >>> + * Note that we use and elf32_hdr to access the class since the start of the
> >>> + * struct is the same for both elf class
> >>> + *
> >>> + * Return: elf class of the firmware
> >>> + */
> >>> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> >>> +{
> >>> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> >>> +
> >>> +	return ehdr->e_ident[EI_CLASS];
> >>> +}
> >>> +
> >>> +#define ELF_GET_FIELD(__s, __field, __type) \
> >>> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
> >>> +{ \
> >>> +	if (class == ELFCLASS32) \
> >>> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
> >>> +	else \
> >>> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
> >>> +}
> >>> +
> >>> +ELF_GET_FIELD(hdr, e_entry, u64)
> >>> +ELF_GET_FIELD(hdr, e_phnum, u16)
> >>> +ELF_GET_FIELD(hdr, e_shnum, u16)
> >>> +ELF_GET_FIELD(hdr, e_phoff, u64)
> >>> +ELF_GET_FIELD(hdr, e_shoff, u64)
> >>> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
> >>> +
> >>> +ELF_GET_FIELD(phdr, p_paddr, u64)
> >>> +ELF_GET_FIELD(phdr, p_filesz, u64)
> >>> +ELF_GET_FIELD(phdr, p_memsz, u64)
> >>> +ELF_GET_FIELD(phdr, p_type, u32)
> >>> +ELF_GET_FIELD(phdr, p_offset, u64)
> >>> +
> >>> +ELF_GET_FIELD(shdr, sh_size, u64)
> >>> +ELF_GET_FIELD(shdr, sh_offset, u64)
> >>> +ELF_GET_FIELD(shdr, sh_name, u32)
> >>> +ELF_GET_FIELD(shdr, sh_addr, u64)
> >>> +
> >>> +#define ELF_STRUCT_SIZE(__s) \
> >>> +static inline unsigned long elf_size_of_##__s(u8 class) \
> >>> +{ \
> >>> +	if (class == ELFCLASS32)\
> >>> +		return sizeof(struct elf32_##__s); \
> >>> +	else \
> >>> +		return sizeof(struct elf64_##__s); \
> >>> +}
> >>> +
> >>> +ELF_STRUCT_SIZE(shdr)
> >>> +ELF_STRUCT_SIZE(phdr)
> >>> +
> >>> +#endif /* REMOTEPROC_ELF_LOADER_H */
> >>> diff --git a/drivers/remoteproc/remoteproc_internal.h
> >>> b/drivers/remoteproc/remoteproc_internal.h
> >>> index 004867061721..eeb26434220e 100644
> >>> --- a/drivers/remoteproc/remoteproc_internal.h
> >>> +++ b/drivers/remoteproc/remoteproc_internal.h
> >>> @@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
> >>>  int rproc_trigger_recovery(struct rproc *rproc);
> >>>  
> >>>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> >>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
> >>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
> >>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> >>> diff --git a/drivers/remoteproc/st_remoteproc.c
> >>> b/drivers/remoteproc/st_remoteproc.c
> >>> index ee13d23b43a9..a3268d95a50e 100644
> >>> --- a/drivers/remoteproc/st_remoteproc.c
> >>> +++ b/drivers/remoteproc/st_remoteproc.c
> >>> @@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
> >>>  		}
> >>>  	}
> >>>  
> >>> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> >>> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
> >>>  
> >>>  	return 0;
> >>>  
> >>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> >>> index f84bd5fe0211..82cebca9344c 100644
> >>> --- a/include/linux/remoteproc.h
> >>> +++ b/include/linux/remoteproc.h
> >>> @@ -382,7 +382,7 @@ struct rproc_ops {
> >>>  				struct rproc *rproc, const struct firmware *fw);
> >>>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
> >>>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> >>> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> >>> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> >>>  };
> >>>  
> >>>  /**
> >>> @@ -498,7 +498,7 @@ struct rproc {
> >>>  	int num_traces;
> >>>  	struct list_head carveouts;
> >>>  	struct list_head mappings;
> >>> -	u32 bootaddr;
> >>> +	u64 bootaddr;
> >> 
> >> That will cause problems for rproc_coredump()[1] and fixing it properly
> >> likely means that a 32 or 64 elf should be generated based on the type of image
> >> that was loaded.  This is also true if ->p_vaddr and ->p_paddr (also in the same
> >> function) are to be handled properly.
> >> 
> >> I'm interested in your opinion on this.
> > 
> > Indeed, you are right !
> > 
> > I'm "afraid" I will have to fix that !
> > Most sane thing to do is to dump an elf with the input elf class.
> > I will make a V4 with a patch for that.
> > 
> 
> Actually, this does not seems directly related to elf loading.
> The coredump mecanism dumps segment that have been registered
> using rproc_coredump_add_*_segment and this is not done directly
> by the elf loader.

Correct, but it is fair to assume rpoc_coredump_add_*_segment() is called for
the image that will run on the MCU (otherwiser doing so would be pointless).

> I'm not 100% sure but the coredump elf format is not tied to
> any machine (EM_NONE) and as a special type (ET_CORE) so the elf
> type is probably not relevant adn elf64 would be generic.
 
That is true, we could generate an elf64 core dump for both 32 and 64 bit MCU
image and be done with it.  But that is almost guaranteed to break some user
space that isn't tailored to deal with an elf64.

> If some coredump user could speak for that part, that would be
> nice !
> 
> If needed, then we could add a rproc_coredump_set_format() function
> to specify various parameters (machine, elf type, lsb/msb, etc).
> 

For this specific patchset I don't think you need to cover cases where this much
flexibility is needed (up to now it hasn't been a requiment).

Keeping track of the type of image being loaded in something like
rproc::elfclass and use that information to generate the right elf core in
rproc_coredump() is probably sufficient for the time being.

> Let me know what you think about it.
> 
> Clément
> 
> > Thanks,
> > 
> > Clément
> > 
> >> 
> >> Thanks,
> >> Mathieu
> >> 
> >> [1].
> >> https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1600
> >> 
> >>>  	struct list_head rvdevs;
> >>>  	struct list_head subdevs;
> >>>  	struct idr notifyids;
> >>> --
> > >> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader
  2020-02-06 17:48                             ` Mathieu Poirier
@ 2020-02-07  7:57                               ` Clément Leger
  2020-02-10 16:22                                 ` [PATCH v4 0/5] remoteproc: Add elf64 support Clement Leger
  0 siblings, 1 reply; 76+ messages in thread
From: Clément Leger @ 2020-02-07  7:57 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna



----- On 6 Feb, 2020, at 18:48, Mathieu Poirier mathieu.poirier@linaro.org wrote:

> On Thu, Feb 06, 2020 at 04:05:44PM +0100, Clément Leger wrote:
>> Hi Mathieu,
>> 
>> ----- On 6 Feb, 2020, at 09:37, Clément Leger cleger@kalray.eu wrote:
>> 
>> > Hi Mathieu,
>> > 
>> > ----- On 5 Feb, 2020, at 23:49, Mathieu Poirier mathieu.poirier@linaro.org
>> > wrote:
>> > 
>> >> On Tue, Feb 04, 2020 at 06:44:12PM +0100, Clement Leger wrote:
>> >>> elf32 and elf64 mainly differ by their types. In order to avoid
>> >>> copy/pasting the whole loader code, generate static inline functions
>> >>> which will access values according to the elf class. It allows to keep a
>> >>> common loader basis.
>> >>> In order to accommodate both elf types sizes, the maximum size for a
>> >>> elf header member is chosen using the maximum value of both elf class.
>> >>> 
>> >>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> >>> Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
>> >>> ---
>> >>>  Documentation/remoteproc.txt               |   2 +-
>> >>>  drivers/remoteproc/remoteproc_elf_loader.c | 147 ++++++++++++++++++-----------
>> >>>  drivers/remoteproc/remoteproc_elf_loader.h |  69 ++++++++++++++
>> >>>  drivers/remoteproc/remoteproc_internal.h   |   2 +-
>> >>>  drivers/remoteproc/st_remoteproc.c         |   2 +-
>> >>>  include/linux/remoteproc.h                 |   4 +-
>> >>>  6 files changed, 167 insertions(+), 59 deletions(-)
>> >>>  create mode 100644 drivers/remoteproc/remoteproc_elf_loader.h
>> >>> 
>> >>> diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
>> >>> index 03c3d2e568b0..2be1147256e0 100644
>> >>> --- a/Documentation/remoteproc.txt
>> >>> +++ b/Documentation/remoteproc.txt
>> >>> @@ -230,7 +230,7 @@ in the used rings.
>> >>>  Binary Firmware Structure
>> >>>  =========================
>> >>>  
>> >>> -At this point remoteproc only supports ELF32 firmware binaries. However,
>> >>> +At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
>> >>>  it is quite expected that other platforms/devices which we'd want to
>> >>>  support with this framework will be based on different binary formats.
>> >>>  
>> >>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
>> >>> b/drivers/remoteproc/remoteproc_elf_loader.c
>> >>> index 606aae166eba..21fd2b2fe5ae 100644
>> >>> --- a/drivers/remoteproc/remoteproc_elf_loader.c
>> >>> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
>> >>> @@ -23,6 +23,7 @@
>> >>>  #include <linux/elf.h>
>> >>>  
>> >>>  #include "remoteproc_internal.h"
>> >>> +#include "remoteproc_elf_loader.h"
>> >>>  
>> >>>  /**
>> >>>   * rproc_elf_sanity_check() - Sanity Check ELF firmware image
>> >>> @@ -35,8 +36,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> >>> firmware *fw)
>> >>>  {
>> >>>  	const char *name = rproc->firmware;
>> >>>  	struct device *dev = &rproc->dev;
>> >>> +	/*
>> >>> +	 * Elf files are beginning with the same structure. Thus, to simplify
>> >>> +	 * header parsing, we can use the elf32_hdr one for both elf64 and
>> >>> +	 * elf32.
>> >>> +	 */
>> >>>  	struct elf32_hdr *ehdr;
>> >>> +	u32 elf_shdr_size;
>> >>> +	u64 phoff, shoff;
>> >>>  	char class;
>> >>> +	u16 phnum;
>> >>>  
>> >>>  	if (!fw) {
>> >>>  		dev_err(dev, "failed to load %s\n", name);
>> >>> @@ -50,13 +59,22 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> >>> firmware *fw)
>> >>>  
>> >>>  	ehdr = (struct elf32_hdr *)fw->data;
>> >>>  
>> >>> -	/* We only support ELF32 at this point */
>> >>> +	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> >>> +		dev_err(dev, "Image is corrupted (bad magic)\n");
>> >>> +		return -EINVAL;
>> >>> +	}
>> >>> +
>> >>>  	class = ehdr->e_ident[EI_CLASS];
>> >>> -	if (class != ELFCLASS32) {
>> >>> +	if (class != ELFCLASS32 && class != ELFCLASS64) {
>> >>>  		dev_err(dev, "Unsupported class: %d\n", class);
>> >>>  		return -EINVAL;
>> >>>  	}
>> >>>  
>> >>> +	if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
>> >>> +		dev_err(dev, "elf64 header is too small\n");
>> >>> +		return -EINVAL;
>> >>> +	}
>> >>> +
>> >>>  	/* We assume the firmware has the same endianness as the host */
>> >>>  # ifdef __LITTLE_ENDIAN
>> >>>  	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
>> >>> @@ -67,26 +85,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> >>> firmware *fw)
>> >>>  		return -EINVAL;
>> >>>  	}
>> >>>  
>> >>> -	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
>> >>> -		dev_err(dev, "Image is too small\n");
>> >>> -		return -EINVAL;
>> >>> -	}
>> >>> +	phoff = elf_hdr_e_phoff(class, fw->data);
>> >>> +	shoff = elf_hdr_e_shoff(class, fw->data);
>> >>> +	phnum =  elf_hdr_e_phnum(class, fw->data);
>> >>> +	elf_shdr_size = elf_size_of_shdr(class);
>> >>>  
>> >>> -	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
>> >>> -		dev_err(dev, "Image is corrupted (bad magic)\n");
>> >>> +	if (fw->size < shoff + elf_shdr_size) {
>> >>> +		dev_err(dev, "Image is too small\n");
>> >>>  		return -EINVAL;
>> >>>  	}
>> >>>  
>> >>> -	if (ehdr->e_phnum == 0) {
>> >>> +	if (phnum == 0) {
>> >>>  		dev_err(dev, "No loadable segments\n");
>> >>>  		return -EINVAL;
>> >>>  	}
>> >>>  
>> >>> -	if (ehdr->e_phoff > fw->size) {
>> >>> +	if (phoff > fw->size) {
>> >>>  		dev_err(dev, "Firmware size is too small\n");
>> >>>  		return -EINVAL;
>> >>>  	}
>> >>>  
>> >>> +	dev_dbg(dev, "Firmware is an elf%d file\n",
>> >>> +		class == ELFCLASS32 ? 32 : 64);
>> >>> +
>> >>>  	return 0;
>> >>>  }
>> >>>  EXPORT_SYMBOL(rproc_elf_sanity_check);
>> >>> @@ -102,11 +123,9 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>> >>>   * Note that the boot address is not a configurable property of all remote
>> >>>   * processors. Some will always boot at a specific hard-coded address.
>> >>>   */
>> >>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> >>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> >>>  {
>> >>> -	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
>> >>> -
>> >>> -	return ehdr->e_entry;
>> >>> +	return elf_hdr_e_entry(fw_elf_get_class(fw), fw->data);
>> >>>  }
>> >>>  EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>> >>>  
>> >>> @@ -137,37 +156,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
>> >>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>> >>>  {
>> >>>  	struct device *dev = &rproc->dev;
>> >>> -	struct elf32_hdr *ehdr;
>> >>> -	struct elf32_phdr *phdr;
>> >>> +	const void *ehdr, *phdr;
>> >>>  	int i, ret = 0;
>> >>> +	u16 phnum;
>> >>>  	const u8 *elf_data = fw->data;
>> >>> +	u8 class = fw_elf_get_class(fw);
>> >>> +	u32 elf_phdr_size = elf_size_of_phdr(class);
>> >>>  
>> >>> -	ehdr = (struct elf32_hdr *)elf_data;
>> >>> -	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
>> >>> +	ehdr = elf_data;
>> >>> +	phnum = elf_hdr_e_phnum(class, ehdr);
>> >>> +	phdr = elf_data + elf_hdr_e_phoff(class, ehdr);
>> >>>  
>> >>>  	/* go through the available ELF segments */
>> >>> -	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
>> >>> -		u32 da = phdr->p_paddr;
>> >>> -		u32 memsz = phdr->p_memsz;
>> >>> -		u32 filesz = phdr->p_filesz;
>> >>> -		u32 offset = phdr->p_offset;
>> >>> +	for (i = 0; i < phnum; i++, phdr += elf_phdr_size) {
>> >>> +		u64 da = elf_phdr_p_paddr(class, phdr);
>> >>> +		u64 memsz = elf_phdr_p_memsz(class, phdr);
>> >>> +		u64 filesz = elf_phdr_p_filesz(class, phdr);
>> >>> +		u64 offset = elf_phdr_p_offset(class, phdr);
>> >>> +		u32 type = elf_phdr_p_type(class, phdr);
>> >>>  		void *ptr;
>> >>>  
>> >>> -		if (phdr->p_type != PT_LOAD)
>> >>> +		if (type != PT_LOAD)
>> >>>  			continue;
>> >>>  
>> >>> -		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
>> >>> -			phdr->p_type, da, memsz, filesz);
>> >>> +		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
>> >>> +			type, da, memsz, filesz);
>> >>>  
>> >>>  		if (filesz > memsz) {
>> >>> -			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
>> >>> +			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
>> >>>  				filesz, memsz);
>> >>>  			ret = -EINVAL;
>> >>>  			break;
>> >>>  		}
>> >>>  
>> >>>  		if (offset + filesz > fw->size) {
>> >>> -			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
>> >>> +			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
>> >>>  				offset + filesz, fw->size);
>> >>>  			ret = -EINVAL;
>> >>>  			break;
>> >>> @@ -176,14 +199,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> >>> struct firmware *fw)
>> >>>  		/* grab the kernel address for this device address */
>> >>>  		ptr = rproc_da_to_va(rproc, da, memsz);
>> >>>  		if (!ptr) {
>> >>> -			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
>> >>> +			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
>> >>> +				memsz);
>> >>>  			ret = -EINVAL;
>> >>>  			break;
>> >>>  		}
>> >>>  
>> >>>  		/* put the segment where the remote processor expects it */
>> >>> -		if (phdr->p_filesz)
>> >>> -			memcpy(ptr, elf_data + phdr->p_offset, filesz);
>> >>> +		if (filesz)
>> >>> +			memcpy(ptr, elf_data + offset, filesz);
>> >>>  
>> >>>  		/*
>> >>>  		 * Zero out remaining memory for this segment.
>> >>> @@ -200,24 +224,35 @@ int rproc_elf_load_segments(struct rproc *rproc, const
>> >>> struct firmware *fw)
>> >>>  }
>> >>>  EXPORT_SYMBOL(rproc_elf_load_segments);
>> >>>  
>> >>> -static struct elf32_shdr *
>> >>> -find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
>> >>> +static const void *
>> >>> +find_table(struct device *dev, const struct firmware *fw)
>> >>>  {
>> >>> -	struct elf32_shdr *shdr;
>> >>> +	const void *shdr, *name_table_shdr;
>> >>>  	int i;
>> >>>  	const char *name_table;
>> >>>  	struct resource_table *table = NULL;
>> >>> -	const u8 *elf_data = (void *)ehdr;
>> >>> +	const u8 *elf_data = (void *)fw->data;
>> >>> +	u8 class = fw_elf_get_class(fw);
>> >>> +	size_t fw_size = fw->size;
>> >>> +	const void *ehdr = elf_data;
>> >>> +	u16 shnum = elf_hdr_e_shnum(class, ehdr);
>> >>> +	u32 elf_shdr_size = elf_size_of_shdr(class);
>> >>> +	u16 shstrndx = elf_hdr_e_shstrndx(class, ehdr);
>> >>>  
>> >>>  	/* look for the resource table and handle it */
>> >>> -	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
>> >>> -	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
>> >>> -
>> >>> -	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
>> >>> -		u32 size = shdr->sh_size;
>> >>> -		u32 offset = shdr->sh_offset;
>> >>> -
>> >>> -		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
>> >>> +	/* First, get the section header according to the elf class */
>> >>> +	shdr = elf_data + elf_hdr_e_shoff(class, ehdr);
>> >>> +	/* Compute name table section header entry in shdr array */
>> >>> +	name_table_shdr = shdr + (shstrndx * elf_shdr_size);
>> >>> +	/* Finally, compute the name table section address in elf */
>> >>> +	name_table = elf_data + elf_shdr_sh_offset(class, name_table_shdr);
>> >>> +
>> >>> +	for (i = 0; i < shnum; i++, shdr += elf_shdr_size) {
>> >>> +		u64 size = elf_shdr_sh_size(class, shdr);
>> >>> +		u64 offset = elf_shdr_sh_offset(class, shdr);
>> >>> +		u32 name = elf_shdr_sh_name(class, shdr);
>> >>> +
>> >>> +		if (strcmp(name_table + name, ".resource_table"))
>> >>>  			continue;
>> >>>  
>> >>>  		table = (struct resource_table *)(elf_data + offset);
>> >>> @@ -270,21 +305,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr,
>> >>> size_t fw_size)
>> >>>   */
>> >>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>> >>>  {
>> >>> -	struct elf32_hdr *ehdr;
>> >>> -	struct elf32_shdr *shdr;
>> >>> +	const void *shdr;
>> >>>  	struct device *dev = &rproc->dev;
>> >>>  	struct resource_table *table = NULL;
>> >>>  	const u8 *elf_data = fw->data;
>> >>>  	size_t tablesz;
>> >>> +	u8 class = fw_elf_get_class(fw);
>> >>> +	u64 sh_offset;
>> >>>  
>> >>> -	ehdr = (struct elf32_hdr *)elf_data;
>> >>> -
>> >>> -	shdr = find_table(dev, ehdr, fw->size);
>> >>> +	shdr = find_table(dev, fw);
>> >>>  	if (!shdr)
>> >>>  		return -EINVAL;
>> >>>  
>> >>> -	table = (struct resource_table *)(elf_data + shdr->sh_offset);
>> >>> -	tablesz = shdr->sh_size;
>> >>> +	sh_offset = elf_shdr_sh_offset(class, shdr);
>> >>> +	table = (struct resource_table *)(elf_data + sh_offset);
>> >>> +	tablesz = elf_shdr_sh_size(class, shdr);
>> >>>  
>> >>>  	/*
>> >>>  	 * Create a copy of the resource table. When a virtio device starts
>> >>> @@ -317,13 +352,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
>> >>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>> >>>  						       const struct firmware *fw)
>> >>>  {
>> >>> -	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> >>> -	struct elf32_shdr *shdr;
>> >>> +	const void *shdr;
>> >>> +	u64 sh_addr, sh_size;
>> >>> +	u8 class = fw_elf_get_class(fw);
>> >>>  
>> >>> -	shdr = find_table(&rproc->dev, ehdr, fw->size);
>> >>> +	shdr = find_table(&rproc->dev, fw);
>> >>>  	if (!shdr)
>> >>>  		return NULL;
>> >>>  
>> >>> -	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
>> >>> +	sh_addr = elf_shdr_sh_addr(class, shdr);
>> >>> +	sh_size = elf_shdr_sh_size(class, shdr);
>> >>> +
>> >>> +	return rproc_da_to_va(rproc, sh_addr, sh_size);
>> >>>  }
>> >>>  EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
>> >>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.h
>> >>> b/drivers/remoteproc/remoteproc_elf_loader.h
>> >>> new file mode 100644
>> >>> index 000000000000..fac3565734f9
>> >>> --- /dev/null
>> >>> +++ b/drivers/remoteproc/remoteproc_elf_loader.h
>> >>> @@ -0,0 +1,69 @@
>> >>> +/* SPDX-License-Identifier: GPL-2.0 */
>> >>> +/*
>> >>> + * Remote processor elf loader defines
>> >>> + *
>> >>> + * Copyright (C) 2019 Kalray, Inc.
>> >>> + */
>> >>> +
>> >>> +#ifndef REMOTEPROC_ELF_LOADER_H
>> >>> +#define REMOTEPROC_ELF_LOADER_H
>> >>> +
>> >>> +#include <linux/elf.h>
>> >>> +#include <linux/types.h>
>> >>> +
>> >>> +/**
>> >>> + * fw_elf_get_class - Get elf class
>> >>> + * @fw: the ELF firmware image
>> >>> + *
>> >>> + * Note that we use and elf32_hdr to access the class since the start of the
>> >>> + * struct is the same for both elf class
>> >>> + *
>> >>> + * Return: elf class of the firmware
>> >>> + */
>> >>> +static inline u8 fw_elf_get_class(const struct firmware *fw)
>> >>> +{
>> >>> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
>> >>> +
>> >>> +	return ehdr->e_ident[EI_CLASS];
>> >>> +}
>> >>> +
>> >>> +#define ELF_GET_FIELD(__s, __field, __type) \
>> >>> +static inline __type elf_##__s##_##__field(u8 class, const void *arg) \
>> >>> +{ \
>> >>> +	if (class == ELFCLASS32) \
>> >>> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
>> >>> +	else \
>> >>> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
>> >>> +}
>> >>> +
>> >>> +ELF_GET_FIELD(hdr, e_entry, u64)
>> >>> +ELF_GET_FIELD(hdr, e_phnum, u16)
>> >>> +ELF_GET_FIELD(hdr, e_shnum, u16)
>> >>> +ELF_GET_FIELD(hdr, e_phoff, u64)
>> >>> +ELF_GET_FIELD(hdr, e_shoff, u64)
>> >>> +ELF_GET_FIELD(hdr, e_shstrndx, u16)
>> >>> +
>> >>> +ELF_GET_FIELD(phdr, p_paddr, u64)
>> >>> +ELF_GET_FIELD(phdr, p_filesz, u64)
>> >>> +ELF_GET_FIELD(phdr, p_memsz, u64)
>> >>> +ELF_GET_FIELD(phdr, p_type, u32)
>> >>> +ELF_GET_FIELD(phdr, p_offset, u64)
>> >>> +
>> >>> +ELF_GET_FIELD(shdr, sh_size, u64)
>> >>> +ELF_GET_FIELD(shdr, sh_offset, u64)
>> >>> +ELF_GET_FIELD(shdr, sh_name, u32)
>> >>> +ELF_GET_FIELD(shdr, sh_addr, u64)
>> >>> +
>> >>> +#define ELF_STRUCT_SIZE(__s) \
>> >>> +static inline unsigned long elf_size_of_##__s(u8 class) \
>> >>> +{ \
>> >>> +	if (class == ELFCLASS32)\
>> >>> +		return sizeof(struct elf32_##__s); \
>> >>> +	else \
>> >>> +		return sizeof(struct elf64_##__s); \
>> >>> +}
>> >>> +
>> >>> +ELF_STRUCT_SIZE(shdr)
>> >>> +ELF_STRUCT_SIZE(phdr)
>> >>> +
>> >>> +#endif /* REMOTEPROC_ELF_LOADER_H */
>> >>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> >>> b/drivers/remoteproc/remoteproc_internal.h
>> >>> index 004867061721..eeb26434220e 100644
>> >>> --- a/drivers/remoteproc/remoteproc_internal.h
>> >>> +++ b/drivers/remoteproc/remoteproc_internal.h
>> >>> @@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>> >>>  int rproc_trigger_recovery(struct rproc *rproc);
>> >>>  
>> >>>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
>> >>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> >>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> >>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>> >>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>> >>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
>> >>> diff --git a/drivers/remoteproc/st_remoteproc.c
>> >>> b/drivers/remoteproc/st_remoteproc.c
>> >>> index ee13d23b43a9..a3268d95a50e 100644
>> >>> --- a/drivers/remoteproc/st_remoteproc.c
>> >>> +++ b/drivers/remoteproc/st_remoteproc.c
>> >>> @@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
>> >>>  		}
>> >>>  	}
>> >>>  
>> >>> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
>> >>> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>> >>>  
>> >>>  	return 0;
>> >>>  
>> >>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> >>> index f84bd5fe0211..82cebca9344c 100644
>> >>> --- a/include/linux/remoteproc.h
>> >>> +++ b/include/linux/remoteproc.h
>> >>> @@ -382,7 +382,7 @@ struct rproc_ops {
>> >>>  				struct rproc *rproc, const struct firmware *fw);
>> >>>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
>> >>>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
>> >>> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> >>> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> >>>  };
>> >>>  
>> >>>  /**
>> >>> @@ -498,7 +498,7 @@ struct rproc {
>> >>>  	int num_traces;
>> >>>  	struct list_head carveouts;
>> >>>  	struct list_head mappings;
>> >>> -	u32 bootaddr;
>> >>> +	u64 bootaddr;
>> >> 
>> >> That will cause problems for rproc_coredump()[1] and fixing it properly
>> >> likely means that a 32 or 64 elf should be generated based on the type of image
>> >> that was loaded.  This is also true if ->p_vaddr and ->p_paddr (also in the same
>> >> function) are to be handled properly.
>> >> 
>> >> I'm interested in your opinion on this.
>> > 
>> > Indeed, you are right !
>> > 
>> > I'm "afraid" I will have to fix that !
>> > Most sane thing to do is to dump an elf with the input elf class.
>> > I will make a V4 with a patch for that.
>> > 
>> 
>> Actually, this does not seems directly related to elf loading.
>> The coredump mecanism dumps segment that have been registered
>> using rproc_coredump_add_*_segment and this is not done directly
>> by the elf loader.
> 
> Correct, but it is fair to assume rpoc_coredump_add_*_segment() is called for
> the image that will run on the MCU (otherwiser doing so would be pointless).
> 
>> I'm not 100% sure but the coredump elf format is not tied to
>> any machine (EM_NONE) and as a special type (ET_CORE) so the elf
>> type is probably not relevant adn elf64 would be generic.
> 
> That is true, we could generate an elf64 core dump for both 32 and 64 bit MCU
> image and be done with it.  But that is almost guaranteed to break some user
> space that isn't tailored to deal with an elf64.
> 
>> If some coredump user could speak for that part, that would be
>> nice !
>> 
>> If needed, then we could add a rproc_coredump_set_format() function
>> to specify various parameters (machine, elf type, lsb/msb, etc).
>> 
> 
> For this specific patchset I don't think you need to cover cases where this much
> flexibility is needed (up to now it hasn't been a requiment).
> 
> Keeping track of the type of image being loaded in something like
> rproc::elfclass and use that information to generate the right elf core in
> rproc_coredump() is probably sufficient for the time being.

Ok, let's go this way.

> 
>> Let me know what you think about it.
>> 
>> Clément
>> 
>> > Thanks,
>> > 
>> > Clément
>> > 
>> >> 
>> >> Thanks,
>> >> Mathieu
>> >> 
>> >> [1].
>> >> https://elixir.bootlin.com/linux/latest/source/drivers/remoteproc/remoteproc_core.c#L1600
>> >> 
>> >>>  	struct list_head rvdevs;
>> >>>  	struct list_head subdevs;
>> >>>  	struct idr notifyids;
>> >>> --
> > > >> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v4 0/5] remoteproc: Add elf64 support
  2020-02-07  7:57                               ` Clément Leger
@ 2020-02-10 16:22                                 ` Clement Leger
  2020-02-10 16:22                                   ` [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va Clement Leger
                                                     ` (6 more replies)
  0 siblings, 7 replies; 76+ messages in thread
From: Clement Leger @ 2020-02-10 16:22 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

This serie add support for elf64 in remoteproc (elf loader, coredump). 
First two patches modifies the type of len argument (in da_to_va) and
boot_addr in order to allow loading elf64 segment with a u64 size
and a u64 entry point.
Next patch introduce a set of macros to access elf64 and elf32
transparently.
Last two patches are the actual modification in the elf loader and
remoteproc coredump support to add elf64 support.

Changes from V3:
 - Adapt coredump to elf64 file format
 - Rename remoteproc_elf_loader.h to remoteproc_elf_helpers.h
 - Update copyright year in remoteproc_elf_helpers.h
 - Rename macros elf_hdr_* to elf_get_hdr_* for coherency with elf_hdr_set_*
 - Split elf64 loader patch in 3:
   - boot_addr u64 change
   - remoteproc_elf_helpers.h creation
   - elf64 loading

Clement Leger (5):
  remoteproc: Use u64 len for da_to_va
  remoteproc: Use u64 type for boot_addr
  remoteproc: Add elf helpers to access elf64 and elf32 fields
  remoteproc: Add elf64 support in elf loader
  remoteproc: Adapt coredump to generate correct elf type

 Documentation/remoteproc.txt                |   2 +-
 drivers/remoteproc/imx_rproc.c              |  11 +-
 drivers/remoteproc/keystone_remoteproc.c    |   4 +-
 drivers/remoteproc/qcom_q6v5_adsp.c         |   2 +-
 drivers/remoteproc/qcom_q6v5_mss.c          |   2 +-
 drivers/remoteproc/qcom_q6v5_pas.c          |   2 +-
 drivers/remoteproc/qcom_q6v5_wcss.c         |   2 +-
 drivers/remoteproc/qcom_wcnss.c             |   2 +-
 drivers/remoteproc/remoteproc_core.c        |  69 +++++++------
 drivers/remoteproc/remoteproc_elf_helpers.h |  95 ++++++++++++++++++
 drivers/remoteproc/remoteproc_elf_loader.c  | 150 ++++++++++++++++++----------
 drivers/remoteproc/remoteproc_internal.h    |   4 +-
 drivers/remoteproc/st_remoteproc.c          |   2 +-
 drivers/remoteproc/st_slim_rproc.c          |   4 +-
 drivers/remoteproc/wkup_m3_rproc.c          |   4 +-
 include/linux/remoteproc.h                  |   7 +-
 16 files changed, 252 insertions(+), 110 deletions(-)
 create mode 100644 drivers/remoteproc/remoteproc_elf_helpers.h

-- 
2.15.0.276.g89ea799


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va
  2020-02-10 16:22                                 ` [PATCH v4 0/5] remoteproc: Add elf64 support Clement Leger
@ 2020-02-10 16:22                                   ` Clement Leger
  2020-02-11 15:53                                     ` Arnaud POULIQUEN
  2020-02-10 16:22                                   ` [PATCH v4 2/5] remoteproc: Use u64 type for boot_addr Clement Leger
                                                     ` (5 subsequent siblings)
  6 siblings, 1 reply; 76+ messages in thread
From: Clement Leger @ 2020-02-10 16:22 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

With upcoming changes in elf loader for elf64 support, section size will
be a u64. When used with da_to_va, this will potentially lead to
overflow if using the current "int" type for len argument. Change
da_to_va prototype to use a u64 for len and fix all users of this
function.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
 drivers/remoteproc/keystone_remoteproc.c |  4 ++--
 drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
 drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
 drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
 drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
 drivers/remoteproc/qcom_wcnss.c          |  2 +-
 drivers/remoteproc/remoteproc_core.c     |  2 +-
 drivers/remoteproc/remoteproc_internal.h |  2 +-
 drivers/remoteproc/st_slim_rproc.c       |  4 ++--
 drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
 include/linux/remoteproc.h               |  2 +-
 12 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 3e72b6f38d4b..f497f5b49b18 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
 }
 
 static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
-			       int len, u64 *sys)
+			       u64 len, u64 *sys)
 {
 	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
 	int i;
@@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
 		}
 	}
 
-	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
+	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
 		 da, len);
 	return -ENOENT;
 }
 
-static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct imx_rproc *priv = rproc->priv;
 	void *va = NULL;
 	u64 sys;
 	int i;
 
-	if (len <= 0)
+	if (len == 0)
 		return NULL;
 
 	/*
@@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 		}
 	}
 
-	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
+	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
+		da, len, va);
 
 	return va;
 }
diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
index 5c4658f00b3d..466093f48814 100644
--- a/drivers/remoteproc/keystone_remoteproc.c
+++ b/drivers/remoteproc/keystone_remoteproc.c
@@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
  * can be used either by the remoteproc core for loading (when using kernel
  * remoteproc loader), or by any rpmsg bus drivers.
  */
-static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct keystone_rproc *ksproc = rproc->priv;
 	void __iomem *va = NULL;
@@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 	size_t size;
 	int i;
 
-	if (len <= 0)
+	if (len == 0)
 		return NULL;
 
 	for (i = 0; i < ksproc->num_mems; i++) {
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index e953886b2eb7..7518e67a49e5 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index 471128a2e723..248febde6fc1 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct q6v5 *qproc = rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index db4b3c4bacd7..cf2cd609c90d 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
index f93e1e4a1cc0..3a6b82a16961 100644
--- a/drivers/remoteproc/qcom_q6v5_wcss.c
+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
@@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct q6v5_wcss *wcss = rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index dc135754bb9c..f893219e45a8 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 307df98347ba..9e6d3c6a60ee 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
  * here the output of the DMA API for the carveouts, which should be more
  * correct.
  */
-void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct rproc_mem_entry *carveout;
 	void *ptr = NULL;
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 493ef9262411..004867061721 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
 void rproc_free_vring(struct rproc_vring *rvring);
 int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
 
-void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
+void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
 phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
index 04492fead3c8..fc01cd879b60 100644
--- a/drivers/remoteproc/st_slim_rproc.c
+++ b/drivers/remoteproc/st_slim_rproc.c
@@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct st_slim_rproc *slim_rproc = rproc->priv;
 	void *va = NULL;
@@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 		}
 	}
 
-	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
+	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
 		da, len, va);
 
 	return va;
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
index 3984e585c847..91485b467407 100644
--- a/drivers/remoteproc/wkup_m3_rproc.c
+++ b/drivers/remoteproc/wkup_m3_rproc.c
@@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
 {
 	struct wkup_m3_rproc *wkupm3 = rproc->priv;
 	void *va = NULL;
 	int i;
 	u32 offset;
 
-	if (len <= 0)
+	if (len == 0)
 		return NULL;
 
 	for (i = 0; i < WKUPM3_MEM_MAX; i++) {
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 16ad66683ad0..f84bd5fe0211 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -374,7 +374,7 @@ struct rproc_ops {
 	int (*start)(struct rproc *rproc);
 	int (*stop)(struct rproc *rproc);
 	void (*kick)(struct rproc *rproc, int vqid);
-	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
+	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
 	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
 	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
 			  int offset, int avail);
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v4 2/5] remoteproc: Use u64 type for boot_addr
  2020-02-10 16:22                                 ` [PATCH v4 0/5] remoteproc: Add elf64 support Clement Leger
  2020-02-10 16:22                                   ` [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va Clement Leger
@ 2020-02-10 16:22                                   ` Clement Leger
  2020-02-10 16:22                                   ` [PATCH v4 3/5] remoteproc: Add elf helpers to access elf64 and elf32 fields Clement Leger
                                                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 76+ messages in thread
From: Clement Leger @ 2020-02-10 16:22 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

elf64 entry is defined as a u64. Since boot_addr is used to store the
elf entry point, change boot_addr type to u64 to support both elf32
and elf64. In the same time, fix users that were using this variable.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
 drivers/remoteproc/remoteproc_internal.h   | 2 +-
 drivers/remoteproc/st_remoteproc.c         | 2 +-
 include/linux/remoteproc.h                 | 4 ++--
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 606aae166eba..c2a9783cfb9a 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -102,7 +102,7 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
  * Note that the boot address is not a configurable property of all remote
  * processors. Some will always boot at a specific hard-coded address.
  */
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
 {
 	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
 
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 004867061721..eeb26434220e 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
 int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index ee13d23b43a9..a3268d95a50e 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
 		}
 	}
 
-	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
+	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
 
 	return 0;
 
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index f84bd5fe0211..82cebca9344c 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -382,7 +382,7 @@ struct rproc_ops {
 				struct rproc *rproc, const struct firmware *fw);
 	int (*load)(struct rproc *rproc, const struct firmware *fw);
 	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
-	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
 };
 
 /**
@@ -498,7 +498,7 @@ struct rproc {
 	int num_traces;
 	struct list_head carveouts;
 	struct list_head mappings;
-	u32 bootaddr;
+	u64 bootaddr;
 	struct list_head rvdevs;
 	struct list_head subdevs;
 	struct idr notifyids;
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v4 3/5] remoteproc: Add elf helpers to access elf64 and elf32 fields
  2020-02-10 16:22                                 ` [PATCH v4 0/5] remoteproc: Add elf64 support Clement Leger
  2020-02-10 16:22                                   ` [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va Clement Leger
  2020-02-10 16:22                                   ` [PATCH v4 2/5] remoteproc: Use u64 type for boot_addr Clement Leger
@ 2020-02-10 16:22                                   ` Clement Leger
  2020-02-10 16:22                                   ` [PATCH v4 4/5] remoteproc: Add elf64 support in elf loader Clement Leger
                                                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 76+ messages in thread
From: Clement Leger @ 2020-02-10 16:22 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

elf32 and elf64 mainly differ by their types. In order to avoid
copy/pasting the whole loader code, generate static inline functions
which will access values according to the elf class. It allows to
keep a common loader basis.
In order to accommodate both elf types sizes, the maximum size for a
elf header member is chosen using the maximum value of the field for
both elf class.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/remoteproc_elf_helpers.h | 95 +++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)
 create mode 100644 drivers/remoteproc/remoteproc_elf_helpers.h

diff --git a/drivers/remoteproc/remoteproc_elf_helpers.h b/drivers/remoteproc/remoteproc_elf_helpers.h
new file mode 100644
index 000000000000..a29c17aaedb7
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_elf_helpers.h
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Remote processor elf helpers defines
+ *
+ * Copyright (C) 2020 Kalray, Inc.
+ */
+
+#ifndef REMOTEPROC_ELF_LOADER_H
+#define REMOTEPROC_ELF_LOADER_H
+
+#include <linux/elf.h>
+#include <linux/types.h>
+
+/**
+ * fw_elf_get_class - Get elf class
+ * @fw: the ELF firmware image
+ *
+ * Note that we use and elf32_hdr to access the class since the start of the
+ * struct is the same for both elf class
+ *
+ * Return: elf class of the firmware
+ */
+static inline u8 fw_elf_get_class(const struct firmware *fw)
+{
+	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
+
+	return ehdr->e_ident[EI_CLASS];
+}
+
+static inline void elf_hdr_init_ident(struct elf32_hdr *hdr, u8 class)
+{
+	memcpy(hdr->e_ident, ELFMAG, SELFMAG);
+	hdr->e_ident[EI_CLASS] = class;
+	hdr->e_ident[EI_DATA] = ELFDATA2LSB;
+	hdr->e_ident[EI_VERSION] = EV_CURRENT;
+	hdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
+}
+
+/* Generate getter and setter for a specific elf struct/field */
+#define ELF_GEN_FIELD_GET_SET(__s, __field, __type) \
+static inline __type elf_##__s##_get_##__field(u8 class, const void *arg) \
+{ \
+	if (class == ELFCLASS32) \
+		return (__type) ((const struct elf32_##__s *) arg)->__field; \
+	else \
+		return (__type) ((const struct elf64_##__s *) arg)->__field; \
+} \
+static inline void elf_##__s##_set_##__field(u8 class, void *arg, __type value) \
+{ \
+	if (class == ELFCLASS32) \
+		((struct elf32_##__s *) arg)->__field = (__type) value; \
+	else \
+		((struct elf64_##__s *) arg)->__field = (__type) value; \
+}
+
+ELF_GEN_FIELD_GET_SET(hdr, e_entry, u64)
+ELF_GEN_FIELD_GET_SET(hdr, e_phnum, u16)
+ELF_GEN_FIELD_GET_SET(hdr, e_shnum, u16)
+ELF_GEN_FIELD_GET_SET(hdr, e_phoff, u64)
+ELF_GEN_FIELD_GET_SET(hdr, e_shoff, u64)
+ELF_GEN_FIELD_GET_SET(hdr, e_shstrndx, u16)
+ELF_GEN_FIELD_GET_SET(hdr, e_machine, u16)
+ELF_GEN_FIELD_GET_SET(hdr, e_type, u16)
+ELF_GEN_FIELD_GET_SET(hdr, e_version, u32)
+ELF_GEN_FIELD_GET_SET(hdr, e_ehsize, u32)
+ELF_GEN_FIELD_GET_SET(hdr, e_phentsize, u16)
+
+ELF_GEN_FIELD_GET_SET(phdr, p_paddr, u64)
+ELF_GEN_FIELD_GET_SET(phdr, p_vaddr, u64)
+ELF_GEN_FIELD_GET_SET(phdr, p_filesz, u64)
+ELF_GEN_FIELD_GET_SET(phdr, p_memsz, u64)
+ELF_GEN_FIELD_GET_SET(phdr, p_type, u32)
+ELF_GEN_FIELD_GET_SET(phdr, p_offset, u64)
+ELF_GEN_FIELD_GET_SET(phdr, p_flags, u32)
+ELF_GEN_FIELD_GET_SET(phdr, p_align, u64)
+
+ELF_GEN_FIELD_GET_SET(shdr, sh_size, u64)
+ELF_GEN_FIELD_GET_SET(shdr, sh_offset, u64)
+ELF_GEN_FIELD_GET_SET(shdr, sh_name, u32)
+ELF_GEN_FIELD_GET_SET(shdr, sh_addr, u64)
+
+#define ELF_STRUCT_SIZE(__s) \
+static inline unsigned long elf_size_of_##__s(u8 class) \
+{ \
+	if (class == ELFCLASS32)\
+		return sizeof(struct elf32_##__s); \
+	else \
+		return sizeof(struct elf64_##__s); \
+}
+
+ELF_STRUCT_SIZE(shdr)
+ELF_STRUCT_SIZE(phdr)
+ELF_STRUCT_SIZE(hdr)
+
+#endif /* REMOTEPROC_ELF_LOADER_H */
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v4 4/5] remoteproc: Add elf64 support in elf loader
  2020-02-10 16:22                                 ` [PATCH v4 0/5] remoteproc: Add elf64 support Clement Leger
                                                     ` (2 preceding siblings ...)
  2020-02-10 16:22                                   ` [PATCH v4 3/5] remoteproc: Add elf helpers to access elf64 and elf32 fields Clement Leger
@ 2020-02-10 16:22                                   ` Clement Leger
  2020-02-10 16:22                                   ` [PATCH v4 5/5] remoteproc: Adapt coredump to generate correct elf type Clement Leger
                                                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 76+ messages in thread
From: Clement Leger @ 2020-02-10 16:22 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

In order to support elf64, use macros from remoteproc_elf_helpers.h
to access elf headers depending on elf class.

Signed-off-by: Clement Leger <cleger@kalray.eu>
Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
---
 Documentation/remoteproc.txt               |   2 +-
 drivers/remoteproc/remoteproc_elf_loader.c | 145 ++++++++++++++++++-----------
 2 files changed, 93 insertions(+), 54 deletions(-)

diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
index 03c3d2e568b0..2be1147256e0 100644
--- a/Documentation/remoteproc.txt
+++ b/Documentation/remoteproc.txt
@@ -230,7 +230,7 @@ in the used rings.
 Binary Firmware Structure
 =========================
 
-At this point remoteproc only supports ELF32 firmware binaries. However,
+At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
 it is quite expected that other platforms/devices which we'd want to
 support with this framework will be based on different binary formats.
 
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index c2a9783cfb9a..2ffb02a2ee36 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -23,6 +23,7 @@
 #include <linux/elf.h>
 
 #include "remoteproc_internal.h"
+#include "remoteproc_elf_helpers.h"
 
 /**
  * rproc_elf_sanity_check() - Sanity Check ELF firmware image
@@ -35,8 +36,16 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 {
 	const char *name = rproc->firmware;
 	struct device *dev = &rproc->dev;
+	/*
+	 * Elf files are beginning with the same structure. Thus, to simplify
+	 * header parsing, we can use the elf32_hdr one for both elf64 and
+	 * elf32.
+	 */
 	struct elf32_hdr *ehdr;
+	u32 elf_shdr_get_size;
+	u64 phoff, shoff;
 	char class;
+	u16 phnum;
 
 	if (!fw) {
 		dev_err(dev, "failed to load %s\n", name);
@@ -50,13 +59,22 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 
 	ehdr = (struct elf32_hdr *)fw->data;
 
-	/* We only support ELF32 at this point */
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(dev, "Image is corrupted (bad magic)\n");
+		return -EINVAL;
+	}
+
 	class = ehdr->e_ident[EI_CLASS];
-	if (class != ELFCLASS32) {
+	if (class != ELFCLASS32 && class != ELFCLASS64) {
 		dev_err(dev, "Unsupported class: %d\n", class);
 		return -EINVAL;
 	}
 
+	if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
+		dev_err(dev, "elf64 header is too small\n");
+		return -EINVAL;
+	}
+
 	/* We assume the firmware has the same endianness as the host */
 # ifdef __LITTLE_ENDIAN
 	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
@@ -67,26 +85,29 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 		return -EINVAL;
 	}
 
-	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
-		dev_err(dev, "Image is too small\n");
-		return -EINVAL;
-	}
+	phoff = elf_hdr_get_e_phoff(class, fw->data);
+	shoff = elf_hdr_get_e_shoff(class, fw->data);
+	phnum =  elf_hdr_get_e_phnum(class, fw->data);
+	elf_shdr_get_size = elf_size_of_shdr(class);
 
-	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(dev, "Image is corrupted (bad magic)\n");
+	if (fw->size < shoff + elf_shdr_get_size) {
+		dev_err(dev, "Image is too small\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phnum == 0) {
+	if (phnum == 0) {
 		dev_err(dev, "No loadable segments\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phoff > fw->size) {
+	if (phoff > fw->size) {
 		dev_err(dev, "Firmware size is too small\n");
 		return -EINVAL;
 	}
 
+	dev_dbg(dev, "Firmware is an elf%d file\n",
+		class == ELFCLASS32 ? 32 : 64);
+
 	return 0;
 }
 EXPORT_SYMBOL(rproc_elf_sanity_check);
@@ -104,9 +125,7 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
  */
 u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
-
-	return ehdr->e_entry;
+	return elf_hdr_get_e_entry(fw_elf_get_class(fw), fw->data);
 }
 EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 
@@ -137,37 +156,41 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 {
 	struct device *dev = &rproc->dev;
-	struct elf32_hdr *ehdr;
-	struct elf32_phdr *phdr;
+	const void *ehdr, *phdr;
 	int i, ret = 0;
+	u16 phnum;
 	const u8 *elf_data = fw->data;
+	u8 class = fw_elf_get_class(fw);
+	u32 elf_phdr_get_size = elf_size_of_phdr(class);
 
-	ehdr = (struct elf32_hdr *)elf_data;
-	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+	ehdr = elf_data;
+	phnum = elf_hdr_get_e_phnum(class, ehdr);
+	phdr = elf_data + elf_hdr_get_e_phoff(class, ehdr);
 
 	/* go through the available ELF segments */
-	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-		u32 da = phdr->p_paddr;
-		u32 memsz = phdr->p_memsz;
-		u32 filesz = phdr->p_filesz;
-		u32 offset = phdr->p_offset;
+	for (i = 0; i < phnum; i++, phdr += elf_phdr_get_size) {
+		u64 da = elf_phdr_get_p_paddr(class, phdr);
+		u64 memsz = elf_phdr_get_p_memsz(class, phdr);
+		u64 filesz = elf_phdr_get_p_filesz(class, phdr);
+		u64 offset = elf_phdr_get_p_offset(class, phdr);
+		u32 type = elf_phdr_get_p_type(class, phdr);
 		void *ptr;
 
-		if (phdr->p_type != PT_LOAD)
+		if (type != PT_LOAD)
 			continue;
 
-		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-			phdr->p_type, da, memsz, filesz);
+		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
+			type, da, memsz, filesz);
 
 		if (filesz > memsz) {
-			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
 				filesz, memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		if (offset + filesz > fw->size) {
-			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
+			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
 				offset + filesz, fw->size);
 			ret = -EINVAL;
 			break;
@@ -176,14 +199,15 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 		/* grab the kernel address for this device address */
 		ptr = rproc_da_to_va(rproc, da, memsz);
 		if (!ptr) {
-			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
+				memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		/* put the segment where the remote processor expects it */
-		if (phdr->p_filesz)
-			memcpy(ptr, elf_data + phdr->p_offset, filesz);
+		if (filesz)
+			memcpy(ptr, elf_data + offset, filesz);
 
 		/*
 		 * Zero out remaining memory for this segment.
@@ -200,24 +224,35 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 }
 EXPORT_SYMBOL(rproc_elf_load_segments);
 
-static struct elf32_shdr *
-find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
+static const void *
+find_table(struct device *dev, const struct firmware *fw)
 {
-	struct elf32_shdr *shdr;
+	const void *shdr, *name_table_shdr;
 	int i;
 	const char *name_table;
 	struct resource_table *table = NULL;
-	const u8 *elf_data = (void *)ehdr;
+	const u8 *elf_data = (void *)fw->data;
+	u8 class = fw_elf_get_class(fw);
+	size_t fw_size = fw->size;
+	const void *ehdr = elf_data;
+	u16 shnum = elf_hdr_get_e_shnum(class, ehdr);
+	u32 elf_shdr_get_size = elf_size_of_shdr(class);
+	u16 shstrndx = elf_hdr_get_e_shstrndx(class, ehdr);
 
 	/* look for the resource table and handle it */
-	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
-	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
-
-	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
-		u32 size = shdr->sh_size;
-		u32 offset = shdr->sh_offset;
-
-		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+	/* First, get the section header according to the elf class */
+	shdr = elf_data + elf_hdr_get_e_shoff(class, ehdr);
+	/* Compute name table section header entry in shdr array */
+	name_table_shdr = shdr + (shstrndx * elf_shdr_get_size);
+	/* Finally, compute the name table section address in elf */
+	name_table = elf_data + elf_shdr_get_sh_offset(class, name_table_shdr);
+
+	for (i = 0; i < shnum; i++, shdr += elf_shdr_get_size) {
+		u64 size = elf_shdr_get_sh_size(class, shdr);
+		u64 offset = elf_shdr_get_sh_offset(class, shdr);
+		u32 name = elf_shdr_get_sh_name(class, shdr);
+
+		if (strcmp(name_table + name, ".resource_table"))
 			continue;
 
 		table = (struct resource_table *)(elf_data + offset);
@@ -270,21 +305,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
  */
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr;
-	struct elf32_shdr *shdr;
+	const void *shdr;
 	struct device *dev = &rproc->dev;
 	struct resource_table *table = NULL;
 	const u8 *elf_data = fw->data;
 	size_t tablesz;
+	u8 class = fw_elf_get_class(fw);
+	u64 sh_offset;
 
-	ehdr = (struct elf32_hdr *)elf_data;
-
-	shdr = find_table(dev, ehdr, fw->size);
+	shdr = find_table(dev, fw);
 	if (!shdr)
 		return -EINVAL;
 
-	table = (struct resource_table *)(elf_data + shdr->sh_offset);
-	tablesz = shdr->sh_size;
+	sh_offset = elf_shdr_get_sh_offset(class, shdr);
+	table = (struct resource_table *)(elf_data + sh_offset);
+	tablesz = elf_shdr_get_sh_size(class, shdr);
 
 	/*
 	 * Create a copy of the resource table. When a virtio device starts
@@ -317,13 +352,17 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 						       const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
-	struct elf32_shdr *shdr;
+	const void *shdr;
+	u64 sh_addr, sh_size;
+	u8 class = fw_elf_get_class(fw);
 
-	shdr = find_table(&rproc->dev, ehdr, fw->size);
+	shdr = find_table(&rproc->dev, fw);
 	if (!shdr)
 		return NULL;
 
-	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
+	sh_addr = elf_shdr_get_sh_addr(class, shdr);
+	sh_size = elf_shdr_get_sh_size(class, shdr);
+
+	return rproc_da_to_va(rproc, sh_addr, sh_size);
 }
 EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v4 5/5] remoteproc: Adapt coredump to generate correct elf type
  2020-02-10 16:22                                 ` [PATCH v4 0/5] remoteproc: Add elf64 support Clement Leger
                                                     ` (3 preceding siblings ...)
  2020-02-10 16:22                                   ` [PATCH v4 4/5] remoteproc: Add elf64 support in elf loader Clement Leger
@ 2020-02-10 16:22                                   ` Clement Leger
  2020-02-11 23:11                                     ` Mathieu Poirier
  2020-02-11 15:57                                   ` [PATCH v4 0/5] remoteproc: Add elf64 support Arnaud POULIQUEN
  2020-03-02  9:38                                   ` [PATCH v5 0/8] " Clement Leger
  6 siblings, 1 reply; 76+ messages in thread
From: Clement Leger @ 2020-02-10 16:22 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

Now that remoteproc can load an elf64, coredump elf class should be
the same as the loaded elf class. In order to do that, add a
elf_class field to rproc with default values. If an elf is loaded
successfully, these fields will be updated with the loaded elf class.
Then, the coredump core code has been modified to use the generic elf
macro in order to create an elf file with correct class.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/remoteproc_core.c       | 67 ++++++++++++++++--------------
 drivers/remoteproc/remoteproc_elf_loader.c |  3 ++
 include/linux/remoteproc.h                 |  1 +
 3 files changed, 39 insertions(+), 32 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 9e6d3c6a60ee..ce70656ae150 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -38,6 +38,7 @@
 #include <linux/platform_device.h>
 
 #include "remoteproc_internal.h"
+#include "remoteproc_elf_helpers.h"
 
 #define HIGH_BITS_MASK 0xFFFFFFFF00000000ULL
 
@@ -1564,20 +1565,21 @@ EXPORT_SYMBOL(rproc_coredump_add_custom_segment);
 static void rproc_coredump(struct rproc *rproc)
 {
 	struct rproc_dump_segment *segment;
-	struct elf32_phdr *phdr;
-	struct elf32_hdr *ehdr;
+	void *phdr;
+	void *ehdr;
 	size_t data_size;
 	size_t offset;
 	void *data;
 	void *ptr;
+	u8 class = rproc->elf_class;
 	int phnum = 0;
 
 	if (list_empty(&rproc->dump_segments))
 		return;
 
-	data_size = sizeof(*ehdr);
+	data_size = elf_size_of_hdr(class);
 	list_for_each_entry(segment, &rproc->dump_segments, node) {
-		data_size += sizeof(*phdr) + segment->size;
+		data_size += elf_size_of_phdr(class) + segment->size;
 
 		phnum++;
 	}
@@ -1588,33 +1590,33 @@ static void rproc_coredump(struct rproc *rproc)
 
 	ehdr = data;
 
-	memset(ehdr, 0, sizeof(*ehdr));
-	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
-	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
-	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
-	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
-	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
-	ehdr->e_type = ET_CORE;
-	ehdr->e_machine = EM_NONE;
-	ehdr->e_version = EV_CURRENT;
-	ehdr->e_entry = rproc->bootaddr;
-	ehdr->e_phoff = sizeof(*ehdr);
-	ehdr->e_ehsize = sizeof(*ehdr);
-	ehdr->e_phentsize = sizeof(*phdr);
-	ehdr->e_phnum = phnum;
-
-	phdr = data + ehdr->e_phoff;
-	offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum;
+	memset(ehdr, 0, elf_size_of_hdr(class));
+	/* e_ident field is common for both elf32 and elf64 */
+	elf_hdr_init_ident(ehdr, class);
+
+	elf_hdr_set_e_type(class, ehdr, ET_CORE);
+	elf_hdr_set_e_machine(class, ehdr, EM_NONE);
+	elf_hdr_set_e_version(class, ehdr, EV_CURRENT);
+	elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr);
+	elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class));
+	elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class));
+	elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class));
+	elf_hdr_set_e_phnum(class, ehdr, phnum);
+
+	phdr = data + elf_hdr_get_e_phoff(class, ehdr);
+	offset = elf_hdr_get_e_phoff(class, ehdr);
+	offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr);
+
 	list_for_each_entry(segment, &rproc->dump_segments, node) {
-		memset(phdr, 0, sizeof(*phdr));
-		phdr->p_type = PT_LOAD;
-		phdr->p_offset = offset;
-		phdr->p_vaddr = segment->da;
-		phdr->p_paddr = segment->da;
-		phdr->p_filesz = segment->size;
-		phdr->p_memsz = segment->size;
-		phdr->p_flags = PF_R | PF_W | PF_X;
-		phdr->p_align = 0;
+		memset(phdr, 0, elf_size_of_phdr(class));
+		elf_phdr_set_p_type(class, phdr, PT_LOAD);
+		elf_phdr_set_p_offset(class, phdr, offset);
+		elf_phdr_set_p_vaddr(class, phdr, segment->da);
+		elf_phdr_set_p_paddr(class, phdr, segment->da);
+		elf_phdr_set_p_filesz(class, phdr, segment->size);
+		elf_phdr_set_p_memsz(class, phdr, segment->size);
+		elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X);
+		elf_phdr_set_p_align(class, phdr, 0);
 
 		if (segment->dump) {
 			segment->dump(rproc, segment, data + offset);
@@ -1630,8 +1632,8 @@ static void rproc_coredump(struct rproc *rproc)
 			}
 		}
 
-		offset += phdr->p_filesz;
-		phdr++;
+		offset += elf_phdr_get_p_filesz(class, phdr);
+		phdr += elf_size_of_phdr(class);
 	}
 
 	dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
@@ -2029,6 +2031,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
 	rproc->name = name;
 	rproc->priv = &rproc[1];
 	rproc->auto_boot = true;
+	rproc->elf_class = ELFCLASS32;
 
 	device_initialize(&rproc->dev);
 	rproc->dev.parent = dev;
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 2ffb02a2ee36..07712a541ea6 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -220,6 +220,9 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 			memset(ptr + filesz, 0, memsz - filesz);
 	}
 
+	if (ret == 0)
+		rproc->elf_class = class;
+
 	return ret;
 }
 EXPORT_SYMBOL(rproc_elf_load_segments);
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 82cebca9344c..113e356ce56a 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -514,6 +514,7 @@ struct rproc {
 	bool auto_boot;
 	struct list_head dump_segments;
 	int nb_vdev;
+	int elf_class;
 };
 
 /**
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va
  2020-02-10 16:22                                   ` [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va Clement Leger
@ 2020-02-11 15:53                                     ` Arnaud POULIQUEN
  2020-02-11 16:39                                       ` Clément Leger
  0 siblings, 1 reply; 76+ messages in thread
From: Arnaud POULIQUEN @ 2020-02-11 15:53 UTC (permalink / raw)
  To: Clement Leger, Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet,
	Shawn Guo, Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Loic PALLARDY, s-anna,
	Mathieu Poirier



On 2/10/20 5:22 PM, Clement Leger wrote:
> With upcoming changes in elf loader for elf64 support, section size will
> be a u64. When used with da_to_va, this will potentially lead to
> overflow if using the current "int" type for len argument. Change
> da_to_va prototype to use a u64 for len and fix all users of this
> function.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>
> ---
>  drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
>  drivers/remoteproc/keystone_remoteproc.c |  4 ++--
>  drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
>  drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
>  drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
>  drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
>  drivers/remoteproc/qcom_wcnss.c          |  2 +-
>  drivers/remoteproc/remoteproc_core.c     |  2 +-
>  drivers/remoteproc/remoteproc_internal.h |  2 +-
>  drivers/remoteproc/st_slim_rproc.c       |  4 ++--
>  drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
>  include/linux/remoteproc.h               |  2 +-
>  12 files changed, 20 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 3e72b6f38d4b..f497f5b49b18 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
>  }
>  
>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
> -			       int len, u64 *sys)
> +			       u64 len, u64 *sys)
>  {
>  	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
>  	int i;
> @@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
>  		}
>  	}
>  
> -	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
> +	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
>  		 da, len);
>  	return -ENOENT;
>  }
>  
> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct imx_rproc *priv = rproc->priv;
>  	void *va = NULL;
>  	u64 sys;
>  	int i;
>  
> -	if (len <= 0)
> +	if (len == 0)
>  		return NULL;
>  
>  	/*
> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  		}
>  	}
>  
> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
> +		da, len, va);
>  
>  	return va;
>  }
> diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
> index 5c4658f00b3d..466093f48814 100644
> --- a/drivers/remoteproc/keystone_remoteproc.c
> +++ b/drivers/remoteproc/keystone_remoteproc.c
> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
>   * can be used either by the remoteproc core for loading (when using kernel
>   * remoteproc loader), or by any rpmsg bus drivers.
>   */
> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct keystone_rproc *ksproc = rproc->priv;
>  	void __iomem *va = NULL;
> @@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  	size_t size;
>  	int i;
>  
> -	if (len <= 0)
> +	if (len == 0)
>  		return NULL;
>  
>  	for (i = 0; i < ksproc->num_mems; i++) {
> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
> index e953886b2eb7..7518e67a49e5 100644
> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
> index 471128a2e723..248febde6fc1 100644
> --- a/drivers/remoteproc/qcom_q6v5_mss.c
> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct q6v5 *qproc = rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
> index db4b3c4bacd7..cf2cd609c90d 100644
> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
> index f93e1e4a1cc0..3a6b82a16961 100644
> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct q6v5_wcss *wcss = rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> index dc135754bb9c..f893219e45a8 100644
> --- a/drivers/remoteproc/qcom_wcnss.c
> +++ b/drivers/remoteproc/qcom_wcnss.c
> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 307df98347ba..9e6d3c6a60ee 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>   * here the output of the DMA API for the carveouts, which should be more
>   * correct.
>   */
> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)

This function is exported, don't see any update in consequence...
references:
https://elixir.bootlin.com/linux/v5.6-rc1/ident/rproc_da_to_va
For instance the function rproc_trace_read use it. it quite strange that my gcc does not warns for the cast but i suppose that some could.
An indirect consequence is that the len field in rproc_mem_entry struct should probably been updated to u64 to be aligned.

I'm still wondering about the use of size_t instead,which seems more rational from my window.
So i you or Mathieu remember it was decided to use u64, please could remind me the arguments?
As an alternative a check should be added for 32 bits processors to ensure that the size is not higher than 
its address range capability...  

Regards
Arnaud  
 
>  {
>  	struct rproc_mem_entry *carveout;
>  	void *ptr = NULL;
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 493ef9262411..004867061721 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>  void rproc_free_vring(struct rproc_vring *rvring);
>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>  
> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>  int rproc_trigger_recovery(struct rproc *rproc);
>  
> diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
> index 04492fead3c8..fc01cd879b60 100644
> --- a/drivers/remoteproc/st_slim_rproc.c
> +++ b/drivers/remoteproc/st_slim_rproc.c
> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct st_slim_rproc *slim_rproc = rproc->priv;
>  	void *va = NULL;
> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  		}
>  	}
>  
> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
>  		da, len, va);
>  
>  	return va;
> diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
> index 3984e585c847..91485b467407 100644
> --- a/drivers/remoteproc/wkup_m3_rproc.c
> +++ b/drivers/remoteproc/wkup_m3_rproc.c
> @@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>  {
>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
>  	void *va = NULL;
>  	int i;
>  	u32 offset;
>  
> -	if (len <= 0)
> +	if (len == 0)
>  		return NULL;
>  
>  	for (i = 0; i < WKUPM3_MEM_MAX; i++) {
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 16ad66683ad0..f84bd5fe0211 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -374,7 +374,7 @@ struct rproc_ops {
>  	int (*start)(struct rproc *rproc);
>  	int (*stop)(struct rproc *rproc);
>  	void (*kick)(struct rproc *rproc, int vqid);
> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
> +	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
>  			  int offset, int avail);
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 0/5] remoteproc: Add elf64 support
  2020-02-10 16:22                                 ` [PATCH v4 0/5] remoteproc: Add elf64 support Clement Leger
                                                     ` (4 preceding siblings ...)
  2020-02-10 16:22                                   ` [PATCH v4 5/5] remoteproc: Adapt coredump to generate correct elf type Clement Leger
@ 2020-02-11 15:57                                   ` Arnaud POULIQUEN
  2020-02-11 23:12                                     ` Mathieu Poirier
  2020-03-02  9:38                                   ` [PATCH v5 0/8] " Clement Leger
  6 siblings, 1 reply; 76+ messages in thread
From: Arnaud POULIQUEN @ 2020-02-11 15:57 UTC (permalink / raw)
  To: Clement Leger, Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet,
	Shawn Guo, Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Loic PALLARDY, s-anna,
	Mathieu Poirier

Hi Clement,

I tested the series on the stm32 platform for remote proc firmwre load: no regression found.
I do not test the da_to_va feature as not implemented on stm32 platform.

Regards,
Arnaud



On 2/10/20 5:22 PM, Clement Leger wrote:
> This serie add support for elf64 in remoteproc (elf loader, coredump). 
> First two patches modifies the type of len argument (in da_to_va) and
> boot_addr in order to allow loading elf64 segment with a u64 size
> and a u64 entry point.
> Next patch introduce a set of macros to access elf64 and elf32
> transparently.
> Last two patches are the actual modification in the elf loader and
> remoteproc coredump support to add elf64 support.
> 
> Changes from V3:
>  - Adapt coredump to elf64 file format
>  - Rename remoteproc_elf_loader.h to remoteproc_elf_helpers.h
>  - Update copyright year in remoteproc_elf_helpers.h
>  - Rename macros elf_hdr_* to elf_get_hdr_* for coherency with elf_hdr_set_*
>  - Split elf64 loader patch in 3:
>    - boot_addr u64 change
>    - remoteproc_elf_helpers.h creation
>    - elf64 loading
> 
> Clement Leger (5):
>   remoteproc: Use u64 len for da_to_va
>   remoteproc: Use u64 type for boot_addr
>   remoteproc: Add elf helpers to access elf64 and elf32 fields
>   remoteproc: Add elf64 support in elf loader
>   remoteproc: Adapt coredump to generate correct elf type
> 
>  Documentation/remoteproc.txt                |   2 +-
>  drivers/remoteproc/imx_rproc.c              |  11 +-
>  drivers/remoteproc/keystone_remoteproc.c    |   4 +-
>  drivers/remoteproc/qcom_q6v5_adsp.c         |   2 +-
>  drivers/remoteproc/qcom_q6v5_mss.c          |   2 +-
>  drivers/remoteproc/qcom_q6v5_pas.c          |   2 +-
>  drivers/remoteproc/qcom_q6v5_wcss.c         |   2 +-
>  drivers/remoteproc/qcom_wcnss.c             |   2 +-
>  drivers/remoteproc/remoteproc_core.c        |  69 +++++++------
>  drivers/remoteproc/remoteproc_elf_helpers.h |  95 ++++++++++++++++++
>  drivers/remoteproc/remoteproc_elf_loader.c  | 150 ++++++++++++++++++----------
>  drivers/remoteproc/remoteproc_internal.h    |   4 +-
>  drivers/remoteproc/st_remoteproc.c          |   2 +-
>  drivers/remoteproc/st_slim_rproc.c          |   4 +-
>  drivers/remoteproc/wkup_m3_rproc.c          |   4 +-
>  include/linux/remoteproc.h                  |   7 +-
>  16 files changed, 252 insertions(+), 110 deletions(-)
>  create mode 100644 drivers/remoteproc/remoteproc_elf_helpers.h
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va
  2020-02-11 15:53                                     ` Arnaud POULIQUEN
@ 2020-02-11 16:39                                       ` Clément Leger
  2020-02-11 17:24                                         ` Arnaud POULIQUEN
  2020-02-11 22:37                                         ` Mathieu Poirier
  0 siblings, 2 replies; 76+ messages in thread
From: Clément Leger @ 2020-02-11 16:39 UTC (permalink / raw)
  To: Arnaud Pouliquen
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Loic PALLARDY, s-anna, Mathieu Poirier

Hi Arnaud,

----- On 11 Feb, 2020, at 16:53, Arnaud Pouliquen arnaud.pouliquen@st.com wrote:

> On 2/10/20 5:22 PM, Clement Leger wrote:
>> With upcoming changes in elf loader for elf64 support, section size will
>> be a u64. When used with da_to_va, this will potentially lead to
>> overflow if using the current "int" type for len argument. Change
>> da_to_va prototype to use a u64 for len and fix all users of this
>> function.
>> 
>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> ---
>>  drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
>>  drivers/remoteproc/keystone_remoteproc.c |  4 ++--
>>  drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
>>  drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
>>  drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
>>  drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
>>  drivers/remoteproc/qcom_wcnss.c          |  2 +-
>>  drivers/remoteproc/remoteproc_core.c     |  2 +-
>>  drivers/remoteproc/remoteproc_internal.h |  2 +-
>>  drivers/remoteproc/st_slim_rproc.c       |  4 ++--
>>  drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
>>  include/linux/remoteproc.h               |  2 +-
>>  12 files changed, 20 insertions(+), 19 deletions(-)
>> 
>> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
>> index 3e72b6f38d4b..f497f5b49b18 100644
>> --- a/drivers/remoteproc/imx_rproc.c
>> +++ b/drivers/remoteproc/imx_rproc.c
>> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
>>  }
>>  
>>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
>> -			       int len, u64 *sys)
>> +			       u64 len, u64 *sys)
>>  {
>>  	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
>>  	int i;
>> @@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64
>> da,
>>  		}
>>  	}
>>  
>> -	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
>> +	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
>>  		 da, len);
>>  	return -ENOENT;
>>  }
>>  
>> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct imx_rproc *priv = rproc->priv;
>>  	void *va = NULL;
>>  	u64 sys;
>>  	int i;
>>  
>> -	if (len <= 0)
>> +	if (len == 0)
>>  		return NULL;
>>  
>>  	/*
>> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da,
>> int len)
>>  		}
>>  	}
>>  
>> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
>> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
>> +		da, len, va);
>>  
>>  	return va;
>>  }
>> diff --git a/drivers/remoteproc/keystone_remoteproc.c
>> b/drivers/remoteproc/keystone_remoteproc.c
>> index 5c4658f00b3d..466093f48814 100644
>> --- a/drivers/remoteproc/keystone_remoteproc.c
>> +++ b/drivers/remoteproc/keystone_remoteproc.c
>> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int
>> vqid)
>>   * can be used either by the remoteproc core for loading (when using kernel
>>   * remoteproc loader), or by any rpmsg bus drivers.
>>   */
>> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct keystone_rproc *ksproc = rproc->priv;
>>  	void __iomem *va = NULL;
>> @@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc,
>> u64 da, int len)
>>  	size_t size;
>>  	int i;
>>  
>> -	if (len <= 0)
>> +	if (len == 0)
>>  		return NULL;
>>  
>>  	for (i = 0; i < ksproc->num_mems; i++) {
>> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c
>> b/drivers/remoteproc/qcom_q6v5_adsp.c
>> index e953886b2eb7..7518e67a49e5 100644
>> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
>> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
>> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>>  	return ret;
>>  }
>>  
>> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>>  	int offset;
>> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c
>> b/drivers/remoteproc/qcom_q6v5_mss.c
>> index 471128a2e723..248febde6fc1 100644
>> --- a/drivers/remoteproc/qcom_q6v5_mss.c
>> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
>> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>>  	return 0;
>>  }
>>  
>> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct q6v5 *qproc = rproc->priv;
>>  	int offset;
>> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c
>> b/drivers/remoteproc/qcom_q6v5_pas.c
>> index db4b3c4bacd7..cf2cd609c90d 100644
>> --- a/drivers/remoteproc/qcom_q6v5_pas.c
>> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
>> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>>  	return ret;
>>  }
>>  
>> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>>  	int offset;
>> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c
>> b/drivers/remoteproc/qcom_q6v5_wcss.c
>> index f93e1e4a1cc0..3a6b82a16961 100644
>> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
>> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
>> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>>  	return 0;
>>  }
>>  
>> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct q6v5_wcss *wcss = rproc->priv;
>>  	int offset;
>> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
>> index dc135754bb9c..f893219e45a8 100644
>> --- a/drivers/remoteproc/qcom_wcnss.c
>> +++ b/drivers/remoteproc/qcom_wcnss.c
>> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>>  	return ret;
>>  }
>>  
>> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>>  	int offset;
>> diff --git a/drivers/remoteproc/remoteproc_core.c
>> b/drivers/remoteproc/remoteproc_core.c
>> index 307df98347ba..9e6d3c6a60ee 100644
>> --- a/drivers/remoteproc/remoteproc_core.c
>> +++ b/drivers/remoteproc/remoteproc_core.c
>> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>>   * here the output of the DMA API for the carveouts, which should be more
>>   * correct.
>>   */
>> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> 
> This function is exported, don't see any update in consequence...
> references:
> https://elixir.bootlin.com/linux/v5.6-rc1/ident/rproc_da_to_va
> For instance the function rproc_trace_read use it. it quite strange that my gcc
> does not warns for the cast but i suppose that some could.

Agreed, even if len should never have been a signed type since it can't be
negative. I will try to fix all callers.

> An indirect consequence is that the len field in rproc_mem_entry struct should
> probably been updated to u64 to be aligned.

Ok, I will do that once we settle on the type of len.

> 
> I'm still wondering about the use of size_t instead,which seems more rational
> from my window.
> So i you or Mathieu remember it was decided to use u64, please could remind me
> the arguments?

I tried to find the notes of a meeting we had for OpenAMP but I did not found
them. Anyway, the argument was coming from Tomas or someone else, (I can't
remember) talking about a 32 bits CPU executing code on a 64 bits accelerator.
In that case, the size_t type could fail due to being only 32bits on the host
CPU but larger than 4G.

However, I can't say if it's a real usecase or not... All I can say is
that keeping it open is probably better if one day somebody comes with such
architecture.

> As an alternative a check should be added for 32 bits processors to ensure that
> the size is not higher than
> its address range capability...

Agreed.
I was even thinking about a mecanism for remoteproc drivers to declare the type
of supported elfs files (such as EM_*, ELFCLASS* and other needed thing).
Or should it be supported by overriding .sanity_check in drivers  to reject
elf64 for instance ?

Since elf is a "specific format" and that rproc can support other formats,
I did not want to add a specific elf_sanity_check field to rproc ops.

Regards,

Clément

> 
> Regards
> Arnaud
> 
>>  {
>>  	struct rproc_mem_entry *carveout;
>>  	void *ptr = NULL;
>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> b/drivers/remoteproc/remoteproc_internal.h
>> index 493ef9262411..004867061721 100644
>> --- a/drivers/remoteproc/remoteproc_internal.h
>> +++ b/drivers/remoteproc/remoteproc_internal.h
>> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>>  void rproc_free_vring(struct rproc_vring *rvring);
>>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>>  
>> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
>> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
>>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>>  int rproc_trigger_recovery(struct rproc *rproc);
>>  
>> diff --git a/drivers/remoteproc/st_slim_rproc.c
>> b/drivers/remoteproc/st_slim_rproc.c
>> index 04492fead3c8..fc01cd879b60 100644
>> --- a/drivers/remoteproc/st_slim_rproc.c
>> +++ b/drivers/remoteproc/st_slim_rproc.c
>> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>>  	return 0;
>>  }
>>  
>> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct st_slim_rproc *slim_rproc = rproc->priv;
>>  	void *va = NULL;
>> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64
>> da, int len)
>>  		}
>>  	}
>>  
>> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
>> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
>>  		da, len, va);
>>  
>>  	return va;
>> diff --git a/drivers/remoteproc/wkup_m3_rproc.c
>> b/drivers/remoteproc/wkup_m3_rproc.c
>> index 3984e585c847..91485b467407 100644
>> --- a/drivers/remoteproc/wkup_m3_rproc.c
>> +++ b/drivers/remoteproc/wkup_m3_rproc.c
>> @@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>>  	return 0;
>>  }
>>  
>> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>  {
>>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
>>  	void *va = NULL;
>>  	int i;
>>  	u32 offset;
>>  
>> -	if (len <= 0)
>> +	if (len == 0)
>>  		return NULL;
>>  
>>  	for (i = 0; i < WKUPM3_MEM_MAX; i++) {
>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> index 16ad66683ad0..f84bd5fe0211 100644
>> --- a/include/linux/remoteproc.h
>> +++ b/include/linux/remoteproc.h
>> @@ -374,7 +374,7 @@ struct rproc_ops {
>>  	int (*start)(struct rproc *rproc);
>>  	int (*stop)(struct rproc *rproc);
>>  	void (*kick)(struct rproc *rproc, int vqid);
>> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
>> +	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
>>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
>>  			  int offset, int avail);

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va
  2020-02-11 16:39                                       ` Clément Leger
@ 2020-02-11 17:24                                         ` Arnaud POULIQUEN
  2020-02-11 22:37                                         ` Mathieu Poirier
  1 sibling, 0 replies; 76+ messages in thread
From: Arnaud POULIQUEN @ 2020-02-11 17:24 UTC (permalink / raw)
  To: Clément Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Loic PALLARDY, s-anna, Mathieu Poirier



On 2/11/20 5:39 PM, Clément Leger wrote:
> Hi Arnaud,
> 
> ----- On 11 Feb, 2020, at 16:53, Arnaud Pouliquen arnaud.pouliquen@st.com wrote:
> 
>> On 2/10/20 5:22 PM, Clement Leger wrote:
>>> With upcoming changes in elf loader for elf64 support, section size will
>>> be a u64. When used with da_to_va, this will potentially lead to
>>> overflow if using the current "int" type for len argument. Change
>>> da_to_va prototype to use a u64 for len and fix all users of this
>>> function.
>>>
>>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>>> ---
>>>  drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
>>>  drivers/remoteproc/keystone_remoteproc.c |  4 ++--
>>>  drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
>>>  drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
>>>  drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
>>>  drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
>>>  drivers/remoteproc/qcom_wcnss.c          |  2 +-
>>>  drivers/remoteproc/remoteproc_core.c     |  2 +-
>>>  drivers/remoteproc/remoteproc_internal.h |  2 +-
>>>  drivers/remoteproc/st_slim_rproc.c       |  4 ++--
>>>  drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
>>>  include/linux/remoteproc.h               |  2 +-
>>>  12 files changed, 20 insertions(+), 19 deletions(-)
>>>
>>> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
>>> index 3e72b6f38d4b..f497f5b49b18 100644
>>> --- a/drivers/remoteproc/imx_rproc.c
>>> +++ b/drivers/remoteproc/imx_rproc.c
>>> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
>>>  }
>>>  
>>>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
>>> -			       int len, u64 *sys)
>>> +			       u64 len, u64 *sys)
>>>  {
>>>  	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
>>>  	int i;
>>> @@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64
>>> da,
>>>  		}
>>>  	}
>>>  
>>> -	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
>>> +	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
>>>  		 da, len);
>>>  	return -ENOENT;
>>>  }
>>>  
>>> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct imx_rproc *priv = rproc->priv;
>>>  	void *va = NULL;
>>>  	u64 sys;
>>>  	int i;
>>>  
>>> -	if (len <= 0)
>>> +	if (len == 0)
>>>  		return NULL;
>>>  
>>>  	/*
>>> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da,
>>> int len)
>>>  		}
>>>  	}
>>>  
>>> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
>>> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
>>> +		da, len, va);
>>>  
>>>  	return va;
>>>  }
>>> diff --git a/drivers/remoteproc/keystone_remoteproc.c
>>> b/drivers/remoteproc/keystone_remoteproc.c
>>> index 5c4658f00b3d..466093f48814 100644
>>> --- a/drivers/remoteproc/keystone_remoteproc.c
>>> +++ b/drivers/remoteproc/keystone_remoteproc.c
>>> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int
>>> vqid)
>>>   * can be used either by the remoteproc core for loading (when using kernel
>>>   * remoteproc loader), or by any rpmsg bus drivers.
>>>   */
>>> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct keystone_rproc *ksproc = rproc->priv;
>>>  	void __iomem *va = NULL;
>>> @@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc,
>>> u64 da, int len)
>>>  	size_t size;
>>>  	int i;
>>>  
>>> -	if (len <= 0)
>>> +	if (len == 0)
>>>  		return NULL;
>>>  
>>>  	for (i = 0; i < ksproc->num_mems; i++) {
>>> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c
>>> b/drivers/remoteproc/qcom_q6v5_adsp.c
>>> index e953886b2eb7..7518e67a49e5 100644
>>> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
>>> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
>>> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>>>  	return ret;
>>>  }
>>>  
>>> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>>>  	int offset;
>>> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c
>>> b/drivers/remoteproc/qcom_q6v5_mss.c
>>> index 471128a2e723..248febde6fc1 100644
>>> --- a/drivers/remoteproc/qcom_q6v5_mss.c
>>> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
>>> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>>>  	return 0;
>>>  }
>>>  
>>> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct q6v5 *qproc = rproc->priv;
>>>  	int offset;
>>> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c
>>> b/drivers/remoteproc/qcom_q6v5_pas.c
>>> index db4b3c4bacd7..cf2cd609c90d 100644
>>> --- a/drivers/remoteproc/qcom_q6v5_pas.c
>>> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
>>> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>>>  	return ret;
>>>  }
>>>  
>>> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>>>  	int offset;
>>> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c
>>> b/drivers/remoteproc/qcom_q6v5_wcss.c
>>> index f93e1e4a1cc0..3a6b82a16961 100644
>>> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
>>> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
>>> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>>>  	return 0;
>>>  }
>>>  
>>> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct q6v5_wcss *wcss = rproc->priv;
>>>  	int offset;
>>> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
>>> index dc135754bb9c..f893219e45a8 100644
>>> --- a/drivers/remoteproc/qcom_wcnss.c
>>> +++ b/drivers/remoteproc/qcom_wcnss.c
>>> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>>>  	return ret;
>>>  }
>>>  
>>> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>>>  	int offset;
>>> diff --git a/drivers/remoteproc/remoteproc_core.c
>>> b/drivers/remoteproc/remoteproc_core.c
>>> index 307df98347ba..9e6d3c6a60ee 100644
>>> --- a/drivers/remoteproc/remoteproc_core.c
>>> +++ b/drivers/remoteproc/remoteproc_core.c
>>> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>>>   * here the output of the DMA API for the carveouts, which should be more
>>>   * correct.
>>>   */
>>> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>
>> This function is exported, don't see any update in consequence...
>> references:
>> https://elixir.bootlin.com/linux/v5.6-rc1/ident/rproc_da_to_va
>> For instance the function rproc_trace_read use it. it quite strange that my gcc
>> does not warns for the cast but i suppose that some could.
> 
> Agreed, even if len should never have been a signed type since it can't be
> negative. I will try to fix all callers.
> 
>> An indirect consequence is that the len field in rproc_mem_entry struct should
>> probably been updated to u64 to be aligned.
> 
> Ok, I will do that once we settle on the type of len.
> 
>>
>> I'm still wondering about the use of size_t instead,which seems more rational
>> from my window.
>> So i you or Mathieu remember it was decided to use u64, please could remind me
>> the arguments?
> 
> I tried to find the notes of a meeting we had for OpenAMP but I did not found
> them. Anyway, the argument was coming from Tomas or someone else, (I can't
> remember) talking about a 32 bits CPU executing code on a 64 bits accelerator.
> In that case, the size_t type could fail due to being only 32bits on the host
> CPU but larger than 4G.
> 
> However, I can't say if it's a real usecase or not... All I can say is
> that keeping it open is probably better if one day somebody comes with such
> architecture.
> 
>> As an alternative a check should be added for 32 bits processors to ensure that
>> the size is not higher than
>> its address range capability...
> 
> Agreed.
> I was even thinking about a mecanism for remoteproc drivers to declare the type
> of supported elfs files (such as EM_*, ELFCLASS* and other needed thing).
> Or should it be supported by overriding .sanity_check in drivers  to reject
> elf64 for instance ?
> 
> Since elf is a "specific format" and that rproc can support other formats,
> I did not want to add a specific elf_sanity_check field to rproc ops.
Agree, platform driver as to check the format it can support, elf, bin, properitay format....
To check the size, the da_to_va ops seems a good candidate as called for loaded segments and memories.
So ok to delegate the check to the platform driver.

Regards
Arnaud

> 
> Regards,
> 
> Clément
> 
>>
>> Regards
>> Arnaud
>>
>>>  {
>>>  	struct rproc_mem_entry *carveout;
>>>  	void *ptr = NULL;
>>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>>> b/drivers/remoteproc/remoteproc_internal.h
>>> index 493ef9262411..004867061721 100644
>>> --- a/drivers/remoteproc/remoteproc_internal.h
>>> +++ b/drivers/remoteproc/remoteproc_internal.h
>>> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>>>  void rproc_free_vring(struct rproc_vring *rvring);
>>>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>>>  
>>> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
>>> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
>>>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>>>  int rproc_trigger_recovery(struct rproc *rproc);
>>>  
>>> diff --git a/drivers/remoteproc/st_slim_rproc.c
>>> b/drivers/remoteproc/st_slim_rproc.c
>>> index 04492fead3c8..fc01cd879b60 100644
>>> --- a/drivers/remoteproc/st_slim_rproc.c
>>> +++ b/drivers/remoteproc/st_slim_rproc.c
>>> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>>>  	return 0;
>>>  }
>>>  
>>> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct st_slim_rproc *slim_rproc = rproc->priv;
>>>  	void *va = NULL;
>>> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64
>>> da, int len)
>>>  		}
>>>  	}
>>>  
>>> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
>>> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
>>>  		da, len, va);
>>>  
>>>  	return va;
>>> diff --git a/drivers/remoteproc/wkup_m3_rproc.c
>>> b/drivers/remoteproc/wkup_m3_rproc.c
>>> index 3984e585c847..91485b467407 100644
>>> --- a/drivers/remoteproc/wkup_m3_rproc.c
>>> +++ b/drivers/remoteproc/wkup_m3_rproc.c
>>> @@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>>>  	return 0;
>>>  }
>>>  
>>> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>>> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>>>  {
>>>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
>>>  	void *va = NULL;
>>>  	int i;
>>>  	u32 offset;
>>>  
>>> -	if (len <= 0)
>>> +	if (len == 0)
>>>  		return NULL;
>>>  
>>>  	for (i = 0; i < WKUPM3_MEM_MAX; i++) {
>>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>>> index 16ad66683ad0..f84bd5fe0211 100644
>>> --- a/include/linux/remoteproc.h
>>> +++ b/include/linux/remoteproc.h
>>> @@ -374,7 +374,7 @@ struct rproc_ops {
>>>  	int (*start)(struct rproc *rproc);
>>>  	int (*stop)(struct rproc *rproc);
>>>  	void (*kick)(struct rproc *rproc, int vqid);
>>> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
>>> +	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
>>>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>>>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
>>>  			  int offset, int avail);

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va
  2020-02-11 16:39                                       ` Clément Leger
  2020-02-11 17:24                                         ` Arnaud POULIQUEN
@ 2020-02-11 22:37                                         ` Mathieu Poirier
  2020-02-12 10:37                                           ` Clément Leger
  1 sibling, 1 reply; 76+ messages in thread
From: Mathieu Poirier @ 2020-02-11 22:37 UTC (permalink / raw)
  To: Clément Leger
  Cc: Arnaud Pouliquen, Ohad Ben-Cohen, Bjorn Andersson,
	Jonathan Corbet, Shawn Guo, Sascha Hauer, linux-remoteproc,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Loic PALLARDY, s-anna

On Tue, Feb 11, 2020 at 05:39:21PM +0100, Clément Leger wrote:
> Hi Arnaud,
> 
> ----- On 11 Feb, 2020, at 16:53, Arnaud Pouliquen arnaud.pouliquen@st.com wrote:
> 
> > On 2/10/20 5:22 PM, Clement Leger wrote:
> >> With upcoming changes in elf loader for elf64 support, section size will
> >> be a u64. When used with da_to_va, this will potentially lead to
> >> overflow if using the current "int" type for len argument. Change
> >> da_to_va prototype to use a u64 for len and fix all users of this
> >> function.
> >> 
> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
> >> ---
> >>  drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
> >>  drivers/remoteproc/keystone_remoteproc.c |  4 ++--
> >>  drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
> >>  drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
> >>  drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
> >>  drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
> >>  drivers/remoteproc/qcom_wcnss.c          |  2 +-
> >>  drivers/remoteproc/remoteproc_core.c     |  2 +-
> >>  drivers/remoteproc/remoteproc_internal.h |  2 +-
> >>  drivers/remoteproc/st_slim_rproc.c       |  4 ++--
> >>  drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
> >>  include/linux/remoteproc.h               |  2 +-
> >>  12 files changed, 20 insertions(+), 19 deletions(-)
> >> 
> >> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> >> index 3e72b6f38d4b..f497f5b49b18 100644
> >> --- a/drivers/remoteproc/imx_rproc.c
> >> +++ b/drivers/remoteproc/imx_rproc.c
> >> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
> >>  }
> >>  
> >>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
> >> -			       int len, u64 *sys)
> >> +			       u64 len, u64 *sys)
> >>  {
> >>  	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> >>  	int i;
> >> @@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64
> >> da,
> >>  		}
> >>  	}
> >>  
> >> -	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
> >> +	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
> >>  		 da, len);
> >>  	return -ENOENT;
> >>  }
> >>  
> >> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >>  {
> >>  	struct imx_rproc *priv = rproc->priv;
> >>  	void *va = NULL;
> >>  	u64 sys;
> >>  	int i;
> >>  
> >> -	if (len <= 0)
> >> +	if (len == 0)
> >>  		return NULL;
> >>  
> >>  	/*
> >> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da,
> >> int len)
> >>  		}
> >>  	}
> >>  
> >> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
> >> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
> >> +		da, len, va);
> >>  
> >>  	return va;
> >>  }
> >> diff --git a/drivers/remoteproc/keystone_remoteproc.c
> >> b/drivers/remoteproc/keystone_remoteproc.c
> >> index 5c4658f00b3d..466093f48814 100644
> >> --- a/drivers/remoteproc/keystone_remoteproc.c
> >> +++ b/drivers/remoteproc/keystone_remoteproc.c
> >> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int
> >> vqid)
> >>   * can be used either by the remoteproc core for loading (when using kernel
> >>   * remoteproc loader), or by any rpmsg bus drivers.
> >>   */
> >> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >>  {
> >>  	struct keystone_rproc *ksproc = rproc->priv;
> >>  	void __iomem *va = NULL;
> >> @@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc,
> >> u64 da, int len)
> >>  	size_t size;
> >>  	int i;
> >>  
> >> -	if (len <= 0)
> >> +	if (len == 0)
> >>  		return NULL;
> >>  
> >>  	for (i = 0; i < ksproc->num_mems; i++) {
> >> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c
> >> b/drivers/remoteproc/qcom_q6v5_adsp.c
> >> index e953886b2eb7..7518e67a49e5 100644
> >> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> >> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> >> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
> >>  	return ret;
> >>  }
> >>  
> >> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> >> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >>  {
> >>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
> >>  	int offset;
> >> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c
> >> b/drivers/remoteproc/qcom_q6v5_mss.c
> >> index 471128a2e723..248febde6fc1 100644
> >> --- a/drivers/remoteproc/qcom_q6v5_mss.c
> >> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
> >> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
> >>  	return 0;
> >>  }
> >>  
> >> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
> >> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >>  {
> >>  	struct q6v5 *qproc = rproc->priv;
> >>  	int offset;
> >> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c
> >> b/drivers/remoteproc/qcom_q6v5_pas.c
> >> index db4b3c4bacd7..cf2cd609c90d 100644
> >> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> >> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> >> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
> >>  	return ret;
> >>  }
> >>  
> >> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> >> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >>  {
> >>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
> >>  	int offset;
> >> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c
> >> b/drivers/remoteproc/qcom_q6v5_wcss.c
> >> index f93e1e4a1cc0..3a6b82a16961 100644
> >> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
> >> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
> >> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
> >>  	return 0;
> >>  }
> >>  
> >> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
> >> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >>  {
> >>  	struct q6v5_wcss *wcss = rproc->priv;
> >>  	int offset;
> >> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> >> index dc135754bb9c..f893219e45a8 100644
> >> --- a/drivers/remoteproc/qcom_wcnss.c
> >> +++ b/drivers/remoteproc/qcom_wcnss.c
> >> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
> >>  	return ret;
> >>  }
> >>  
> >> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
> >> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >>  {
> >>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
> >>  	int offset;
> >> diff --git a/drivers/remoteproc/remoteproc_core.c
> >> b/drivers/remoteproc/remoteproc_core.c
> >> index 307df98347ba..9e6d3c6a60ee 100644
> >> --- a/drivers/remoteproc/remoteproc_core.c
> >> +++ b/drivers/remoteproc/remoteproc_core.c
> >> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
> >>   * here the output of the DMA API for the carveouts, which should be more
> >>   * correct.
> >>   */
> >> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> > 
> > This function is exported, don't see any update in consequence...
> > references:
> > https://elixir.bootlin.com/linux/v5.6-rc1/ident/rproc_da_to_va
> > For instance the function rproc_trace_read use it. it quite strange that my gcc
> > does not warns for the cast but i suppose that some could.
> 
> Agreed, even if len should never have been a signed type since it can't be
> negative. I will try to fix all callers.
> 
> > An indirect consequence is that the len field in rproc_mem_entry struct should
> > probably been updated to u64 to be aligned.
> 
> Ok, I will do that once we settle on the type of len.
> 
> > 
> > I'm still wondering about the use of size_t instead,which seems more rational
> > from my window.
> > So i you or Mathieu remember it was decided to use u64, please could remind me
> > the arguments?
> 
> I tried to find the notes of a meeting we had for OpenAMP but I did not found
> them. Anyway, the argument was coming from Tomas or someone else, (I can't
> remember) talking about a 32 bits CPU executing code on a 64 bits accelerator.
> In that case, the size_t type could fail due to being only 32bits on the host
> CPU but larger than 4G.
> 
> However, I can't say if it's a real usecase or not... All I can say is
> that keeping it open is probably better if one day somebody comes with such
> architecture.

In order to support a 32bit AP with a 64bit MCU we'd also have to deal with all
the dma_attr_t in the structure we use.

Also something that became very clear to me while thinking about this patchset
is that supporting elf64 does __not__ mean we support 64bit MCU.  As long as
the addresses conveyed by the elf64 image fit within 32 bits we are fine.
Supporting 64bit MCUs is a completely different topic, one that will demand
serious refactoring. 

So moving from "int len" to "u64 len" doesn't give us much.  It doesn't hurt to
do it but if @len ever becomes bigger than 31 bits we'll have other problems to
deal with. 

> 
> > As an alternative a check should be added for 32 bits processors to ensure that
> > the size is not higher than
> > its address range capability...
> 
> Agreed.
> I was even thinking about a mecanism for remoteproc drivers to declare the type
> of supported elfs files (such as EM_*, ELFCLASS* and other needed thing).
> Or should it be supported by overriding .sanity_check in drivers  to reject
> elf64 for instance ?
> 
> Since elf is a "specific format" and that rproc can support other formats,
> I did not want to add a specific elf_sanity_check field to rproc ops.
> 
> Regards,
> 
> Clément
> 
> > 
> > Regards
> > Arnaud
> > 
> >>  {
> >>  	struct rproc_mem_entry *carveout;
> >>  	void *ptr = NULL;
> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
> >> b/drivers/remoteproc/remoteproc_internal.h
> >> index 493ef9262411..004867061721 100644
> >> --- a/drivers/remoteproc/remoteproc_internal.h
> >> +++ b/drivers/remoteproc/remoteproc_internal.h
> >> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
> >>  void rproc_free_vring(struct rproc_vring *rvring);
> >>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
> >>  
> >> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
> >> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
> >>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
> >>  int rproc_trigger_recovery(struct rproc *rproc);
> >>  
> >> diff --git a/drivers/remoteproc/st_slim_rproc.c
> >> b/drivers/remoteproc/st_slim_rproc.c
> >> index 04492fead3c8..fc01cd879b60 100644
> >> --- a/drivers/remoteproc/st_slim_rproc.c
> >> +++ b/drivers/remoteproc/st_slim_rproc.c
> >> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
> >>  	return 0;
> >>  }
> >>  
> >> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >>  {
> >>  	struct st_slim_rproc *slim_rproc = rproc->priv;
> >>  	void *va = NULL;
> >> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64
> >> da, int len)
> >>  		}
> >>  	}
> >>  
> >> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
> >> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
> >>  		da, len, va);
> >>  
> >>  	return va;
> >> diff --git a/drivers/remoteproc/wkup_m3_rproc.c
> >> b/drivers/remoteproc/wkup_m3_rproc.c
> >> index 3984e585c847..91485b467407 100644
> >> --- a/drivers/remoteproc/wkup_m3_rproc.c
> >> +++ b/drivers/remoteproc/wkup_m3_rproc.c
> >> @@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
> >>  	return 0;
> >>  }
> >>  
> >> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >>  {
> >>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
> >>  	void *va = NULL;
> >>  	int i;
> >>  	u32 offset;
> >>  
> >> -	if (len <= 0)
> >> +	if (len == 0)
> >>  		return NULL;
> >>  
> >>  	for (i = 0; i < WKUPM3_MEM_MAX; i++) {
> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> >> index 16ad66683ad0..f84bd5fe0211 100644
> >> --- a/include/linux/remoteproc.h
> >> +++ b/include/linux/remoteproc.h
> >> @@ -374,7 +374,7 @@ struct rproc_ops {
> >>  	int (*start)(struct rproc *rproc);
> >>  	int (*stop)(struct rproc *rproc);
> >>  	void (*kick)(struct rproc *rproc, int vqid);
> >> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
> >> +	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
> >>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
> >>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
> >>  			  int offset, int avail);

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 5/5] remoteproc: Adapt coredump to generate correct elf type
  2020-02-10 16:22                                   ` [PATCH v4 5/5] remoteproc: Adapt coredump to generate correct elf type Clement Leger
@ 2020-02-11 23:11                                     ` Mathieu Poirier
  0 siblings, 0 replies; 76+ messages in thread
From: Mathieu Poirier @ 2020-02-11 23:11 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Mon, Feb 10, 2020 at 05:22:09PM +0100, Clement Leger wrote:
> Now that remoteproc can load an elf64, coredump elf class should be
> the same as the loaded elf class. In order to do that, add a
> elf_class field to rproc with default values. If an elf is loaded
> successfully, these fields will be updated with the loaded elf class.
> Then, the coredump core code has been modified to use the generic elf
> macro in order to create an elf file with correct class.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>
> ---
>  drivers/remoteproc/remoteproc_core.c       | 67 ++++++++++++++++--------------
>  drivers/remoteproc/remoteproc_elf_loader.c |  3 ++
>  include/linux/remoteproc.h                 |  1 +
>  3 files changed, 39 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 9e6d3c6a60ee..ce70656ae150 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -38,6 +38,7 @@
>  #include <linux/platform_device.h>
>  
>  #include "remoteproc_internal.h"
> +#include "remoteproc_elf_helpers.h"
>  
>  #define HIGH_BITS_MASK 0xFFFFFFFF00000000ULL
>  
> @@ -1564,20 +1565,21 @@ EXPORT_SYMBOL(rproc_coredump_add_custom_segment);
>  static void rproc_coredump(struct rproc *rproc)
>  {
>  	struct rproc_dump_segment *segment;
> -	struct elf32_phdr *phdr;
> -	struct elf32_hdr *ehdr;
> +	void *phdr;
> +	void *ehdr;
>  	size_t data_size;
>  	size_t offset;
>  	void *data;
>  	void *ptr;
> +	u8 class = rproc->elf_class;
>  	int phnum = 0;
>  
>  	if (list_empty(&rproc->dump_segments))
>  		return;
>  
> -	data_size = sizeof(*ehdr);
> +	data_size = elf_size_of_hdr(class);
>  	list_for_each_entry(segment, &rproc->dump_segments, node) {
> -		data_size += sizeof(*phdr) + segment->size;
> +		data_size += elf_size_of_phdr(class) + segment->size;
>  
>  		phnum++;
>  	}
> @@ -1588,33 +1590,33 @@ static void rproc_coredump(struct rproc *rproc)
>  
>  	ehdr = data;
>  
> -	memset(ehdr, 0, sizeof(*ehdr));
> -	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
> -	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
> -	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
> -	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
> -	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
> -	ehdr->e_type = ET_CORE;
> -	ehdr->e_machine = EM_NONE;
> -	ehdr->e_version = EV_CURRENT;
> -	ehdr->e_entry = rproc->bootaddr;
> -	ehdr->e_phoff = sizeof(*ehdr);
> -	ehdr->e_ehsize = sizeof(*ehdr);
> -	ehdr->e_phentsize = sizeof(*phdr);
> -	ehdr->e_phnum = phnum;
> -
> -	phdr = data + ehdr->e_phoff;
> -	offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum;
> +	memset(ehdr, 0, elf_size_of_hdr(class));
> +	/* e_ident field is common for both elf32 and elf64 */
> +	elf_hdr_init_ident(ehdr, class);
> +
> +	elf_hdr_set_e_type(class, ehdr, ET_CORE);
> +	elf_hdr_set_e_machine(class, ehdr, EM_NONE);
> +	elf_hdr_set_e_version(class, ehdr, EV_CURRENT);
> +	elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr);
> +	elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class));
> +	elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class));
> +	elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class));
> +	elf_hdr_set_e_phnum(class, ehdr, phnum);
> +
> +	phdr = data + elf_hdr_get_e_phoff(class, ehdr);
> +	offset = elf_hdr_get_e_phoff(class, ehdr);
> +	offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr);
> +
>  	list_for_each_entry(segment, &rproc->dump_segments, node) {
> -		memset(phdr, 0, sizeof(*phdr));
> -		phdr->p_type = PT_LOAD;
> -		phdr->p_offset = offset;
> -		phdr->p_vaddr = segment->da;
> -		phdr->p_paddr = segment->da;
> -		phdr->p_filesz = segment->size;
> -		phdr->p_memsz = segment->size;
> -		phdr->p_flags = PF_R | PF_W | PF_X;
> -		phdr->p_align = 0;
> +		memset(phdr, 0, elf_size_of_phdr(class));
> +		elf_phdr_set_p_type(class, phdr, PT_LOAD);
> +		elf_phdr_set_p_offset(class, phdr, offset);
> +		elf_phdr_set_p_vaddr(class, phdr, segment->da);
> +		elf_phdr_set_p_paddr(class, phdr, segment->da);
> +		elf_phdr_set_p_filesz(class, phdr, segment->size);
> +		elf_phdr_set_p_memsz(class, phdr, segment->size);
> +		elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X);
> +		elf_phdr_set_p_align(class, phdr, 0);
>  
>  		if (segment->dump) {
>  			segment->dump(rproc, segment, data + offset);
> @@ -1630,8 +1632,8 @@ static void rproc_coredump(struct rproc *rproc)
>  			}
>  		}
>  
> -		offset += phdr->p_filesz;
> -		phdr++;
> +		offset += elf_phdr_get_p_filesz(class, phdr);
> +		phdr += elf_size_of_phdr(class);
>  	}
>  
>  	dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
> @@ -2029,6 +2031,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
>  	rproc->name = name;
>  	rproc->priv = &rproc[1];
>  	rproc->auto_boot = true;
> +	rproc->elf_class = ELFCLASS32;

I suppose this is as good a place as any.

>  
>  	device_initialize(&rproc->dev);
>  	rproc->dev.parent = dev;
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index 2ffb02a2ee36..07712a541ea6 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -220,6 +220,9 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  			memset(ptr + filesz, 0, memsz - filesz);
>  	}
>  
> +	if (ret == 0)
> +		rproc->elf_class = class;
> +
>  	return ret;
>  }
>  EXPORT_SYMBOL(rproc_elf_load_segments);
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 82cebca9344c..113e356ce56a 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -514,6 +514,7 @@ struct rproc {
>  	bool auto_boot;
>  	struct list_head dump_segments;
>  	int nb_vdev;
> +	int elf_class;

Type 'int'?  I expected 'u8' as it is in the specification and in
rproc_elf_load_segments().

Thanks,
Mathieu


>  };
>  
>  /**
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 0/5] remoteproc: Add elf64 support
  2020-02-11 15:57                                   ` [PATCH v4 0/5] remoteproc: Add elf64 support Arnaud POULIQUEN
@ 2020-02-11 23:12                                     ` Mathieu Poirier
  2020-02-12  8:15                                       ` Arnaud POULIQUEN
  0 siblings, 1 reply; 76+ messages in thread
From: Mathieu Poirier @ 2020-02-11 23:12 UTC (permalink / raw)
  To: Arnaud POULIQUEN
  Cc: Clement Leger, Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet,
	Shawn Guo, Sascha Hauer, linux-remoteproc,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Loic PALLARDY, s-anna

On Tue, Feb 11, 2020 at 04:57:18PM +0100, Arnaud POULIQUEN wrote:
> Hi Clement,
> 
> I tested the series on the stm32 platform for remote proc firmwre load: no regression found.
> I do not test the da_to_va feature as not implemented on stm32 platform.

It would be very interesting if you could test the coredump, that would give us
a lot more confidence in the implementation.

Thanks,
Mathieu

> 
> Regards,
> Arnaud
> 
> 
> 
> On 2/10/20 5:22 PM, Clement Leger wrote:
> > This serie add support for elf64 in remoteproc (elf loader, coredump). 
> > First two patches modifies the type of len argument (in da_to_va) and
> > boot_addr in order to allow loading elf64 segment with a u64 size
> > and a u64 entry point.
> > Next patch introduce a set of macros to access elf64 and elf32
> > transparently.
> > Last two patches are the actual modification in the elf loader and
> > remoteproc coredump support to add elf64 support.
> > 
> > Changes from V3:
> >  - Adapt coredump to elf64 file format
> >  - Rename remoteproc_elf_loader.h to remoteproc_elf_helpers.h
> >  - Update copyright year in remoteproc_elf_helpers.h
> >  - Rename macros elf_hdr_* to elf_get_hdr_* for coherency with elf_hdr_set_*
> >  - Split elf64 loader patch in 3:
> >    - boot_addr u64 change
> >    - remoteproc_elf_helpers.h creation
> >    - elf64 loading
> > 
> > Clement Leger (5):
> >   remoteproc: Use u64 len for da_to_va
> >   remoteproc: Use u64 type for boot_addr
> >   remoteproc: Add elf helpers to access elf64 and elf32 fields
> >   remoteproc: Add elf64 support in elf loader
> >   remoteproc: Adapt coredump to generate correct elf type
> > 
> >  Documentation/remoteproc.txt                |   2 +-
> >  drivers/remoteproc/imx_rproc.c              |  11 +-
> >  drivers/remoteproc/keystone_remoteproc.c    |   4 +-
> >  drivers/remoteproc/qcom_q6v5_adsp.c         |   2 +-
> >  drivers/remoteproc/qcom_q6v5_mss.c          |   2 +-
> >  drivers/remoteproc/qcom_q6v5_pas.c          |   2 +-
> >  drivers/remoteproc/qcom_q6v5_wcss.c         |   2 +-
> >  drivers/remoteproc/qcom_wcnss.c             |   2 +-
> >  drivers/remoteproc/remoteproc_core.c        |  69 +++++++------
> >  drivers/remoteproc/remoteproc_elf_helpers.h |  95 ++++++++++++++++++
> >  drivers/remoteproc/remoteproc_elf_loader.c  | 150 ++++++++++++++++++----------
> >  drivers/remoteproc/remoteproc_internal.h    |   4 +-
> >  drivers/remoteproc/st_remoteproc.c          |   2 +-
> >  drivers/remoteproc/st_slim_rproc.c          |   4 +-
> >  drivers/remoteproc/wkup_m3_rproc.c          |   4 +-
> >  include/linux/remoteproc.h                  |   7 +-
> >  16 files changed, 252 insertions(+), 110 deletions(-)
> >  create mode 100644 drivers/remoteproc/remoteproc_elf_helpers.h
> > 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 0/5] remoteproc: Add elf64 support
  2020-02-11 23:12                                     ` Mathieu Poirier
@ 2020-02-12  8:15                                       ` Arnaud POULIQUEN
  0 siblings, 0 replies; 76+ messages in thread
From: Arnaud POULIQUEN @ 2020-02-12  8:15 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Clement Leger, Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet,
	Shawn Guo, Sascha Hauer, linux-remoteproc,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Loic PALLARDY, s-anna



On 2/12/20 12:12 AM, Mathieu Poirier wrote:
> On Tue, Feb 11, 2020 at 04:57:18PM +0100, Arnaud POULIQUEN wrote:
>> Hi Clement,
>>
>> I tested the series on the stm32 platform for remote proc firmwre load: no regression found.
>> I do not test the da_to_va feature as not implemented on stm32 platform.
> 
> It would be very interesting if you could test the coredump, that would give us
> a lot more confidence in the implementation.
I also tested the coredump generation. LGTM

> 
> Thanks,
> Mathieu
> 
>>
>> Regards,
>> Arnaud
>>
>>
>>
>> On 2/10/20 5:22 PM, Clement Leger wrote:
>>> This serie add support for elf64 in remoteproc (elf loader, coredump). 
>>> First two patches modifies the type of len argument (in da_to_va) and
>>> boot_addr in order to allow loading elf64 segment with a u64 size
>>> and a u64 entry point.
>>> Next patch introduce a set of macros to access elf64 and elf32
>>> transparently.
>>> Last two patches are the actual modification in the elf loader and
>>> remoteproc coredump support to add elf64 support.
>>>
>>> Changes from V3:
>>>  - Adapt coredump to elf64 file format
>>>  - Rename remoteproc_elf_loader.h to remoteproc_elf_helpers.h
>>>  - Update copyright year in remoteproc_elf_helpers.h
>>>  - Rename macros elf_hdr_* to elf_get_hdr_* for coherency with elf_hdr_set_*
>>>  - Split elf64 loader patch in 3:
>>>    - boot_addr u64 change
>>>    - remoteproc_elf_helpers.h creation
>>>    - elf64 loading
>>>
>>> Clement Leger (5):
>>>   remoteproc: Use u64 len for da_to_va
>>>   remoteproc: Use u64 type for boot_addr
>>>   remoteproc: Add elf helpers to access elf64 and elf32 fields
>>>   remoteproc: Add elf64 support in elf loader
>>>   remoteproc: Adapt coredump to generate correct elf type
>>>
>>>  Documentation/remoteproc.txt                |   2 +-
>>>  drivers/remoteproc/imx_rproc.c              |  11 +-
>>>  drivers/remoteproc/keystone_remoteproc.c    |   4 +-
>>>  drivers/remoteproc/qcom_q6v5_adsp.c         |   2 +-
>>>  drivers/remoteproc/qcom_q6v5_mss.c          |   2 +-
>>>  drivers/remoteproc/qcom_q6v5_pas.c          |   2 +-
>>>  drivers/remoteproc/qcom_q6v5_wcss.c         |   2 +-
>>>  drivers/remoteproc/qcom_wcnss.c             |   2 +-
>>>  drivers/remoteproc/remoteproc_core.c        |  69 +++++++------
>>>  drivers/remoteproc/remoteproc_elf_helpers.h |  95 ++++++++++++++++++
>>>  drivers/remoteproc/remoteproc_elf_loader.c  | 150 ++++++++++++++++++----------
>>>  drivers/remoteproc/remoteproc_internal.h    |   4 +-
>>>  drivers/remoteproc/st_remoteproc.c          |   2 +-
>>>  drivers/remoteproc/st_slim_rproc.c          |   4 +-
>>>  drivers/remoteproc/wkup_m3_rproc.c          |   4 +-
>>>  include/linux/remoteproc.h                  |   7 +-
>>>  16 files changed, 252 insertions(+), 110 deletions(-)
>>>  create mode 100644 drivers/remoteproc/remoteproc_elf_helpers.h
>>>

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va
  2020-02-11 22:37                                         ` Mathieu Poirier
@ 2020-02-12 10:37                                           ` Clément Leger
  2020-02-12 21:59                                             ` Mathieu Poirier
  0 siblings, 1 reply; 76+ messages in thread
From: Clément Leger @ 2020-02-12 10:37 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Arnaud Pouliquen, Ohad Ben-Cohen, Bjorn Andersson,
	Jonathan Corbet, Shawn Guo, Sascha Hauer, linux-remoteproc,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Loic PALLARDY, s-anna

Hi Mathieu,

----- On 11 Feb, 2020, at 23:37, Mathieu Poirier mathieu.poirier@linaro.org wrote:

> On Tue, Feb 11, 2020 at 05:39:21PM +0100, Clément Leger wrote:
>> Hi Arnaud,
>> 
>> ----- On 11 Feb, 2020, at 16:53, Arnaud Pouliquen arnaud.pouliquen@st.com wrote:
>> 
>> > On 2/10/20 5:22 PM, Clement Leger wrote:
>> >> With upcoming changes in elf loader for elf64 support, section size will
>> >> be a u64. When used with da_to_va, this will potentially lead to
>> >> overflow if using the current "int" type for len argument. Change
>> >> da_to_va prototype to use a u64 for len and fix all users of this
>> >> function.
>> >> 
>> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> >> ---
>> >>  drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
>> >>  drivers/remoteproc/keystone_remoteproc.c |  4 ++--
>> >>  drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
>> >>  drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
>> >>  drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
>> >>  drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
>> >>  drivers/remoteproc/qcom_wcnss.c          |  2 +-
>> >>  drivers/remoteproc/remoteproc_core.c     |  2 +-
>> >>  drivers/remoteproc/remoteproc_internal.h |  2 +-
>> >>  drivers/remoteproc/st_slim_rproc.c       |  4 ++--
>> >>  drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
>> >>  include/linux/remoteproc.h               |  2 +-
>> >>  12 files changed, 20 insertions(+), 19 deletions(-)
>> >> 
>> >> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
>> >> index 3e72b6f38d4b..f497f5b49b18 100644
>> >> --- a/drivers/remoteproc/imx_rproc.c
>> >> +++ b/drivers/remoteproc/imx_rproc.c
>> >> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
>> >>  }
>> >>  
>> >>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
>> >> -			       int len, u64 *sys)
>> >> +			       u64 len, u64 *sys)
>> >>  {
>> >>  	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
>> >>  	int i;
>> >> @@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64
>> >> da,
>> >>  		}
>> >>  	}
>> >>  
>> >> -	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
>> >> +	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
>> >>  		 da, len);
>> >>  	return -ENOENT;
>> >>  }
>> >>  
>> >> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >>  {
>> >>  	struct imx_rproc *priv = rproc->priv;
>> >>  	void *va = NULL;
>> >>  	u64 sys;
>> >>  	int i;
>> >>  
>> >> -	if (len <= 0)
>> >> +	if (len == 0)
>> >>  		return NULL;
>> >>  
>> >>  	/*
>> >> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da,
>> >> int len)
>> >>  		}
>> >>  	}
>> >>  
>> >> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
>> >> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
>> >> +		da, len, va);
>> >>  
>> >>  	return va;
>> >>  }
>> >> diff --git a/drivers/remoteproc/keystone_remoteproc.c
>> >> b/drivers/remoteproc/keystone_remoteproc.c
>> >> index 5c4658f00b3d..466093f48814 100644
>> >> --- a/drivers/remoteproc/keystone_remoteproc.c
>> >> +++ b/drivers/remoteproc/keystone_remoteproc.c
>> >> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int
>> >> vqid)
>> >>   * can be used either by the remoteproc core for loading (when using kernel
>> >>   * remoteproc loader), or by any rpmsg bus drivers.
>> >>   */
>> >> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >>  {
>> >>  	struct keystone_rproc *ksproc = rproc->priv;
>> >>  	void __iomem *va = NULL;
>> >> @@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc,
>> >> u64 da, int len)
>> >>  	size_t size;
>> >>  	int i;
>> >>  
>> >> -	if (len <= 0)
>> >> +	if (len == 0)
>> >>  		return NULL;
>> >>  
>> >>  	for (i = 0; i < ksproc->num_mems; i++) {
>> >> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c
>> >> b/drivers/remoteproc/qcom_q6v5_adsp.c
>> >> index e953886b2eb7..7518e67a49e5 100644
>> >> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
>> >> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
>> >> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>> >>  	return ret;
>> >>  }
>> >>  
>> >> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >>  {
>> >>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>> >>  	int offset;
>> >> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c
>> >> b/drivers/remoteproc/qcom_q6v5_mss.c
>> >> index 471128a2e723..248febde6fc1 100644
>> >> --- a/drivers/remoteproc/qcom_q6v5_mss.c
>> >> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
>> >> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>> >>  	return 0;
>> >>  }
>> >>  
>> >> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >>  {
>> >>  	struct q6v5 *qproc = rproc->priv;
>> >>  	int offset;
>> >> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c
>> >> b/drivers/remoteproc/qcom_q6v5_pas.c
>> >> index db4b3c4bacd7..cf2cd609c90d 100644
>> >> --- a/drivers/remoteproc/qcom_q6v5_pas.c
>> >> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
>> >> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>> >>  	return ret;
>> >>  }
>> >>  
>> >> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >>  {
>> >>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>> >>  	int offset;
>> >> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c
>> >> b/drivers/remoteproc/qcom_q6v5_wcss.c
>> >> index f93e1e4a1cc0..3a6b82a16961 100644
>> >> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
>> >> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
>> >> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>> >>  	return 0;
>> >>  }
>> >>  
>> >> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >>  {
>> >>  	struct q6v5_wcss *wcss = rproc->priv;
>> >>  	int offset;
>> >> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
>> >> index dc135754bb9c..f893219e45a8 100644
>> >> --- a/drivers/remoteproc/qcom_wcnss.c
>> >> +++ b/drivers/remoteproc/qcom_wcnss.c
>> >> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>> >>  	return ret;
>> >>  }
>> >>  
>> >> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >>  {
>> >>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>> >>  	int offset;
>> >> diff --git a/drivers/remoteproc/remoteproc_core.c
>> >> b/drivers/remoteproc/remoteproc_core.c
>> >> index 307df98347ba..9e6d3c6a60ee 100644
>> >> --- a/drivers/remoteproc/remoteproc_core.c
>> >> +++ b/drivers/remoteproc/remoteproc_core.c
>> >> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>> >>   * here the output of the DMA API for the carveouts, which should be more
>> >>   * correct.
>> >>   */
>> >> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> > 
>> > This function is exported, don't see any update in consequence...
>> > references:
>> > https://elixir.bootlin.com/linux/v5.6-rc1/ident/rproc_da_to_va
>> > For instance the function rproc_trace_read use it. it quite strange that my gcc
>> > does not warns for the cast but i suppose that some could.
>> 
>> Agreed, even if len should never have been a signed type since it can't be
>> negative. I will try to fix all callers.
>> 
>> > An indirect consequence is that the len field in rproc_mem_entry struct should
>> > probably been updated to u64 to be aligned.
>> 
>> Ok, I will do that once we settle on the type of len.
>> 
>> > 
>> > I'm still wondering about the use of size_t instead,which seems more rational
>> > from my window.
>> > So i you or Mathieu remember it was decided to use u64, please could remind me
>> > the arguments?
>> 
>> I tried to find the notes of a meeting we had for OpenAMP but I did not found
>> them. Anyway, the argument was coming from Tomas or someone else, (I can't
>> remember) talking about a 32 bits CPU executing code on a 64 bits accelerator.
>> In that case, the size_t type could fail due to being only 32bits on the host
>> CPU but larger than 4G.
>> 
>> However, I can't say if it's a real usecase or not... All I can say is
>> that keeping it open is probably better if one day somebody comes with such
>> architecture.
> 
> In order to support a 32bit AP with a 64bit MCU we'd also have to deal with all
> the dma_attr_t in the structure we use.

Totally ok with that... 

> 
> Also something that became very clear to me while thinking about this patchset
> is that supporting elf64 does __not__ mean we support 64bit MCU.  As long as
> the addresses conveyed by the elf64 image fit within 32 bits we are fine.
> Supporting 64bit MCUs is a completely different topic, one that will demand
> serious refactoring.

Exactly, an elf64 can potentially contain an executable fitting in 32 bits.

> 
> So moving from "int len" to "u64 len" doesn't give us much.  It doesn't hurt to
> do it but if @len ever becomes bigger than 31 bits we'll have other problems to
> deal with.

Agreed, so what would be your recommendation reagrding the type of len ?
I'm ok with Arnaud statement too and using a size_t is probably more
"type-safe" than a u64. At least it adds some information.

Thanks,

Clément

> 
>> 
>> > As an alternative a check should be added for 32 bits processors to ensure that
>> > the size is not higher than
>> > its address range capability...
>> 
>> Agreed.
>> I was even thinking about a mecanism for remoteproc drivers to declare the type
>> of supported elfs files (such as EM_*, ELFCLASS* and other needed thing).
>> Or should it be supported by overriding .sanity_check in drivers  to reject
>> elf64 for instance ?
>> 
>> Since elf is a "specific format" and that rproc can support other formats,
>> I did not want to add a specific elf_sanity_check field to rproc ops.
>> 
>> Regards,
>> 
>> Clément
>> 
>> > 
>> > Regards
>> > Arnaud
>> > 
>> >>  {
>> >>  	struct rproc_mem_entry *carveout;
>> >>  	void *ptr = NULL;
>> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> >> b/drivers/remoteproc/remoteproc_internal.h
>> >> index 493ef9262411..004867061721 100644
>> >> --- a/drivers/remoteproc/remoteproc_internal.h
>> >> +++ b/drivers/remoteproc/remoteproc_internal.h
>> >> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>> >>  void rproc_free_vring(struct rproc_vring *rvring);
>> >>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>> >>  
>> >> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
>> >> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
>> >>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>> >>  int rproc_trigger_recovery(struct rproc *rproc);
>> >>  
>> >> diff --git a/drivers/remoteproc/st_slim_rproc.c
>> >> b/drivers/remoteproc/st_slim_rproc.c
>> >> index 04492fead3c8..fc01cd879b60 100644
>> >> --- a/drivers/remoteproc/st_slim_rproc.c
>> >> +++ b/drivers/remoteproc/st_slim_rproc.c
>> >> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>> >>  	return 0;
>> >>  }
>> >>  
>> >> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >>  {
>> >>  	struct st_slim_rproc *slim_rproc = rproc->priv;
>> >>  	void *va = NULL;
>> >> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64
>> >> da, int len)
>> >>  		}
>> >>  	}
>> >>  
>> >> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
>> >> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
>> >>  		da, len, va);
>> >>  
>> >>  	return va;
>> >> diff --git a/drivers/remoteproc/wkup_m3_rproc.c
>> >> b/drivers/remoteproc/wkup_m3_rproc.c
>> >> index 3984e585c847..91485b467407 100644
>> >> --- a/drivers/remoteproc/wkup_m3_rproc.c
>> >> +++ b/drivers/remoteproc/wkup_m3_rproc.c
>> >> @@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>> >>  	return 0;
>> >>  }
>> >>  
>> >> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >>  {
>> >>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
>> >>  	void *va = NULL;
>> >>  	int i;
>> >>  	u32 offset;
>> >>  
>> >> -	if (len <= 0)
>> >> +	if (len == 0)
>> >>  		return NULL;
>> >>  
>> >>  	for (i = 0; i < WKUPM3_MEM_MAX; i++) {
>> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> >> index 16ad66683ad0..f84bd5fe0211 100644
>> >> --- a/include/linux/remoteproc.h
>> >> +++ b/include/linux/remoteproc.h
>> >> @@ -374,7 +374,7 @@ struct rproc_ops {
>> >>  	int (*start)(struct rproc *rproc);
>> >>  	int (*stop)(struct rproc *rproc);
>> >>  	void (*kick)(struct rproc *rproc, int vqid);
>> >> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
>> >> +	void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
>> >>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>> >>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
> > >>  			  int offset, int avail);

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va
  2020-02-12 10:37                                           ` Clément Leger
@ 2020-02-12 21:59                                             ` Mathieu Poirier
  2020-02-18 10:10                                               ` Clément Leger
  0 siblings, 1 reply; 76+ messages in thread
From: Mathieu Poirier @ 2020-02-12 21:59 UTC (permalink / raw)
  To: Clément Leger
  Cc: Arnaud Pouliquen, Ohad Ben-Cohen, Bjorn Andersson,
	Jonathan Corbet, Shawn Guo, Sascha Hauer, linux-remoteproc,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Loic PALLARDY, s-anna

On Wed, 12 Feb 2020 at 03:37, Clément Leger <cleger@kalray.eu> wrote:
>
> Hi Mathieu,
>
> ----- On 11 Feb, 2020, at 23:37, Mathieu Poirier mathieu.poirier@linaro.org wrote:
>
> > On Tue, Feb 11, 2020 at 05:39:21PM +0100, Clément Leger wrote:
> >> Hi Arnaud,
> >>
> >> ----- On 11 Feb, 2020, at 16:53, Arnaud Pouliquen arnaud.pouliquen@st.com wrote:
> >>
> >> > On 2/10/20 5:22 PM, Clement Leger wrote:
> >> >> With upcoming changes in elf loader for elf64 support, section size will
> >> >> be a u64. When used with da_to_va, this will potentially lead to
> >> >> overflow if using the current "int" type for len argument. Change
> >> >> da_to_va prototype to use a u64 for len and fix all users of this
> >> >> function.
> >> >>
> >> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
> >> >> ---
> >> >>  drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
> >> >>  drivers/remoteproc/keystone_remoteproc.c |  4 ++--
> >> >>  drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
> >> >>  drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
> >> >>  drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
> >> >>  drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
> >> >>  drivers/remoteproc/qcom_wcnss.c          |  2 +-
> >> >>  drivers/remoteproc/remoteproc_core.c     |  2 +-
> >> >>  drivers/remoteproc/remoteproc_internal.h |  2 +-
> >> >>  drivers/remoteproc/st_slim_rproc.c       |  4 ++--
> >> >>  drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
> >> >>  include/linux/remoteproc.h               |  2 +-
> >> >>  12 files changed, 20 insertions(+), 19 deletions(-)
> >> >>
> >> >> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> >> >> index 3e72b6f38d4b..f497f5b49b18 100644
> >> >> --- a/drivers/remoteproc/imx_rproc.c
> >> >> +++ b/drivers/remoteproc/imx_rproc.c
> >> >> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
> >> >>  }
> >> >>
> >> >>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
> >> >> -                        int len, u64 *sys)
> >> >> +                        u64 len, u64 *sys)
> >> >>  {
> >> >>   const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> >> >>   int i;
> >> >> @@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64
> >> >> da,
> >> >>           }
> >> >>   }
> >> >>
> >> >> - dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
> >> >> + dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
> >> >>            da, len);
> >> >>   return -ENOENT;
> >> >>  }
> >> >>
> >> >> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >>  {
> >> >>   struct imx_rproc *priv = rproc->priv;
> >> >>   void *va = NULL;
> >> >>   u64 sys;
> >> >>   int i;
> >> >>
> >> >> - if (len <= 0)
> >> >> + if (len == 0)
> >> >>           return NULL;
> >> >>
> >> >>   /*
> >> >> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da,
> >> >> int len)
> >> >>           }
> >> >>   }
> >> >>
> >> >> - dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
> >> >> + dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
> >> >> +         da, len, va);
> >> >>
> >> >>   return va;
> >> >>  }
> >> >> diff --git a/drivers/remoteproc/keystone_remoteproc.c
> >> >> b/drivers/remoteproc/keystone_remoteproc.c
> >> >> index 5c4658f00b3d..466093f48814 100644
> >> >> --- a/drivers/remoteproc/keystone_remoteproc.c
> >> >> +++ b/drivers/remoteproc/keystone_remoteproc.c
> >> >> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int
> >> >> vqid)
> >> >>   * can be used either by the remoteproc core for loading (when using kernel
> >> >>   * remoteproc loader), or by any rpmsg bus drivers.
> >> >>   */
> >> >> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >>  {
> >> >>   struct keystone_rproc *ksproc = rproc->priv;
> >> >>   void __iomem *va = NULL;
> >> >> @@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc,
> >> >> u64 da, int len)
> >> >>   size_t size;
> >> >>   int i;
> >> >>
> >> >> - if (len <= 0)
> >> >> + if (len == 0)
> >> >>           return NULL;
> >> >>
> >> >>   for (i = 0; i < ksproc->num_mems; i++) {
> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c
> >> >> b/drivers/remoteproc/qcom_q6v5_adsp.c
> >> >> index e953886b2eb7..7518e67a49e5 100644
> >> >> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> >> >> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> >> >> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
> >> >>   return ret;
> >> >>  }
> >> >>
> >> >> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >>  {
> >> >>   struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
> >> >>   int offset;
> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c
> >> >> b/drivers/remoteproc/qcom_q6v5_mss.c
> >> >> index 471128a2e723..248febde6fc1 100644
> >> >> --- a/drivers/remoteproc/qcom_q6v5_mss.c
> >> >> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
> >> >> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
> >> >>   return 0;
> >> >>  }
> >> >>
> >> >> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >>  {
> >> >>   struct q6v5 *qproc = rproc->priv;
> >> >>   int offset;
> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c
> >> >> b/drivers/remoteproc/qcom_q6v5_pas.c
> >> >> index db4b3c4bacd7..cf2cd609c90d 100644
> >> >> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> >> >> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> >> >> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
> >> >>   return ret;
> >> >>  }
> >> >>
> >> >> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >>  {
> >> >>   struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
> >> >>   int offset;
> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c
> >> >> b/drivers/remoteproc/qcom_q6v5_wcss.c
> >> >> index f93e1e4a1cc0..3a6b82a16961 100644
> >> >> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
> >> >> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
> >> >> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
> >> >>   return 0;
> >> >>  }
> >> >>
> >> >> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >>  {
> >> >>   struct q6v5_wcss *wcss = rproc->priv;
> >> >>   int offset;
> >> >> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> >> >> index dc135754bb9c..f893219e45a8 100644
> >> >> --- a/drivers/remoteproc/qcom_wcnss.c
> >> >> +++ b/drivers/remoteproc/qcom_wcnss.c
> >> >> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
> >> >>   return ret;
> >> >>  }
> >> >>
> >> >> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >>  {
> >> >>   struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
> >> >>   int offset;
> >> >> diff --git a/drivers/remoteproc/remoteproc_core.c
> >> >> b/drivers/remoteproc/remoteproc_core.c
> >> >> index 307df98347ba..9e6d3c6a60ee 100644
> >> >> --- a/drivers/remoteproc/remoteproc_core.c
> >> >> +++ b/drivers/remoteproc/remoteproc_core.c
> >> >> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
> >> >>   * here the output of the DMA API for the carveouts, which should be more
> >> >>   * correct.
> >> >>   */
> >> >> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >
> >> > This function is exported, don't see any update in consequence...
> >> > references:
> >> > https://elixir.bootlin.com/linux/v5.6-rc1/ident/rproc_da_to_va
> >> > For instance the function rproc_trace_read use it. it quite strange that my gcc
> >> > does not warns for the cast but i suppose that some could.
> >>
> >> Agreed, even if len should never have been a signed type since it can't be
> >> negative. I will try to fix all callers.
> >>
> >> > An indirect consequence is that the len field in rproc_mem_entry struct should
> >> > probably been updated to u64 to be aligned.
> >>
> >> Ok, I will do that once we settle on the type of len.
> >>
> >> >
> >> > I'm still wondering about the use of size_t instead,which seems more rational
> >> > from my window.
> >> > So i you or Mathieu remember it was decided to use u64, please could remind me
> >> > the arguments?
> >>
> >> I tried to find the notes of a meeting we had for OpenAMP but I did not found
> >> them. Anyway, the argument was coming from Tomas or someone else, (I can't
> >> remember) talking about a 32 bits CPU executing code on a 64 bits accelerator.
> >> In that case, the size_t type could fail due to being only 32bits on the host
> >> CPU but larger than 4G.
> >>
> >> However, I can't say if it's a real usecase or not... All I can say is
> >> that keeping it open is probably better if one day somebody comes with such
> >> architecture.
> >
> > In order to support a 32bit AP with a 64bit MCU we'd also have to deal with all
> > the dma_attr_t in the structure we use.
>
> Totally ok with that...
>
> >
> > Also something that became very clear to me while thinking about this patchset
> > is that supporting elf64 does __not__ mean we support 64bit MCU.  As long as
> > the addresses conveyed by the elf64 image fit within 32 bits we are fine.
> > Supporting 64bit MCUs is a completely different topic, one that will demand
> > serious refactoring.
>
> Exactly, an elf64 can potentially contain an executable fitting in 32 bits.
>
> >
> > So moving from "int len" to "u64 len" doesn't give us much.  It doesn't hurt to
> > do it but if @len ever becomes bigger than 31 bits we'll have other problems to
> > deal with.
>
> Agreed, so what would be your recommendation reagrding the type of len ?
> I'm ok with Arnaud statement too and using a size_t is probably more
> "type-safe" than a u64. At least it adds some information.

If @len becomes big enough that it doesn't fit in 31bit then it is
very likely that things will break even before we get to call
rproc_da_to_va().  Fixing it here is possible but will introduce a
fair amount of ripple effect that we probably don't want to deal with
right now.

Other people might feel more opinionated on this but as far as I'm
concerned, I would keep it as it is and fix it for real when the time
comes to add support for 64bit MCUs.

>
> Thanks,
>
> Clément
>
> >
> >>
> >> > As an alternative a check should be added for 32 bits processors to ensure that
> >> > the size is not higher than
> >> > its address range capability...
> >>
> >> Agreed.
> >> I was even thinking about a mecanism for remoteproc drivers to declare the type
> >> of supported elfs files (such as EM_*, ELFCLASS* and other needed thing).
> >> Or should it be supported by overriding .sanity_check in drivers  to reject
> >> elf64 for instance ?
> >>
> >> Since elf is a "specific format" and that rproc can support other formats,
> >> I did not want to add a specific elf_sanity_check field to rproc ops.
> >>
> >> Regards,
> >>
> >> Clément
> >>
> >> >
> >> > Regards
> >> > Arnaud
> >> >
> >> >>  {
> >> >>   struct rproc_mem_entry *carveout;
> >> >>   void *ptr = NULL;
> >> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
> >> >> b/drivers/remoteproc/remoteproc_internal.h
> >> >> index 493ef9262411..004867061721 100644
> >> >> --- a/drivers/remoteproc/remoteproc_internal.h
> >> >> +++ b/drivers/remoteproc/remoteproc_internal.h
> >> >> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
> >> >>  void rproc_free_vring(struct rproc_vring *rvring);
> >> >>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
> >> >>
> >> >> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
> >> >> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
> >> >>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
> >> >>  int rproc_trigger_recovery(struct rproc *rproc);
> >> >>
> >> >> diff --git a/drivers/remoteproc/st_slim_rproc.c
> >> >> b/drivers/remoteproc/st_slim_rproc.c
> >> >> index 04492fead3c8..fc01cd879b60 100644
> >> >> --- a/drivers/remoteproc/st_slim_rproc.c
> >> >> +++ b/drivers/remoteproc/st_slim_rproc.c
> >> >> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
> >> >>   return 0;
> >> >>  }
> >> >>
> >> >> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >>  {
> >> >>   struct st_slim_rproc *slim_rproc = rproc->priv;
> >> >>   void *va = NULL;
> >> >> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64
> >> >> da, int len)
> >> >>           }
> >> >>   }
> >> >>
> >> >> - dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
> >> >> + dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
> >> >>           da, len, va);
> >> >>
> >> >>   return va;
> >> >> diff --git a/drivers/remoteproc/wkup_m3_rproc.c
> >> >> b/drivers/remoteproc/wkup_m3_rproc.c
> >> >> index 3984e585c847..91485b467407 100644
> >> >> --- a/drivers/remoteproc/wkup_m3_rproc.c
> >> >> +++ b/drivers/remoteproc/wkup_m3_rproc.c
> >> >> @@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
> >> >>   return 0;
> >> >>  }
> >> >>
> >> >> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >>  {
> >> >>   struct wkup_m3_rproc *wkupm3 = rproc->priv;
> >> >>   void *va = NULL;
> >> >>   int i;
> >> >>   u32 offset;
> >> >>
> >> >> - if (len <= 0)
> >> >> + if (len == 0)
> >> >>           return NULL;
> >> >>
> >> >>   for (i = 0; i < WKUPM3_MEM_MAX; i++) {
> >> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> >> >> index 16ad66683ad0..f84bd5fe0211 100644
> >> >> --- a/include/linux/remoteproc.h
> >> >> +++ b/include/linux/remoteproc.h
> >> >> @@ -374,7 +374,7 @@ struct rproc_ops {
> >> >>   int (*start)(struct rproc *rproc);
> >> >>   int (*stop)(struct rproc *rproc);
> >> >>   void (*kick)(struct rproc *rproc, int vqid);
> >> >> - void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
> >> >> + void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
> >> >>   int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
> >> >>   int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
> > > >>                            int offset, int avail);

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va
  2020-02-12 21:59                                             ` Mathieu Poirier
@ 2020-02-18 10:10                                               ` Clément Leger
  2020-02-18 17:01                                                 ` Mathieu Poirier
  0 siblings, 1 reply; 76+ messages in thread
From: Clément Leger @ 2020-02-18 10:10 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Arnaud Pouliquen, Ohad Ben-Cohen, Bjorn Andersson,
	Jonathan Corbet, Shawn Guo, Sascha Hauer, linux-remoteproc,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Loic PALLARDY, s-anna

Hi Mathieu,

----- On 12 Feb, 2020, at 22:59, Mathieu Poirier mathieu.poirier@linaro.org wrote:

> On Wed, 12 Feb 2020 at 03:37, Clément Leger <cleger@kalray.eu> wrote:
>>
>> Hi Mathieu,
>>
>> ----- On 11 Feb, 2020, at 23:37, Mathieu Poirier mathieu.poirier@linaro.org
>> wrote:
>>
>> > On Tue, Feb 11, 2020 at 05:39:21PM +0100, Clément Leger wrote:
>> >> Hi Arnaud,
>> >>
>> >> ----- On 11 Feb, 2020, at 16:53, Arnaud Pouliquen arnaud.pouliquen@st.com wrote:
>> >>
>> >> > On 2/10/20 5:22 PM, Clement Leger wrote:
>> >> >> With upcoming changes in elf loader for elf64 support, section size will
>> >> >> be a u64. When used with da_to_va, this will potentially lead to
>> >> >> overflow if using the current "int" type for len argument. Change
>> >> >> da_to_va prototype to use a u64 for len and fix all users of this
>> >> >> function.
>> >> >>
>> >> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> >> >> ---
>> >> >>  drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
>> >> >>  drivers/remoteproc/keystone_remoteproc.c |  4 ++--
>> >> >>  drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
>> >> >>  drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
>> >> >>  drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
>> >> >>  drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
>> >> >>  drivers/remoteproc/qcom_wcnss.c          |  2 +-
>> >> >>  drivers/remoteproc/remoteproc_core.c     |  2 +-
>> >> >>  drivers/remoteproc/remoteproc_internal.h |  2 +-
>> >> >>  drivers/remoteproc/st_slim_rproc.c       |  4 ++--
>> >> >>  drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
>> >> >>  include/linux/remoteproc.h               |  2 +-
>> >> >>  12 files changed, 20 insertions(+), 19 deletions(-)
>> >> >>
>> >> >> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
>> >> >> index 3e72b6f38d4b..f497f5b49b18 100644
>> >> >> --- a/drivers/remoteproc/imx_rproc.c
>> >> >> +++ b/drivers/remoteproc/imx_rproc.c
>> >> >> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
>> >> >>  }
>> >> >>
>> >> >>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
>> >> >> -                        int len, u64 *sys)
>> >> >> +                        u64 len, u64 *sys)
>> >> >>  {
>> >> >>   const struct imx_rproc_dcfg *dcfg = priv->dcfg;
>> >> >>   int i;
>> >> >> @@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64
>> >> >> da,
>> >> >>           }
>> >> >>   }
>> >> >>
>> >> >> - dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
>> >> >> + dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
>> >> >>            da, len);
>> >> >>   return -ENOENT;
>> >> >>  }
>> >> >>
>> >> >> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >> >>  {
>> >> >>   struct imx_rproc *priv = rproc->priv;
>> >> >>   void *va = NULL;
>> >> >>   u64 sys;
>> >> >>   int i;
>> >> >>
>> >> >> - if (len <= 0)
>> >> >> + if (len == 0)
>> >> >>           return NULL;
>> >> >>
>> >> >>   /*
>> >> >> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da,
>> >> >> int len)
>> >> >>           }
>> >> >>   }
>> >> >>
>> >> >> - dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
>> >> >> + dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
>> >> >> +         da, len, va);
>> >> >>
>> >> >>   return va;
>> >> >>  }
>> >> >> diff --git a/drivers/remoteproc/keystone_remoteproc.c
>> >> >> b/drivers/remoteproc/keystone_remoteproc.c
>> >> >> index 5c4658f00b3d..466093f48814 100644
>> >> >> --- a/drivers/remoteproc/keystone_remoteproc.c
>> >> >> +++ b/drivers/remoteproc/keystone_remoteproc.c
>> >> >> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int
>> >> >> vqid)
>> >> >>   * can be used either by the remoteproc core for loading (when using kernel
>> >> >>   * remoteproc loader), or by any rpmsg bus drivers.
>> >> >>   */
>> >> >> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >> >>  {
>> >> >>   struct keystone_rproc *ksproc = rproc->priv;
>> >> >>   void __iomem *va = NULL;
>> >> >> @@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc,
>> >> >> u64 da, int len)
>> >> >>   size_t size;
>> >> >>   int i;
>> >> >>
>> >> >> - if (len <= 0)
>> >> >> + if (len == 0)
>> >> >>           return NULL;
>> >> >>
>> >> >>   for (i = 0; i < ksproc->num_mems; i++) {
>> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c
>> >> >> b/drivers/remoteproc/qcom_q6v5_adsp.c
>> >> >> index e953886b2eb7..7518e67a49e5 100644
>> >> >> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
>> >> >> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
>> >> >> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>> >> >>   return ret;
>> >> >>  }
>> >> >>
>> >> >> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >> >>  {
>> >> >>   struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>> >> >>   int offset;
>> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c
>> >> >> b/drivers/remoteproc/qcom_q6v5_mss.c
>> >> >> index 471128a2e723..248febde6fc1 100644
>> >> >> --- a/drivers/remoteproc/qcom_q6v5_mss.c
>> >> >> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
>> >> >> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>> >> >>   return 0;
>> >> >>  }
>> >> >>
>> >> >> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >> >>  {
>> >> >>   struct q6v5 *qproc = rproc->priv;
>> >> >>   int offset;
>> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c
>> >> >> b/drivers/remoteproc/qcom_q6v5_pas.c
>> >> >> index db4b3c4bacd7..cf2cd609c90d 100644
>> >> >> --- a/drivers/remoteproc/qcom_q6v5_pas.c
>> >> >> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
>> >> >> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>> >> >>   return ret;
>> >> >>  }
>> >> >>
>> >> >> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >> >>  {
>> >> >>   struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>> >> >>   int offset;
>> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c
>> >> >> b/drivers/remoteproc/qcom_q6v5_wcss.c
>> >> >> index f93e1e4a1cc0..3a6b82a16961 100644
>> >> >> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
>> >> >> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
>> >> >> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>> >> >>   return 0;
>> >> >>  }
>> >> >>
>> >> >> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >> >>  {
>> >> >>   struct q6v5_wcss *wcss = rproc->priv;
>> >> >>   int offset;
>> >> >> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
>> >> >> index dc135754bb9c..f893219e45a8 100644
>> >> >> --- a/drivers/remoteproc/qcom_wcnss.c
>> >> >> +++ b/drivers/remoteproc/qcom_wcnss.c
>> >> >> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>> >> >>   return ret;
>> >> >>  }
>> >> >>
>> >> >> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >> >>  {
>> >> >>   struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>> >> >>   int offset;
>> >> >> diff --git a/drivers/remoteproc/remoteproc_core.c
>> >> >> b/drivers/remoteproc/remoteproc_core.c
>> >> >> index 307df98347ba..9e6d3c6a60ee 100644
>> >> >> --- a/drivers/remoteproc/remoteproc_core.c
>> >> >> +++ b/drivers/remoteproc/remoteproc_core.c
>> >> >> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>> >> >>   * here the output of the DMA API for the carveouts, which should be more
>> >> >>   * correct.
>> >> >>   */
>> >> >> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >> >
>> >> > This function is exported, don't see any update in consequence...
>> >> > references:
>> >> > https://elixir.bootlin.com/linux/v5.6-rc1/ident/rproc_da_to_va
>> >> > For instance the function rproc_trace_read use it. it quite strange that my gcc
>> >> > does not warns for the cast but i suppose that some could.
>> >>
>> >> Agreed, even if len should never have been a signed type since it can't be
>> >> negative. I will try to fix all callers.
>> >>
>> >> > An indirect consequence is that the len field in rproc_mem_entry struct should
>> >> > probably been updated to u64 to be aligned.
>> >>
>> >> Ok, I will do that once we settle on the type of len.
>> >>
>> >> >
>> >> > I'm still wondering about the use of size_t instead,which seems more rational
>> >> > from my window.
>> >> > So i you or Mathieu remember it was decided to use u64, please could remind me
>> >> > the arguments?
>> >>
>> >> I tried to find the notes of a meeting we had for OpenAMP but I did not found
>> >> them. Anyway, the argument was coming from Tomas or someone else, (I can't
>> >> remember) talking about a 32 bits CPU executing code on a 64 bits accelerator.
>> >> In that case, the size_t type could fail due to being only 32bits on the host
>> >> CPU but larger than 4G.
>> >>
>> >> However, I can't say if it's a real usecase or not... All I can say is
>> >> that keeping it open is probably better if one day somebody comes with such
>> >> architecture.
>> >
>> > In order to support a 32bit AP with a 64bit MCU we'd also have to deal with all
>> > the dma_attr_t in the structure we use.
>>
>> Totally ok with that...
>>
>> >
>> > Also something that became very clear to me while thinking about this patchset
>> > is that supporting elf64 does __not__ mean we support 64bit MCU.  As long as
>> > the addresses conveyed by the elf64 image fit within 32 bits we are fine.
>> > Supporting 64bit MCUs is a completely different topic, one that will demand
>> > serious refactoring.
>>
>> Exactly, an elf64 can potentially contain an executable fitting in 32 bits.
>>
>> >
>> > So moving from "int len" to "u64 len" doesn't give us much.  It doesn't hurt to
>> > do it but if @len ever becomes bigger than 31 bits we'll have other problems to
>> > deal with.
>>
>> Agreed, so what would be your recommendation reagrding the type of len ?
>> I'm ok with Arnaud statement too and using a size_t is probably more
>> "type-safe" than a u64. At least it adds some information.
> 
> If @len becomes big enough that it doesn't fit in 31bit then it is
> very likely that things will break even before we get to call
> rproc_da_to_va().  Fixing it here is possible but will introduce a
> fair amount of ripple effect that we probably don't want to deal with
> right now.

I did the modification using u64 and tried to follow various code path.
Some end up in dma_alloc_coherent which uses a size_t member. Since
these might be called by rproc with a u64 len, I would be more
inclined to use a size_t. I can probably also add a check in elf loader
which verifies that if sizeof(size_t) < sizeof(u64), then the len must
fit in 32bits. This seems more clean IMHO.

Clément.

> 
> Other people might feel more opinionated on this but as far as I'm
> concerned, I would keep it as it is and fix it for real when the time
> comes to add support for 64bit MCUs.
> 
>>
>> Thanks,
>>
>> Clément
>>
>> >
>> >>
>> >> > As an alternative a check should be added for 32 bits processors to ensure that
>> >> > the size is not higher than
>> >> > its address range capability...
>> >>
>> >> Agreed.
>> >> I was even thinking about a mecanism for remoteproc drivers to declare the type
>> >> of supported elfs files (such as EM_*, ELFCLASS* and other needed thing).
>> >> Or should it be supported by overriding .sanity_check in drivers  to reject
>> >> elf64 for instance ?
>> >>
>> >> Since elf is a "specific format" and that rproc can support other formats,
>> >> I did not want to add a specific elf_sanity_check field to rproc ops.
>> >>
>> >> Regards,
>> >>
>> >> Clément
>> >>
>> >> >
>> >> > Regards
>> >> > Arnaud
>> >> >
>> >> >>  {
>> >> >>   struct rproc_mem_entry *carveout;
>> >> >>   void *ptr = NULL;
>> >> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> >> >> b/drivers/remoteproc/remoteproc_internal.h
>> >> >> index 493ef9262411..004867061721 100644
>> >> >> --- a/drivers/remoteproc/remoteproc_internal.h
>> >> >> +++ b/drivers/remoteproc/remoteproc_internal.h
>> >> >> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>> >> >>  void rproc_free_vring(struct rproc_vring *rvring);
>> >> >>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>> >> >>
>> >> >> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
>> >> >> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
>> >> >>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>> >> >>  int rproc_trigger_recovery(struct rproc *rproc);
>> >> >>
>> >> >> diff --git a/drivers/remoteproc/st_slim_rproc.c
>> >> >> b/drivers/remoteproc/st_slim_rproc.c
>> >> >> index 04492fead3c8..fc01cd879b60 100644
>> >> >> --- a/drivers/remoteproc/st_slim_rproc.c
>> >> >> +++ b/drivers/remoteproc/st_slim_rproc.c
>> >> >> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>> >> >>   return 0;
>> >> >>  }
>> >> >>
>> >> >> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >> >>  {
>> >> >>   struct st_slim_rproc *slim_rproc = rproc->priv;
>> >> >>   void *va = NULL;
>> >> >> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64
>> >> >> da, int len)
>> >> >>           }
>> >> >>   }
>> >> >>
>> >> >> - dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
>> >> >> + dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
>> >> >>           da, len, va);
>> >> >>
>> >> >>   return va;
>> >> >> diff --git a/drivers/remoteproc/wkup_m3_rproc.c
>> >> >> b/drivers/remoteproc/wkup_m3_rproc.c
>> >> >> index 3984e585c847..91485b467407 100644
>> >> >> --- a/drivers/remoteproc/wkup_m3_rproc.c
>> >> >> +++ b/drivers/remoteproc/wkup_m3_rproc.c
>> >> >> @@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>> >> >>   return 0;
>> >> >>  }
>> >> >>
>> >> >> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>> >> >> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
>> >> >>  {
>> >> >>   struct wkup_m3_rproc *wkupm3 = rproc->priv;
>> >> >>   void *va = NULL;
>> >> >>   int i;
>> >> >>   u32 offset;
>> >> >>
>> >> >> - if (len <= 0)
>> >> >> + if (len == 0)
>> >> >>           return NULL;
>> >> >>
>> >> >>   for (i = 0; i < WKUPM3_MEM_MAX; i++) {
>> >> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> >> >> index 16ad66683ad0..f84bd5fe0211 100644
>> >> >> --- a/include/linux/remoteproc.h
>> >> >> +++ b/include/linux/remoteproc.h
>> >> >> @@ -374,7 +374,7 @@ struct rproc_ops {
>> >> >>   int (*start)(struct rproc *rproc);
>> >> >>   int (*stop)(struct rproc *rproc);
>> >> >>   void (*kick)(struct rproc *rproc, int vqid);
>> >> >> - void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
>> >> >> + void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
>> >> >>   int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>> >> >>   int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
> > > > >>                            int offset, int avail);

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v4 1/5] remoteproc: Use u64 len for da_to_va
  2020-02-18 10:10                                               ` Clément Leger
@ 2020-02-18 17:01                                                 ` Mathieu Poirier
  0 siblings, 0 replies; 76+ messages in thread
From: Mathieu Poirier @ 2020-02-18 17:01 UTC (permalink / raw)
  To: Clément Leger
  Cc: Arnaud Pouliquen, Ohad Ben-Cohen, Bjorn Andersson,
	Jonathan Corbet, Shawn Guo, Sascha Hauer, linux-remoteproc,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Loic PALLARDY, s-anna

On Tue, 18 Feb 2020 at 03:10, Clément Leger <cleger@kalrayinc.com> wrote:
>
> Hi Mathieu,
>
> ----- On 12 Feb, 2020, at 22:59, Mathieu Poirier mathieu.poirier@linaro.org wrote:
>
> > On Wed, 12 Feb 2020 at 03:37, Clément Leger <cleger@kalray.eu> wrote:
> >>
> >> Hi Mathieu,
> >>
> >> ----- On 11 Feb, 2020, at 23:37, Mathieu Poirier mathieu.poirier@linaro.org
> >> wrote:
> >>
> >> > On Tue, Feb 11, 2020 at 05:39:21PM +0100, Clément Leger wrote:
> >> >> Hi Arnaud,
> >> >>
> >> >> ----- On 11 Feb, 2020, at 16:53, Arnaud Pouliquen arnaud.pouliquen@st.com wrote:
> >> >>
> >> >> > On 2/10/20 5:22 PM, Clement Leger wrote:
> >> >> >> With upcoming changes in elf loader for elf64 support, section size will
> >> >> >> be a u64. When used with da_to_va, this will potentially lead to
> >> >> >> overflow if using the current "int" type for len argument. Change
> >> >> >> da_to_va prototype to use a u64 for len and fix all users of this
> >> >> >> function.
> >> >> >>
> >> >> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
> >> >> >> ---
> >> >> >>  drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
> >> >> >>  drivers/remoteproc/keystone_remoteproc.c |  4 ++--
> >> >> >>  drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
> >> >> >>  drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
> >> >> >>  drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
> >> >> >>  drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
> >> >> >>  drivers/remoteproc/qcom_wcnss.c          |  2 +-
> >> >> >>  drivers/remoteproc/remoteproc_core.c     |  2 +-
> >> >> >>  drivers/remoteproc/remoteproc_internal.h |  2 +-
> >> >> >>  drivers/remoteproc/st_slim_rproc.c       |  4 ++--
> >> >> >>  drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
> >> >> >>  include/linux/remoteproc.h               |  2 +-
> >> >> >>  12 files changed, 20 insertions(+), 19 deletions(-)
> >> >> >>
> >> >> >> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> >> >> >> index 3e72b6f38d4b..f497f5b49b18 100644
> >> >> >> --- a/drivers/remoteproc/imx_rproc.c
> >> >> >> +++ b/drivers/remoteproc/imx_rproc.c
> >> >> >> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
> >> >> >>  }
> >> >> >>
> >> >> >>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
> >> >> >> -                        int len, u64 *sys)
> >> >> >> +                        u64 len, u64 *sys)
> >> >> >>  {
> >> >> >>   const struct imx_rproc_dcfg *dcfg = priv->dcfg;
> >> >> >>   int i;
> >> >> >> @@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64
> >> >> >> da,
> >> >> >>           }
> >> >> >>   }
> >> >> >>
> >> >> >> - dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
> >> >> >> + dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%llx\n",
> >> >> >>            da, len);
> >> >> >>   return -ENOENT;
> >> >> >>  }
> >> >> >>
> >> >> >> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >> >>  {
> >> >> >>   struct imx_rproc *priv = rproc->priv;
> >> >> >>   void *va = NULL;
> >> >> >>   u64 sys;
> >> >> >>   int i;
> >> >> >>
> >> >> >> - if (len <= 0)
> >> >> >> + if (len == 0)
> >> >> >>           return NULL;
> >> >> >>
> >> >> >>   /*
> >> >> >> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da,
> >> >> >> int len)
> >> >> >>           }
> >> >> >>   }
> >> >> >>
> >> >> >> - dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
> >> >> >> + dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%p\n",
> >> >> >> +         da, len, va);
> >> >> >>
> >> >> >>   return va;
> >> >> >>  }
> >> >> >> diff --git a/drivers/remoteproc/keystone_remoteproc.c
> >> >> >> b/drivers/remoteproc/keystone_remoteproc.c
> >> >> >> index 5c4658f00b3d..466093f48814 100644
> >> >> >> --- a/drivers/remoteproc/keystone_remoteproc.c
> >> >> >> +++ b/drivers/remoteproc/keystone_remoteproc.c
> >> >> >> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int
> >> >> >> vqid)
> >> >> >>   * can be used either by the remoteproc core for loading (when using kernel
> >> >> >>   * remoteproc loader), or by any rpmsg bus drivers.
> >> >> >>   */
> >> >> >> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >> >>  {
> >> >> >>   struct keystone_rproc *ksproc = rproc->priv;
> >> >> >>   void __iomem *va = NULL;
> >> >> >> @@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc,
> >> >> >> u64 da, int len)
> >> >> >>   size_t size;
> >> >> >>   int i;
> >> >> >>
> >> >> >> - if (len <= 0)
> >> >> >> + if (len == 0)
> >> >> >>           return NULL;
> >> >> >>
> >> >> >>   for (i = 0; i < ksproc->num_mems; i++) {
> >> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c
> >> >> >> b/drivers/remoteproc/qcom_q6v5_adsp.c
> >> >> >> index e953886b2eb7..7518e67a49e5 100644
> >> >> >> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> >> >> >> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> >> >> >> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
> >> >> >>   return ret;
> >> >> >>  }
> >> >> >>
> >> >> >> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >> >>  {
> >> >> >>   struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
> >> >> >>   int offset;
> >> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c
> >> >> >> b/drivers/remoteproc/qcom_q6v5_mss.c
> >> >> >> index 471128a2e723..248febde6fc1 100644
> >> >> >> --- a/drivers/remoteproc/qcom_q6v5_mss.c
> >> >> >> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
> >> >> >> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
> >> >> >>   return 0;
> >> >> >>  }
> >> >> >>
> >> >> >> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >> >>  {
> >> >> >>   struct q6v5 *qproc = rproc->priv;
> >> >> >>   int offset;
> >> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c
> >> >> >> b/drivers/remoteproc/qcom_q6v5_pas.c
> >> >> >> index db4b3c4bacd7..cf2cd609c90d 100644
> >> >> >> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> >> >> >> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> >> >> >> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
> >> >> >>   return ret;
> >> >> >>  }
> >> >> >>
> >> >> >> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >> >>  {
> >> >> >>   struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
> >> >> >>   int offset;
> >> >> >> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c
> >> >> >> b/drivers/remoteproc/qcom_q6v5_wcss.c
> >> >> >> index f93e1e4a1cc0..3a6b82a16961 100644
> >> >> >> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
> >> >> >> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
> >> >> >> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
> >> >> >>   return 0;
> >> >> >>  }
> >> >> >>
> >> >> >> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >> >>  {
> >> >> >>   struct q6v5_wcss *wcss = rproc->priv;
> >> >> >>   int offset;
> >> >> >> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> >> >> >> index dc135754bb9c..f893219e45a8 100644
> >> >> >> --- a/drivers/remoteproc/qcom_wcnss.c
> >> >> >> +++ b/drivers/remoteproc/qcom_wcnss.c
> >> >> >> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
> >> >> >>   return ret;
> >> >> >>  }
> >> >> >>
> >> >> >> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >> >>  {
> >> >> >>   struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
> >> >> >>   int offset;
> >> >> >> diff --git a/drivers/remoteproc/remoteproc_core.c
> >> >> >> b/drivers/remoteproc/remoteproc_core.c
> >> >> >> index 307df98347ba..9e6d3c6a60ee 100644
> >> >> >> --- a/drivers/remoteproc/remoteproc_core.c
> >> >> >> +++ b/drivers/remoteproc/remoteproc_core.c
> >> >> >> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
> >> >> >>   * here the output of the DMA API for the carveouts, which should be more
> >> >> >>   * correct.
> >> >> >>   */
> >> >> >> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >> >
> >> >> > This function is exported, don't see any update in consequence...
> >> >> > references:
> >> >> > https://elixir.bootlin.com/linux/v5.6-rc1/ident/rproc_da_to_va
> >> >> > For instance the function rproc_trace_read use it. it quite strange that my gcc
> >> >> > does not warns for the cast but i suppose that some could.
> >> >>
> >> >> Agreed, even if len should never have been a signed type since it can't be
> >> >> negative. I will try to fix all callers.
> >> >>
> >> >> > An indirect consequence is that the len field in rproc_mem_entry struct should
> >> >> > probably been updated to u64 to be aligned.
> >> >>
> >> >> Ok, I will do that once we settle on the type of len.
> >> >>
> >> >> >
> >> >> > I'm still wondering about the use of size_t instead,which seems more rational
> >> >> > from my window.
> >> >> > So i you or Mathieu remember it was decided to use u64, please could remind me
> >> >> > the arguments?
> >> >>
> >> >> I tried to find the notes of a meeting we had for OpenAMP but I did not found
> >> >> them. Anyway, the argument was coming from Tomas or someone else, (I can't
> >> >> remember) talking about a 32 bits CPU executing code on a 64 bits accelerator.
> >> >> In that case, the size_t type could fail due to being only 32bits on the host
> >> >> CPU but larger than 4G.
> >> >>
> >> >> However, I can't say if it's a real usecase or not... All I can say is
> >> >> that keeping it open is probably better if one day somebody comes with such
> >> >> architecture.
> >> >
> >> > In order to support a 32bit AP with a 64bit MCU we'd also have to deal with all
> >> > the dma_attr_t in the structure we use.
> >>
> >> Totally ok with that...
> >>
> >> >
> >> > Also something that became very clear to me while thinking about this patchset
> >> > is that supporting elf64 does __not__ mean we support 64bit MCU.  As long as
> >> > the addresses conveyed by the elf64 image fit within 32 bits we are fine.
> >> > Supporting 64bit MCUs is a completely different topic, one that will demand
> >> > serious refactoring.
> >>
> >> Exactly, an elf64 can potentially contain an executable fitting in 32 bits.
> >>
> >> >
> >> > So moving from "int len" to "u64 len" doesn't give us much.  It doesn't hurt to
> >> > do it but if @len ever becomes bigger than 31 bits we'll have other problems to
> >> > deal with.
> >>
> >> Agreed, so what would be your recommendation reagrding the type of len ?
> >> I'm ok with Arnaud statement too and using a size_t is probably more
> >> "type-safe" than a u64. At least it adds some information.
> >
> > If @len becomes big enough that it doesn't fit in 31bit then it is
> > very likely that things will break even before we get to call
> > rproc_da_to_va().  Fixing it here is possible but will introduce a
> > fair amount of ripple effect that we probably don't want to deal with
> > right now.
>
> I did the modification using u64 and tried to follow various code path.
> Some end up in dma_alloc_coherent which uses a size_t member. Since
> these might be called by rproc with a u64 len, I would be more
> inclined to use a size_t. I can probably also add a check in elf loader
> which verifies that if sizeof(size_t) < sizeof(u64), then the len must
> fit in 32bits. This seems more clean IMHO.
>

I'm all good with that.

> Clément.
>
> >
> > Other people might feel more opinionated on this but as far as I'm
> > concerned, I would keep it as it is and fix it for real when the time
> > comes to add support for 64bit MCUs.
> >
> >>
> >> Thanks,
> >>
> >> Clément
> >>
> >> >
> >> >>
> >> >> > As an alternative a check should be added for 32 bits processors to ensure that
> >> >> > the size is not higher than
> >> >> > its address range capability...
> >> >>
> >> >> Agreed.
> >> >> I was even thinking about a mecanism for remoteproc drivers to declare the type
> >> >> of supported elfs files (such as EM_*, ELFCLASS* and other needed thing).
> >> >> Or should it be supported by overriding .sanity_check in drivers  to reject
> >> >> elf64 for instance ?
> >> >>
> >> >> Since elf is a "specific format" and that rproc can support other formats,
> >> >> I did not want to add a specific elf_sanity_check field to rproc ops.
> >> >>
> >> >> Regards,
> >> >>
> >> >> Clément
> >> >>
> >> >> >
> >> >> > Regards
> >> >> > Arnaud
> >> >> >
> >> >> >>  {
> >> >> >>   struct rproc_mem_entry *carveout;
> >> >> >>   void *ptr = NULL;
> >> >> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
> >> >> >> b/drivers/remoteproc/remoteproc_internal.h
> >> >> >> index 493ef9262411..004867061721 100644
> >> >> >> --- a/drivers/remoteproc/remoteproc_internal.h
> >> >> >> +++ b/drivers/remoteproc/remoteproc_internal.h
> >> >> >> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
> >> >> >>  void rproc_free_vring(struct rproc_vring *rvring);
> >> >> >>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
> >> >> >>
> >> >> >> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
> >> >> >> +void *rproc_da_to_va(struct rproc *rproc, u64 da, u64 len);
> >> >> >>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
> >> >> >>  int rproc_trigger_recovery(struct rproc *rproc);
> >> >> >>
> >> >> >> diff --git a/drivers/remoteproc/st_slim_rproc.c
> >> >> >> b/drivers/remoteproc/st_slim_rproc.c
> >> >> >> index 04492fead3c8..fc01cd879b60 100644
> >> >> >> --- a/drivers/remoteproc/st_slim_rproc.c
> >> >> >> +++ b/drivers/remoteproc/st_slim_rproc.c
> >> >> >> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
> >> >> >>   return 0;
> >> >> >>  }
> >> >> >>
> >> >> >> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >> >>  {
> >> >> >>   struct st_slim_rproc *slim_rproc = rproc->priv;
> >> >> >>   void *va = NULL;
> >> >> >> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64
> >> >> >> da, int len)
> >> >> >>           }
> >> >> >>   }
> >> >> >>
> >> >> >> - dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
> >> >> >> + dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%llx va = 0x%pK\n",
> >> >> >>           da, len, va);
> >> >> >>
> >> >> >>   return va;
> >> >> >> diff --git a/drivers/remoteproc/wkup_m3_rproc.c
> >> >> >> b/drivers/remoteproc/wkup_m3_rproc.c
> >> >> >> index 3984e585c847..91485b467407 100644
> >> >> >> --- a/drivers/remoteproc/wkup_m3_rproc.c
> >> >> >> +++ b/drivers/remoteproc/wkup_m3_rproc.c
> >> >> >> @@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
> >> >> >>   return 0;
> >> >> >>  }
> >> >> >>
> >> >> >> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> >> >> >> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, u64 len)
> >> >> >>  {
> >> >> >>   struct wkup_m3_rproc *wkupm3 = rproc->priv;
> >> >> >>   void *va = NULL;
> >> >> >>   int i;
> >> >> >>   u32 offset;
> >> >> >>
> >> >> >> - if (len <= 0)
> >> >> >> + if (len == 0)
> >> >> >>           return NULL;
> >> >> >>
> >> >> >>   for (i = 0; i < WKUPM3_MEM_MAX; i++) {
> >> >> >> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> >> >> >> index 16ad66683ad0..f84bd5fe0211 100644
> >> >> >> --- a/include/linux/remoteproc.h
> >> >> >> +++ b/include/linux/remoteproc.h
> >> >> >> @@ -374,7 +374,7 @@ struct rproc_ops {
> >> >> >>   int (*start)(struct rproc *rproc);
> >> >> >>   int (*stop)(struct rproc *rproc);
> >> >> >>   void (*kick)(struct rproc *rproc, int vqid);
> >> >> >> - void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
> >> >> >> + void * (*da_to_va)(struct rproc *rproc, u64 da, u64 len);
> >> >> >>   int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
> >> >> >>   int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
> > > > > >>                            int offset, int avail);

^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v5 0/8] remoteproc: Add elf64 support
  2020-02-10 16:22                                 ` [PATCH v4 0/5] remoteproc: Add elf64 support Clement Leger
                                                     ` (5 preceding siblings ...)
  2020-02-11 15:57                                   ` [PATCH v4 0/5] remoteproc: Add elf64 support Arnaud POULIQUEN
@ 2020-03-02  9:38                                   ` Clement Leger
  2020-03-02  9:38                                     ` [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va Clement Leger
                                                       ` (7 more replies)
  6 siblings, 8 replies; 76+ messages in thread
From: Clement Leger @ 2020-03-02  9:38 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

This serie add support for elf64 in remoteproc (elf loader, coredump). 
First three patches modifies the type of len argument (in da_to_va),
boot_addr and rproc_mem_entry len field in order to allow loading elf64
segment with a u64 size and a u64 entry point.
Next patches introduce a set of macros to access elf64 and elf32
transparently.
Last patches are the actual modifications in the elf loader and
remoteproc coredump support to add elf64 support.

Changes v4 -> v5:
 - Add rproc_elf_sanity_check renaming to rproc_elf32_sanity_check
 - Fix checkpatch warning on > 80 column line
 - Change u64 len type for size_t in da_to_va and add checks in loader
 - Modify rproc_mem_entry size field type from int to size_t
 - Add a patch to override sanity_check function

Changes v3 -> v4:
 - Adapt coredump to elf64 file format
 - Rename remoteproc_elf_loader.h to remoteproc_elf_helpers.h
 - Update copyright year in remoteproc_elf_helpers.h
 - Rename macros elf_hdr_* to elf_get_hdr_* for coherency with elf_hdr_set_*
 - Split elf64 loader patch in 3:
   - boot_addr u64 change
   - remoteproc_elf_helpers.h creation
   - elf64 loading

Changes v2 -> v3:
 - da_to_va len type changed from int to u64
 - Add check for elf64 header size
 - Add comments for name table parsing
 - Fix typo in "accommodate
 - Add ELF64 support in documentation

Clement Leger (8):
  remoteproc: Use size_t type for len in da_to_va
  remoteproc: Use size_t instead of int for rproc_mem_entry len
  remoteproc: Use u64 type for boot_addr
  remoteproc: Add elf helpers to access elf64 and elf32 fields
  remoteproc: Rename rproc_elf_sanity_check for elf32
  remoteproc: Add elf64 support in elf loader
  remoteproc: Allow overriding only sanity_check
  remoteproc: Adapt coredump to generate correct elf type

 Documentation/remoteproc.txt                |   2 +-
 drivers/remoteproc/imx_rproc.c              |  11 +-
 drivers/remoteproc/keystone_remoteproc.c    |   4 +-
 drivers/remoteproc/qcom_q6v5_adsp.c         |   2 +-
 drivers/remoteproc/qcom_q6v5_mss.c          |   2 +-
 drivers/remoteproc/qcom_q6v5_pas.c          |   2 +-
 drivers/remoteproc/qcom_q6v5_wcss.c         |   2 +-
 drivers/remoteproc/qcom_wcnss.c             |   2 +-
 drivers/remoteproc/remoteproc_core.c        |  86 +++++++------
 drivers/remoteproc/remoteproc_debugfs.c     |   2 +-
 drivers/remoteproc/remoteproc_elf_helpers.h |  96 ++++++++++++++
 drivers/remoteproc/remoteproc_elf_loader.c  | 189 +++++++++++++++++++---------
 drivers/remoteproc/remoteproc_internal.h    |  14 ++-
 drivers/remoteproc/st_remoteproc.c          |   4 +-
 drivers/remoteproc/st_slim_rproc.c          |   6 +-
 drivers/remoteproc/stm32_rproc.c            |   2 +-
 drivers/remoteproc/wkup_m3_rproc.c          |   4 +-
 include/linux/remoteproc.h                  |  13 +-
 18 files changed, 317 insertions(+), 126 deletions(-)
 create mode 100644 drivers/remoteproc/remoteproc_elf_helpers.h

-- 
2.15.0.276.g89ea799


^ permalink raw reply	[flat|nested] 76+ messages in thread

* [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va
  2020-03-02  9:38                                   ` [PATCH v5 0/8] " Clement Leger
@ 2020-03-02  9:38                                     ` Clement Leger
  2020-03-02 23:06                                       ` Bjorn Andersson
                                                         ` (2 more replies)
  2020-03-02  9:38                                     ` [PATCH v5 2/8] remoteproc: Use size_t instead of int for rproc_mem_entry len Clement Leger
                                                       ` (6 subsequent siblings)
  7 siblings, 3 replies; 76+ messages in thread
From: Clement Leger @ 2020-03-02  9:38 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

With upcoming changes in elf loader for elf64 support, section size will
be a u64. When used with da_to_va, this will potentially lead to
overflow if using the current "int" type for len argument. Change
da_to_va prototype to use a size_t for len and fix all users of this
function.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
 drivers/remoteproc/keystone_remoteproc.c |  4 ++--
 drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
 drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
 drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
 drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
 drivers/remoteproc/qcom_wcnss.c          |  2 +-
 drivers/remoteproc/remoteproc_core.c     |  2 +-
 drivers/remoteproc/remoteproc_internal.h |  2 +-
 drivers/remoteproc/st_slim_rproc.c       |  4 ++--
 drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
 include/linux/remoteproc.h               |  2 +-
 12 files changed, 20 insertions(+), 19 deletions(-)

diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
index 3e72b6f38d4b..8957ed271d20 100644
--- a/drivers/remoteproc/imx_rproc.c
+++ b/drivers/remoteproc/imx_rproc.c
@@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
 }
 
 static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
-			       int len, u64 *sys)
+			       size_t len, u64 *sys)
 {
 	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
 	int i;
@@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
 		}
 	}
 
-	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
+	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%zx\n",
 		 da, len);
 	return -ENOENT;
 }
 
-static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
 {
 	struct imx_rproc *priv = rproc->priv;
 	void *va = NULL;
 	u64 sys;
 	int i;
 
-	if (len <= 0)
+	if (len == 0)
 		return NULL;
 
 	/*
@@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 		}
 	}
 
-	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
+	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%p\n",
+		da, len, va);
 
 	return va;
 }
diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
index 5c4658f00b3d..cd266163a65f 100644
--- a/drivers/remoteproc/keystone_remoteproc.c
+++ b/drivers/remoteproc/keystone_remoteproc.c
@@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
  * can be used either by the remoteproc core for loading (when using kernel
  * remoteproc loader), or by any rpmsg bus drivers.
  */
-static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
 {
 	struct keystone_rproc *ksproc = rproc->priv;
 	void __iomem *va = NULL;
@@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 	size_t size;
 	int i;
 
-	if (len <= 0)
+	if (len == 0)
 		return NULL;
 
 	for (i = 0; i < ksproc->num_mems; i++) {
diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
index e953886b2eb7..2b01f2282062 100644
--- a/drivers/remoteproc/qcom_q6v5_adsp.c
+++ b/drivers/remoteproc/qcom_q6v5_adsp.c
@@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len)
 {
 	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index 471128a2e723..3401a17f8ce6 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *q6v5_da_to_va(struct rproc *rproc, u64 da, size_t len)
 {
 	struct q6v5 *qproc = rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
index db4b3c4bacd7..4e89d04673a4 100644
--- a/drivers/remoteproc/qcom_q6v5_pas.c
+++ b/drivers/remoteproc/qcom_q6v5_pas.c
@@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len)
 {
 	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
index f93e1e4a1cc0..f1924b740a10 100644
--- a/drivers/remoteproc/qcom_q6v5_wcss.c
+++ b/drivers/remoteproc/qcom_q6v5_wcss.c
@@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len)
 {
 	struct q6v5_wcss *wcss = rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
index dc135754bb9c..0c7afd038f0d 100644
--- a/drivers/remoteproc/qcom_wcnss.c
+++ b/drivers/remoteproc/qcom_wcnss.c
@@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
 	return ret;
 }
 
-static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *wcnss_da_to_va(struct rproc *rproc, u64 da, size_t len)
 {
 	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
 	int offset;
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 307df98347ba..5ab094fc1b55 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
  * here the output of the DMA API for the carveouts, which should be more
  * correct.
  */
-void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
 {
 	struct rproc_mem_entry *carveout;
 	void *ptr = NULL;
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 493ef9262411..58580210575c 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
 void rproc_free_vring(struct rproc_vring *rvring);
 int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
 
-void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
+void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len);
 phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
index 04492fead3c8..09bcb4d8b9e0 100644
--- a/drivers/remoteproc/st_slim_rproc.c
+++ b/drivers/remoteproc/st_slim_rproc.c
@@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
 {
 	struct st_slim_rproc *slim_rproc = rproc->priv;
 	void *va = NULL;
@@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
 		}
 	}
 
-	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
+	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%pK\n",
 		da, len, va);
 
 	return va;
diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
index 3984e585c847..b9349d684258 100644
--- a/drivers/remoteproc/wkup_m3_rproc.c
+++ b/drivers/remoteproc/wkup_m3_rproc.c
@@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
 	return 0;
 }
 
-static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
 {
 	struct wkup_m3_rproc *wkupm3 = rproc->priv;
 	void *va = NULL;
 	int i;
 	u32 offset;
 
-	if (len <= 0)
+	if (len == 0)
 		return NULL;
 
 	for (i = 0; i < WKUPM3_MEM_MAX; i++) {
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 16ad66683ad0..89215798eaea 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -374,7 +374,7 @@ struct rproc_ops {
 	int (*start)(struct rproc *rproc);
 	int (*stop)(struct rproc *rproc);
 	void (*kick)(struct rproc *rproc, int vqid);
-	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
+	void * (*da_to_va)(struct rproc *rproc, u64 da, size_t len);
 	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
 	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
 			  int offset, int avail);
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v5 2/8] remoteproc: Use size_t instead of int for rproc_mem_entry len
  2020-03-02  9:38                                   ` [PATCH v5 0/8] " Clement Leger
  2020-03-02  9:38                                     ` [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va Clement Leger
@ 2020-03-02  9:38                                     ` Clement Leger
  2020-03-02 23:07                                       ` Bjorn Andersson
  2020-03-09 19:21                                       ` Mathieu Poirier
  2020-03-02  9:38                                     ` [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr Clement Leger
                                                       ` (5 subsequent siblings)
  7 siblings, 2 replies; 76+ messages in thread
From: Clement Leger @ 2020-03-02  9:38 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

Now that rproc_da_to_va uses a size_t for length, use a size_t for len field
of rproc_mem_entry. Function used to create such structures now takes
a size_t instead of int to allow full size range to be handled.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/remoteproc_core.c    | 14 ++++++++------
 drivers/remoteproc/remoteproc_debugfs.c |  2 +-
 include/linux/remoteproc.h              |  6 +++---
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 5ab094fc1b55..4bfaf4a3c4a3 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -318,8 +318,9 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
 	struct device *dev = &rproc->dev;
 	struct rproc_vring *rvring = &rvdev->vring[i];
 	struct fw_rsc_vdev *rsc;
-	int ret, size, notifyid;
+	int ret, notifyid;
 	struct rproc_mem_entry *mem;
+	size_t size;
 
 	/* actual size of vring (in bytes) */
 	size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
@@ -746,11 +747,12 @@ static int rproc_alloc_carveout(struct rproc *rproc,
 	va = dma_alloc_coherent(dev->parent, mem->len, &dma, GFP_KERNEL);
 	if (!va) {
 		dev_err(dev->parent,
-			"failed to allocate dma memory: len 0x%x\n", mem->len);
+			"failed to allocate dma memory: len 0x%zx\n",
+			mem->len);
 		return -ENOMEM;
 	}
 
-	dev_dbg(dev, "carveout va %pK, dma %pad, len 0x%x\n",
+	dev_dbg(dev, "carveout va %pK, dma %pad, len 0x%zx\n",
 		va, &dma, mem->len);
 
 	if (mem->da != FW_RSC_ADDR_ANY && !rproc->domain) {
@@ -957,7 +959,7 @@ EXPORT_SYMBOL(rproc_add_carveout);
  */
 struct rproc_mem_entry *
 rproc_mem_entry_init(struct device *dev,
-		     void *va, dma_addr_t dma, int len, u32 da,
+		     void *va, dma_addr_t dma, size_t len, u32 da,
 		     int (*alloc)(struct rproc *, struct rproc_mem_entry *),
 		     int (*release)(struct rproc *, struct rproc_mem_entry *),
 		     const char *name, ...)
@@ -999,7 +1001,7 @@ EXPORT_SYMBOL(rproc_mem_entry_init);
  * provided by client.
  */
 struct rproc_mem_entry *
-rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, int len,
+rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, size_t len,
 			     u32 da, const char *name, ...)
 {
 	struct rproc_mem_entry *mem;
@@ -1270,7 +1272,7 @@ static void rproc_resource_cleanup(struct rproc *rproc)
 		unmapped = iommu_unmap(rproc->domain, entry->da, entry->len);
 		if (unmapped != entry->len) {
 			/* nothing much to do besides complaining */
-			dev_err(dev, "failed to unmap %u/%zu\n", entry->len,
+			dev_err(dev, "failed to unmap %zx/%zu\n", entry->len,
 				unmapped);
 		}
 
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index dd93cf04e17f..82dc34b819df 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -293,7 +293,7 @@ static int rproc_carveouts_show(struct seq_file *seq, void *p)
 		seq_printf(seq, "\tVirtual address: %pK\n", carveout->va);
 		seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma);
 		seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da);
-		seq_printf(seq, "\tLength: 0x%x Bytes\n\n", carveout->len);
+		seq_printf(seq, "\tLength: 0x%zx Bytes\n\n", carveout->len);
 	}
 
 	return 0;
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 89215798eaea..bee559330204 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -329,7 +329,7 @@ struct rproc;
 struct rproc_mem_entry {
 	void *va;
 	dma_addr_t dma;
-	int len;
+	size_t len;
 	u32 da;
 	void *priv;
 	char name[32];
@@ -599,13 +599,13 @@ void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem);
 
 struct rproc_mem_entry *
 rproc_mem_entry_init(struct device *dev,
-		     void *va, dma_addr_t dma, int len, u32 da,
+		     void *va, dma_addr_t dma, size_t len, u32 da,
 		     int (*alloc)(struct rproc *, struct rproc_mem_entry *),
 		     int (*release)(struct rproc *, struct rproc_mem_entry *),
 		     const char *name, ...);
 
 struct rproc_mem_entry *
-rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, int len,
+rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, size_t len,
 			     u32 da, const char *name, ...);
 
 int rproc_boot(struct rproc *rproc);
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr
  2020-03-02  9:38                                   ` [PATCH v5 0/8] " Clement Leger
  2020-03-02  9:38                                     ` [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va Clement Leger
  2020-03-02  9:38                                     ` [PATCH v5 2/8] remoteproc: Use size_t instead of int for rproc_mem_entry len Clement Leger
@ 2020-03-02  9:38                                     ` Clement Leger
  2020-03-02 23:08                                       ` Bjorn Andersson
  2020-03-09 19:52                                       ` Mathieu Poirier
  2020-03-02  9:38                                     ` [PATCH v5 4/8] remoteproc: Add elf helpers to access elf64 and elf32 fields Clement Leger
                                                       ` (4 subsequent siblings)
  7 siblings, 2 replies; 76+ messages in thread
From: Clement Leger @ 2020-03-02  9:38 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

elf64 entry is defined as a u64. Since boot_addr is used to store the
elf entry point, change boot_addr type to u64 to support both elf32
and elf64. In the same time, fix users that were using this variable.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
 drivers/remoteproc/remoteproc_internal.h   | 2 +-
 drivers/remoteproc/st_remoteproc.c         | 2 +-
 include/linux/remoteproc.h                 | 4 ++--
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 606aae166eba..c2a9783cfb9a 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -102,7 +102,7 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
  * Note that the boot address is not a configurable property of all remote
  * processors. Some will always boot at a specific hard-coded address.
  */
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
 {
 	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
 
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 58580210575c..0deae5f237b8 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
 int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index ee13d23b43a9..a3268d95a50e 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
 		}
 	}
 
-	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
+	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
 
 	return 0;
 
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index bee559330204..1683d6c386a6 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -382,7 +382,7 @@ struct rproc_ops {
 				struct rproc *rproc, const struct firmware *fw);
 	int (*load)(struct rproc *rproc, const struct firmware *fw);
 	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
-	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
+	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
 };
 
 /**
@@ -498,7 +498,7 @@ struct rproc {
 	int num_traces;
 	struct list_head carveouts;
 	struct list_head mappings;
-	u32 bootaddr;
+	u64 bootaddr;
 	struct list_head rvdevs;
 	struct list_head subdevs;
 	struct idr notifyids;
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v5 4/8] remoteproc: Add elf helpers to access elf64 and elf32 fields
  2020-03-02  9:38                                   ` [PATCH v5 0/8] " Clement Leger
                                                       ` (2 preceding siblings ...)
  2020-03-02  9:38                                     ` [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr Clement Leger
@ 2020-03-02  9:38                                     ` Clement Leger
  2020-03-02 23:12                                       ` Bjorn Andersson
  2020-03-09 19:56                                       ` Mathieu Poirier
  2020-03-02  9:38                                     ` [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32 Clement Leger
                                                       ` (3 subsequent siblings)
  7 siblings, 2 replies; 76+ messages in thread
From: Clement Leger @ 2020-03-02  9:38 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

elf32 and elf64 mainly differ by their types. In order to avoid
copy/pasting the whole loader code, generate static inline functions
which will access values according to the elf class. It allows to
keep a common loader basis.
In order to accommodate both elf types sizes, the maximum size for a
elf header member is chosen using the maximum value of the field for
both elf class.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/remoteproc_elf_helpers.h | 96 +++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 drivers/remoteproc/remoteproc_elf_helpers.h

diff --git a/drivers/remoteproc/remoteproc_elf_helpers.h b/drivers/remoteproc/remoteproc_elf_helpers.h
new file mode 100644
index 000000000000..4b6be7b6bf4d
--- /dev/null
+++ b/drivers/remoteproc/remoteproc_elf_helpers.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Remote processor elf helpers defines
+ *
+ * Copyright (C) 2020 Kalray, Inc.
+ */
+
+#ifndef REMOTEPROC_ELF_LOADER_H
+#define REMOTEPROC_ELF_LOADER_H
+
+#include <linux/elf.h>
+#include <linux/types.h>
+
+/**
+ * fw_elf_get_class - Get elf class
+ * @fw: the ELF firmware image
+ *
+ * Note that we use and elf32_hdr to access the class since the start of the
+ * struct is the same for both elf class
+ *
+ * Return: elf class of the firmware
+ */
+static inline u8 fw_elf_get_class(const struct firmware *fw)
+{
+	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
+
+	return ehdr->e_ident[EI_CLASS];
+}
+
+static inline void elf_hdr_init_ident(struct elf32_hdr *hdr, u8 class)
+{
+	memcpy(hdr->e_ident, ELFMAG, SELFMAG);
+	hdr->e_ident[EI_CLASS] = class;
+	hdr->e_ident[EI_DATA] = ELFDATA2LSB;
+	hdr->e_ident[EI_VERSION] = EV_CURRENT;
+	hdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
+}
+
+/* Generate getter and setter for a specific elf struct/field */
+#define ELF_GEN_FIELD_GET_SET(__s, __field, __type) \
+static inline __type elf_##__s##_get_##__field(u8 class, const void *arg) \
+{ \
+	if (class == ELFCLASS32) \
+		return (__type) ((const struct elf32_##__s *) arg)->__field; \
+	else \
+		return (__type) ((const struct elf64_##__s *) arg)->__field; \
+} \
+static inline void elf_##__s##_set_##__field(u8 class, void *arg, \
+					     __type value) \
+{ \
+	if (class == ELFCLASS32) \
+		((struct elf32_##__s *) arg)->__field = (__type) value; \
+	else \
+		((struct elf64_##__s *) arg)->__field = (__type) value; \
+}
+
+ELF_GEN_FIELD_GET_SET(hdr, e_entry, u64)
+ELF_GEN_FIELD_GET_SET(hdr, e_phnum, u16)
+ELF_GEN_FIELD_GET_SET(hdr, e_shnum, u16)
+ELF_GEN_FIELD_GET_SET(hdr, e_phoff, u64)
+ELF_GEN_FIELD_GET_SET(hdr, e_shoff, u64)
+ELF_GEN_FIELD_GET_SET(hdr, e_shstrndx, u16)
+ELF_GEN_FIELD_GET_SET(hdr, e_machine, u16)
+ELF_GEN_FIELD_GET_SET(hdr, e_type, u16)
+ELF_GEN_FIELD_GET_SET(hdr, e_version, u32)
+ELF_GEN_FIELD_GET_SET(hdr, e_ehsize, u32)
+ELF_GEN_FIELD_GET_SET(hdr, e_phentsize, u16)
+
+ELF_GEN_FIELD_GET_SET(phdr, p_paddr, u64)
+ELF_GEN_FIELD_GET_SET(phdr, p_vaddr, u64)
+ELF_GEN_FIELD_GET_SET(phdr, p_filesz, u64)
+ELF_GEN_FIELD_GET_SET(phdr, p_memsz, u64)
+ELF_GEN_FIELD_GET_SET(phdr, p_type, u32)
+ELF_GEN_FIELD_GET_SET(phdr, p_offset, u64)
+ELF_GEN_FIELD_GET_SET(phdr, p_flags, u32)
+ELF_GEN_FIELD_GET_SET(phdr, p_align, u64)
+
+ELF_GEN_FIELD_GET_SET(shdr, sh_size, u64)
+ELF_GEN_FIELD_GET_SET(shdr, sh_offset, u64)
+ELF_GEN_FIELD_GET_SET(shdr, sh_name, u32)
+ELF_GEN_FIELD_GET_SET(shdr, sh_addr, u64)
+
+#define ELF_STRUCT_SIZE(__s) \
+static inline unsigned long elf_size_of_##__s(u8 class) \
+{ \
+	if (class == ELFCLASS32)\
+		return sizeof(struct elf32_##__s); \
+	else \
+		return sizeof(struct elf64_##__s); \
+}
+
+ELF_STRUCT_SIZE(shdr)
+ELF_STRUCT_SIZE(phdr)
+ELF_STRUCT_SIZE(hdr)
+
+#endif /* REMOTEPROC_ELF_LOADER_H */
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32
  2020-03-02  9:38                                   ` [PATCH v5 0/8] " Clement Leger
                                                       ` (3 preceding siblings ...)
  2020-03-02  9:38                                     ` [PATCH v5 4/8] remoteproc: Add elf helpers to access elf64 and elf32 fields Clement Leger
@ 2020-03-02  9:38                                     ` Clement Leger
  2020-03-02 23:13                                       ` Bjorn Andersson
  2020-03-02  9:39                                     ` [PATCH v5 6/8] remoteproc: Add elf64 support in elf loader Clement Leger
                                                       ` (2 subsequent siblings)
  7 siblings, 1 reply; 76+ messages in thread
From: Clement Leger @ 2020-03-02  9:38 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

Since this function will be modified to support both elf32 and elf64,
rename the existing one to elf32 (which is the only supported format
at the moment). This will allow not to introduce possible side effect
when adding elf64 support (ie: all backends will still support only
elf32 if not requested explicitely using rproc_elf_sanity_check).

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/remoteproc_core.c       | 2 +-
 drivers/remoteproc/remoteproc_elf_loader.c | 6 +++---
 drivers/remoteproc/remoteproc_internal.h   | 2 +-
 drivers/remoteproc/st_remoteproc.c         | 2 +-
 drivers/remoteproc/st_slim_rproc.c         | 2 +-
 drivers/remoteproc/stm32_rproc.c           | 2 +-
 6 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 4bfaf4a3c4a3..99f0b796fbc7 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -2055,7 +2055,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
 		rproc->ops->load = rproc_elf_load_segments;
 		rproc->ops->parse_fw = rproc_elf_load_rsc_table;
 		rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table;
-		rproc->ops->sanity_check = rproc_elf_sanity_check;
+		rproc->ops->sanity_check = rproc_elf32_sanity_check;
 		rproc->ops->get_boot_addr = rproc_elf_get_boot_addr;
 	}
 
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index c2a9783cfb9a..5a67745f2638 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -25,13 +25,13 @@
 #include "remoteproc_internal.h"
 
 /**
- * rproc_elf_sanity_check() - Sanity Check ELF firmware image
+ * rproc_elf_sanity_check() - Sanity Check ELF32 firmware image
  * @rproc: the remote processor handle
  * @fw: the ELF firmware image
  *
  * Make sure this fw image is sane.
  */
-int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
+int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw)
 {
 	const char *name = rproc->firmware;
 	struct device *dev = &rproc->dev;
@@ -89,7 +89,7 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 
 	return 0;
 }
-EXPORT_SYMBOL(rproc_elf_sanity_check);
+EXPORT_SYMBOL(rproc_elf32_sanity_check);
 
 /**
  * rproc_elf_get_boot_addr() - Get rproc's boot address.
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 0deae5f237b8..28639c588d58 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -54,7 +54,7 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len);
 phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
-int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
+int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw);
 u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
index a3268d95a50e..a6cbfa452764 100644
--- a/drivers/remoteproc/st_remoteproc.c
+++ b/drivers/remoteproc/st_remoteproc.c
@@ -233,7 +233,7 @@ static const struct rproc_ops st_rproc_ops = {
 	.parse_fw		= st_rproc_parse_fw,
 	.load			= rproc_elf_load_segments,
 	.find_loaded_rsc_table	= rproc_elf_find_loaded_rsc_table,
-	.sanity_check		= rproc_elf_sanity_check,
+	.sanity_check		= rproc_elf32_sanity_check,
 	.get_boot_addr		= rproc_elf_get_boot_addr,
 };
 
diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
index 09bcb4d8b9e0..3cca8b65a8db 100644
--- a/drivers/remoteproc/st_slim_rproc.c
+++ b/drivers/remoteproc/st_slim_rproc.c
@@ -203,7 +203,7 @@ static const struct rproc_ops slim_rproc_ops = {
 	.da_to_va       = slim_rproc_da_to_va,
 	.get_boot_addr	= rproc_elf_get_boot_addr,
 	.load		= rproc_elf_load_segments,
-	.sanity_check	= rproc_elf_sanity_check,
+	.sanity_check	= rproc_elf32_sanity_check,
 };
 
 /**
diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
index a18f88044111..9a8b5f5e2572 100644
--- a/drivers/remoteproc/stm32_rproc.c
+++ b/drivers/remoteproc/stm32_rproc.c
@@ -505,7 +505,7 @@ static struct rproc_ops st_rproc_ops = {
 	.load		= rproc_elf_load_segments,
 	.parse_fw	= stm32_rproc_parse_fw,
 	.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
-	.sanity_check	= rproc_elf_sanity_check,
+	.sanity_check	= rproc_elf32_sanity_check,
 	.get_boot_addr	= rproc_elf_get_boot_addr,
 };
 
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v5 6/8] remoteproc: Add elf64 support in elf loader
  2020-03-02  9:38                                   ` [PATCH v5 0/8] " Clement Leger
                                                       ` (4 preceding siblings ...)
  2020-03-02  9:38                                     ` [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32 Clement Leger
@ 2020-03-02  9:39                                     ` Clement Leger
  2020-03-02  9:39                                     ` [PATCH v5 7/8] remoteproc: Allow overriding only sanity_check Clement Leger
  2020-03-02  9:39                                     ` [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type Clement Leger
  7 siblings, 0 replies; 76+ messages in thread
From: Clement Leger @ 2020-03-02  9:39 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

In order to support elf64, use macros from remoteproc_elf_helpers.h
to access elf headers depending on elf class.
To allow new drivers to support elf64, add rproc_elf_sanity_check
function which make more sense than adding a elf64 named one since
it will support both elf versions.
Driver which need to support both elf32/elf64 should use this new
function for elf sanity check instead of the elf32 one.

Signed-off-by: Clement Leger <cleger@kalray.eu>
Tested-by: Arnaud POULIQUEN <arnaud.pouliquen@st.com>
---
 Documentation/remoteproc.txt               |   2 +-
 drivers/remoteproc/remoteproc_elf_loader.c | 186 ++++++++++++++++++++---------
 drivers/remoteproc/remoteproc_internal.h   |  10 ++
 3 files changed, 141 insertions(+), 57 deletions(-)

diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt
index 03c3d2e568b0..2be1147256e0 100644
--- a/Documentation/remoteproc.txt
+++ b/Documentation/remoteproc.txt
@@ -230,7 +230,7 @@ in the used rings.
 Binary Firmware Structure
 =========================
 
-At this point remoteproc only supports ELF32 firmware binaries. However,
+At this point remoteproc supports ELF32 and ELF64 firmware binaries. However,
 it is quite expected that other platforms/devices which we'd want to
 support with this framework will be based on different binary formats.
 
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 5a67745f2638..4869fb7d8fe4 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -23,20 +23,29 @@
 #include <linux/elf.h>
 
 #include "remoteproc_internal.h"
+#include "remoteproc_elf_helpers.h"
 
 /**
- * rproc_elf_sanity_check() - Sanity Check ELF32 firmware image
+ * rproc_elf_sanity_check() - Sanity Check for ELF32/ELF64 firmware image
  * @rproc: the remote processor handle
  * @fw: the ELF firmware image
  *
- * Make sure this fw image is sane.
+ * Make sure this fw image is sane (ie a correct ELF32/ELF64 file).
  */
-int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw)
+int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
 {
 	const char *name = rproc->firmware;
 	struct device *dev = &rproc->dev;
+	/*
+	 * Elf files are beginning with the same structure. Thus, to simplify
+	 * header parsing, we can use the elf32_hdr one for both elf64 and
+	 * elf32.
+	 */
 	struct elf32_hdr *ehdr;
+	u32 elf_shdr_get_size;
+	u64 phoff, shoff;
 	char class;
+	u16 phnum;
 
 	if (!fw) {
 		dev_err(dev, "failed to load %s\n", name);
@@ -50,13 +59,22 @@ int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw)
 
 	ehdr = (struct elf32_hdr *)fw->data;
 
-	/* We only support ELF32 at this point */
+	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
+		dev_err(dev, "Image is corrupted (bad magic)\n");
+		return -EINVAL;
+	}
+
 	class = ehdr->e_ident[EI_CLASS];
-	if (class != ELFCLASS32) {
+	if (class != ELFCLASS32 && class != ELFCLASS64) {
 		dev_err(dev, "Unsupported class: %d\n", class);
 		return -EINVAL;
 	}
 
+	if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
+		dev_err(dev, "elf64 header is too small\n");
+		return -EINVAL;
+	}
+
 	/* We assume the firmware has the same endianness as the host */
 # ifdef __LITTLE_ENDIAN
 	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
@@ -67,28 +85,52 @@ int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw)
 		return -EINVAL;
 	}
 
-	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
-		dev_err(dev, "Image is too small\n");
-		return -EINVAL;
-	}
+	phoff = elf_hdr_get_e_phoff(class, fw->data);
+	shoff = elf_hdr_get_e_shoff(class, fw->data);
+	phnum =  elf_hdr_get_e_phnum(class, fw->data);
+	elf_shdr_get_size = elf_size_of_shdr(class);
 
-	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
-		dev_err(dev, "Image is corrupted (bad magic)\n");
+	if (fw->size < shoff + elf_shdr_get_size) {
+		dev_err(dev, "Image is too small\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phnum == 0) {
+	if (phnum == 0) {
 		dev_err(dev, "No loadable segments\n");
 		return -EINVAL;
 	}
 
-	if (ehdr->e_phoff > fw->size) {
+	if (phoff > fw->size) {
 		dev_err(dev, "Firmware size is too small\n");
 		return -EINVAL;
 	}
 
+	dev_dbg(dev, "Firmware is an elf%d file\n",
+		class == ELFCLASS32 ? 32 : 64);
+
 	return 0;
 }
+EXPORT_SYMBOL(rproc_elf_sanity_check);
+
+/**
+ * rproc_elf_sanity_check() - Sanity Check ELF32 firmware image
+ * @rproc: the remote processor handle
+ * @fw: the ELF32 firmware image
+ *
+ * Make sure this fw image is sane.
+ */
+int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw)
+{
+	int ret = rproc_elf_sanity_check(rproc, fw);
+
+	if (ret)
+		return ret;
+
+	if (fw_elf_get_class(fw) == ELFCLASS32)
+		return 0;
+
+	return -EINVAL;
+}
 EXPORT_SYMBOL(rproc_elf32_sanity_check);
 
 /**
@@ -104,9 +146,7 @@ EXPORT_SYMBOL(rproc_elf32_sanity_check);
  */
 u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
-
-	return ehdr->e_entry;
+	return elf_hdr_get_e_entry(fw_elf_get_class(fw), fw->data);
 }
 EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 
@@ -137,53 +177,65 @@ EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 {
 	struct device *dev = &rproc->dev;
-	struct elf32_hdr *ehdr;
-	struct elf32_phdr *phdr;
+	const void *ehdr, *phdr;
 	int i, ret = 0;
+	u16 phnum;
 	const u8 *elf_data = fw->data;
+	u8 class = fw_elf_get_class(fw);
+	u32 elf_phdr_get_size = elf_size_of_phdr(class);
 
-	ehdr = (struct elf32_hdr *)elf_data;
-	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+	ehdr = elf_data;
+	phnum = elf_hdr_get_e_phnum(class, ehdr);
+	phdr = elf_data + elf_hdr_get_e_phoff(class, ehdr);
 
 	/* go through the available ELF segments */
-	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
-		u32 da = phdr->p_paddr;
-		u32 memsz = phdr->p_memsz;
-		u32 filesz = phdr->p_filesz;
-		u32 offset = phdr->p_offset;
+	for (i = 0; i < phnum; i++, phdr += elf_phdr_get_size) {
+		u64 da = elf_phdr_get_p_paddr(class, phdr);
+		u64 memsz = elf_phdr_get_p_memsz(class, phdr);
+		u64 filesz = elf_phdr_get_p_filesz(class, phdr);
+		u64 offset = elf_phdr_get_p_offset(class, phdr);
+		u32 type = elf_phdr_get_p_type(class, phdr);
 		void *ptr;
 
-		if (phdr->p_type != PT_LOAD)
+		if (type != PT_LOAD)
 			continue;
 
-		dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
-			phdr->p_type, da, memsz, filesz);
+		dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
+			type, da, memsz, filesz);
 
 		if (filesz > memsz) {
-			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
+			dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
 				filesz, memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		if (offset + filesz > fw->size) {
-			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
+			dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
 				offset + filesz, fw->size);
 			ret = -EINVAL;
 			break;
 		}
 
+		if (!rproc_u64_fit_in_size_t(memsz)) {
+			dev_err(dev, "size (%llx) does not fit in size_t type\n",
+				memsz);
+			ret = -EOVERFLOW;
+			break;
+		}
+
 		/* grab the kernel address for this device address */
 		ptr = rproc_da_to_va(rproc, da, memsz);
 		if (!ptr) {
-			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
+			dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
+				memsz);
 			ret = -EINVAL;
 			break;
 		}
 
 		/* put the segment where the remote processor expects it */
-		if (phdr->p_filesz)
-			memcpy(ptr, elf_data + phdr->p_offset, filesz);
+		if (filesz)
+			memcpy(ptr, elf_data + offset, filesz);
 
 		/*
 		 * Zero out remaining memory for this segment.
@@ -200,24 +252,35 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 }
 EXPORT_SYMBOL(rproc_elf_load_segments);
 
-static struct elf32_shdr *
-find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
+static const void *
+find_table(struct device *dev, const struct firmware *fw)
 {
-	struct elf32_shdr *shdr;
+	const void *shdr, *name_table_shdr;
 	int i;
 	const char *name_table;
 	struct resource_table *table = NULL;
-	const u8 *elf_data = (void *)ehdr;
+	const u8 *elf_data = (void *)fw->data;
+	u8 class = fw_elf_get_class(fw);
+	size_t fw_size = fw->size;
+	const void *ehdr = elf_data;
+	u16 shnum = elf_hdr_get_e_shnum(class, ehdr);
+	u32 elf_shdr_get_size = elf_size_of_shdr(class);
+	u16 shstrndx = elf_hdr_get_e_shstrndx(class, ehdr);
 
 	/* look for the resource table and handle it */
-	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
-	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
-
-	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
-		u32 size = shdr->sh_size;
-		u32 offset = shdr->sh_offset;
-
-		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
+	/* First, get the section header according to the elf class */
+	shdr = elf_data + elf_hdr_get_e_shoff(class, ehdr);
+	/* Compute name table section header entry in shdr array */
+	name_table_shdr = shdr + (shstrndx * elf_shdr_get_size);
+	/* Finally, compute the name table section address in elf */
+	name_table = elf_data + elf_shdr_get_sh_offset(class, name_table_shdr);
+
+	for (i = 0; i < shnum; i++, shdr += elf_shdr_get_size) {
+		u64 size = elf_shdr_get_sh_size(class, shdr);
+		u64 offset = elf_shdr_get_sh_offset(class, shdr);
+		u32 name = elf_shdr_get_sh_name(class, shdr);
+
+		if (strcmp(name_table + name, ".resource_table"))
 			continue;
 
 		table = (struct resource_table *)(elf_data + offset);
@@ -270,21 +333,21 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
  */
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr;
-	struct elf32_shdr *shdr;
+	const void *shdr;
 	struct device *dev = &rproc->dev;
 	struct resource_table *table = NULL;
 	const u8 *elf_data = fw->data;
 	size_t tablesz;
+	u8 class = fw_elf_get_class(fw);
+	u64 sh_offset;
 
-	ehdr = (struct elf32_hdr *)elf_data;
-
-	shdr = find_table(dev, ehdr, fw->size);
+	shdr = find_table(dev, fw);
 	if (!shdr)
 		return -EINVAL;
 
-	table = (struct resource_table *)(elf_data + shdr->sh_offset);
-	tablesz = shdr->sh_size;
+	sh_offset = elf_shdr_get_sh_offset(class, shdr);
+	table = (struct resource_table *)(elf_data + sh_offset);
+	tablesz = elf_shdr_get_sh_size(class, shdr);
 
 	/*
 	 * Create a copy of the resource table. When a virtio device starts
@@ -317,13 +380,24 @@ EXPORT_SYMBOL(rproc_elf_load_rsc_table);
 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 						       const struct firmware *fw)
 {
-	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
-	struct elf32_shdr *shdr;
+	const void *shdr;
+	u64 sh_addr, sh_size;
+	u8 class = fw_elf_get_class(fw);
+	struct device *dev = &rproc->dev;
 
-	shdr = find_table(&rproc->dev, ehdr, fw->size);
+	shdr = find_table(&rproc->dev, fw);
 	if (!shdr)
 		return NULL;
 
-	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
+	sh_addr = elf_shdr_get_sh_addr(class, shdr);
+	sh_size = elf_shdr_get_sh_size(class, shdr);
+
+	if (!rproc_u64_fit_in_size_t(sh_size)) {
+		dev_err(dev, "size (%llx) does not fit in size_t type\n",
+			sh_size);
+		return NULL;
+	}
+
+	return rproc_da_to_va(rproc, sh_addr, sh_size);
 }
 EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index 28639c588d58..10bb7f57d54e 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -55,6 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
 int rproc_trigger_recovery(struct rproc *rproc);
 
 int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw);
+int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
 u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
@@ -119,4 +120,13 @@ struct resource_table *rproc_find_loaded_rsc_table(struct rproc *rproc,
 	return NULL;
 }
 
+static inline
+bool rproc_u64_fit_in_size_t(u64 val)
+{
+	if (sizeof(size_t) == sizeof(u64))
+		return true;
+
+	return (val <= (size_t) -1);
+}
+
 #endif /* REMOTEPROC_INTERNAL_H */
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v5 7/8] remoteproc: Allow overriding only sanity_check
  2020-03-02  9:38                                   ` [PATCH v5 0/8] " Clement Leger
                                                       ` (5 preceding siblings ...)
  2020-03-02  9:39                                     ` [PATCH v5 6/8] remoteproc: Add elf64 support in elf loader Clement Leger
@ 2020-03-02  9:39                                     ` Clement Leger
  2020-03-02  9:39                                     ` [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type Clement Leger
  7 siblings, 0 replies; 76+ messages in thread
From: Clement Leger @ 2020-03-02  9:39 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

Now that rproc_elf_sanity_check can be used by external drivers, allow
to only overwrite the sanity_check member of rproc_ops. This will allow
drivers to handle elf32 and elf64 by overwriting sanity_check with
rproc_elf_sanity_check function.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/remoteproc_core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 99f0b796fbc7..b932a64a2be2 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -2055,7 +2055,8 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
 		rproc->ops->load = rproc_elf_load_segments;
 		rproc->ops->parse_fw = rproc_elf_load_rsc_table;
 		rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table;
-		rproc->ops->sanity_check = rproc_elf32_sanity_check;
+		if (!rproc->ops->sanity_check)
+			rproc->ops->sanity_check = rproc_elf32_sanity_check;
 		rproc->ops->get_boot_addr = rproc_elf_get_boot_addr;
 	}
 
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type
  2020-03-02  9:38                                   ` [PATCH v5 0/8] " Clement Leger
                                                       ` (6 preceding siblings ...)
  2020-03-02  9:39                                     ` [PATCH v5 7/8] remoteproc: Allow overriding only sanity_check Clement Leger
@ 2020-03-02  9:39                                     ` Clement Leger
  2020-03-03 22:01                                       ` Bjorn Andersson
  2020-03-09 20:32                                       ` Mathieu Poirier
  7 siblings, 2 replies; 76+ messages in thread
From: Clement Leger @ 2020-03-02  9:39 UTC (permalink / raw)
  To: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc
  Cc: Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Andy Gross, Patrice Chotard, linux-doc, linux-kernel,
	linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen, Loic PALLARDY,
	s-anna, Mathieu Poirier, Clement Leger

Now that remoteproc can load an elf64, coredump elf class should be
the same as the loaded elf class. In order to do that, add a
elf_class field to rproc with default values. If an elf is loaded
successfully, this field will be updated with the loaded elf class.
Then, the coredump core code has been modified to use the generic elf
macro in order to create an elf file with correct class.

Signed-off-by: Clement Leger <cleger@kalray.eu>
---
 drivers/remoteproc/remoteproc_core.c       | 67 ++++++++++++++++--------------
 drivers/remoteproc/remoteproc_elf_loader.c |  3 ++
 include/linux/remoteproc.h                 |  1 +
 3 files changed, 39 insertions(+), 32 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index b932a64a2be2..f923355aa3f9 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -38,6 +38,7 @@
 #include <linux/platform_device.h>
 
 #include "remoteproc_internal.h"
+#include "remoteproc_elf_helpers.h"
 
 #define HIGH_BITS_MASK 0xFFFFFFFF00000000ULL
 
@@ -1566,20 +1567,21 @@ EXPORT_SYMBOL(rproc_coredump_add_custom_segment);
 static void rproc_coredump(struct rproc *rproc)
 {
 	struct rproc_dump_segment *segment;
-	struct elf32_phdr *phdr;
-	struct elf32_hdr *ehdr;
+	void *phdr;
+	void *ehdr;
 	size_t data_size;
 	size_t offset;
 	void *data;
 	void *ptr;
+	u8 class = rproc->elf_class;
 	int phnum = 0;
 
 	if (list_empty(&rproc->dump_segments))
 		return;
 
-	data_size = sizeof(*ehdr);
+	data_size = elf_size_of_hdr(class);
 	list_for_each_entry(segment, &rproc->dump_segments, node) {
-		data_size += sizeof(*phdr) + segment->size;
+		data_size += elf_size_of_phdr(class) + segment->size;
 
 		phnum++;
 	}
@@ -1590,33 +1592,33 @@ static void rproc_coredump(struct rproc *rproc)
 
 	ehdr = data;
 
-	memset(ehdr, 0, sizeof(*ehdr));
-	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
-	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
-	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
-	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
-	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
-	ehdr->e_type = ET_CORE;
-	ehdr->e_machine = EM_NONE;
-	ehdr->e_version = EV_CURRENT;
-	ehdr->e_entry = rproc->bootaddr;
-	ehdr->e_phoff = sizeof(*ehdr);
-	ehdr->e_ehsize = sizeof(*ehdr);
-	ehdr->e_phentsize = sizeof(*phdr);
-	ehdr->e_phnum = phnum;
-
-	phdr = data + ehdr->e_phoff;
-	offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum;
+	memset(ehdr, 0, elf_size_of_hdr(class));
+	/* e_ident field is common for both elf32 and elf64 */
+	elf_hdr_init_ident(ehdr, class);
+
+	elf_hdr_set_e_type(class, ehdr, ET_CORE);
+	elf_hdr_set_e_machine(class, ehdr, EM_NONE);
+	elf_hdr_set_e_version(class, ehdr, EV_CURRENT);
+	elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr);
+	elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class));
+	elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class));
+	elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class));
+	elf_hdr_set_e_phnum(class, ehdr, phnum);
+
+	phdr = data + elf_hdr_get_e_phoff(class, ehdr);
+	offset = elf_hdr_get_e_phoff(class, ehdr);
+	offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr);
+
 	list_for_each_entry(segment, &rproc->dump_segments, node) {
-		memset(phdr, 0, sizeof(*phdr));
-		phdr->p_type = PT_LOAD;
-		phdr->p_offset = offset;
-		phdr->p_vaddr = segment->da;
-		phdr->p_paddr = segment->da;
-		phdr->p_filesz = segment->size;
-		phdr->p_memsz = segment->size;
-		phdr->p_flags = PF_R | PF_W | PF_X;
-		phdr->p_align = 0;
+		memset(phdr, 0, elf_size_of_phdr(class));
+		elf_phdr_set_p_type(class, phdr, PT_LOAD);
+		elf_phdr_set_p_offset(class, phdr, offset);
+		elf_phdr_set_p_vaddr(class, phdr, segment->da);
+		elf_phdr_set_p_paddr(class, phdr, segment->da);
+		elf_phdr_set_p_filesz(class, phdr, segment->size);
+		elf_phdr_set_p_memsz(class, phdr, segment->size);
+		elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X);
+		elf_phdr_set_p_align(class, phdr, 0);
 
 		if (segment->dump) {
 			segment->dump(rproc, segment, data + offset);
@@ -1632,8 +1634,8 @@ static void rproc_coredump(struct rproc *rproc)
 			}
 		}
 
-		offset += phdr->p_filesz;
-		phdr++;
+		offset += elf_phdr_get_p_filesz(class, phdr);
+		phdr += elf_size_of_phdr(class);
 	}
 
 	dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
@@ -2031,6 +2033,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
 	rproc->name = name;
 	rproc->priv = &rproc[1];
 	rproc->auto_boot = true;
+	rproc->elf_class = ELFCLASS32;
 
 	device_initialize(&rproc->dev);
 	rproc->dev.parent = dev;
diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 4869fb7d8fe4..16e2c496fd45 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -248,6 +248,9 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 			memset(ptr + filesz, 0, memsz - filesz);
 	}
 
+	if (ret == 0)
+		rproc->elf_class = class;
+
 	return ret;
 }
 EXPORT_SYMBOL(rproc_elf_load_segments);
diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
index 1683d6c386a6..ed127b2d35ca 100644
--- a/include/linux/remoteproc.h
+++ b/include/linux/remoteproc.h
@@ -514,6 +514,7 @@ struct rproc {
 	bool auto_boot;
 	struct list_head dump_segments;
 	int nb_vdev;
+	u8 elf_class;
 };
 
 /**
-- 
2.15.0.276.g89ea799


^ permalink raw reply related	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va
  2020-03-02  9:38                                     ` [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va Clement Leger
@ 2020-03-02 23:06                                       ` Bjorn Andersson
  2020-03-09 17:52                                       ` Mathieu Poirier
  2020-03-27  7:37                                       ` Oleksij Rempel
  2 siblings, 0 replies; 76+ messages in thread
From: Bjorn Andersson @ 2020-03-02 23:06 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Jonathan Corbet, Shawn Guo, Sascha Hauer,
	linux-remoteproc, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Andy Gross, Patrice Chotard, linux-doc,
	linux-kernel, linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen,
	Loic PALLARDY, s-anna, Mathieu Poirier

On Mon 02 Mar 01:38 PST 2020, Clement Leger wrote:

> With upcoming changes in elf loader for elf64 support, section size will
> be a u64. When used with da_to_va, this will potentially lead to
> overflow if using the current "int" type for len argument. Change
> da_to_va prototype to use a size_t for len and fix all users of this
> function.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>

Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>

> ---
>  drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
>  drivers/remoteproc/keystone_remoteproc.c |  4 ++--
>  drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
>  drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
>  drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
>  drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
>  drivers/remoteproc/qcom_wcnss.c          |  2 +-
>  drivers/remoteproc/remoteproc_core.c     |  2 +-
>  drivers/remoteproc/remoteproc_internal.h |  2 +-
>  drivers/remoteproc/st_slim_rproc.c       |  4 ++--
>  drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
>  include/linux/remoteproc.h               |  2 +-
>  12 files changed, 20 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 3e72b6f38d4b..8957ed271d20 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
>  }
>  
>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
> -			       int len, u64 *sys)
> +			       size_t len, u64 *sys)
>  {
>  	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
>  	int i;
> @@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
>  		}
>  	}
>  
> -	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
> +	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%zx\n",
>  		 da, len);
>  	return -ENOENT;
>  }
>  
> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct imx_rproc *priv = rproc->priv;
>  	void *va = NULL;
>  	u64 sys;
>  	int i;
>  
> -	if (len <= 0)
> +	if (len == 0)
>  		return NULL;
>  
>  	/*
> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  		}
>  	}
>  
> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%p\n",
> +		da, len, va);
>  
>  	return va;
>  }
> diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
> index 5c4658f00b3d..cd266163a65f 100644
> --- a/drivers/remoteproc/keystone_remoteproc.c
> +++ b/drivers/remoteproc/keystone_remoteproc.c
> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
>   * can be used either by the remoteproc core for loading (when using kernel
>   * remoteproc loader), or by any rpmsg bus drivers.
>   */
> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct keystone_rproc *ksproc = rproc->priv;
>  	void __iomem *va = NULL;
> @@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  	size_t size;
>  	int i;
>  
> -	if (len <= 0)
> +	if (len == 0)
>  		return NULL;
>  
>  	for (i = 0; i < ksproc->num_mems; i++) {
> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
> index e953886b2eb7..2b01f2282062 100644
> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
> index 471128a2e723..3401a17f8ce6 100644
> --- a/drivers/remoteproc/qcom_q6v5_mss.c
> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct q6v5 *qproc = rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
> index db4b3c4bacd7..4e89d04673a4 100644
> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
> index f93e1e4a1cc0..f1924b740a10 100644
> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct q6v5_wcss *wcss = rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> index dc135754bb9c..0c7afd038f0d 100644
> --- a/drivers/remoteproc/qcom_wcnss.c
> +++ b/drivers/remoteproc/qcom_wcnss.c
> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 307df98347ba..5ab094fc1b55 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>   * here the output of the DMA API for the carveouts, which should be more
>   * correct.
>   */
> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct rproc_mem_entry *carveout;
>  	void *ptr = NULL;
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 493ef9262411..58580210575c 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>  void rproc_free_vring(struct rproc_vring *rvring);
>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>  
> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
> +void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len);
>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>  int rproc_trigger_recovery(struct rproc *rproc);
>  
> diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
> index 04492fead3c8..09bcb4d8b9e0 100644
> --- a/drivers/remoteproc/st_slim_rproc.c
> +++ b/drivers/remoteproc/st_slim_rproc.c
> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct st_slim_rproc *slim_rproc = rproc->priv;
>  	void *va = NULL;
> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  		}
>  	}
>  
> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%pK\n",
>  		da, len, va);
>  
>  	return va;
> diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
> index 3984e585c847..b9349d684258 100644
> --- a/drivers/remoteproc/wkup_m3_rproc.c
> +++ b/drivers/remoteproc/wkup_m3_rproc.c
> @@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
>  	void *va = NULL;
>  	int i;
>  	u32 offset;
>  
> -	if (len <= 0)
> +	if (len == 0)
>  		return NULL;
>  
>  	for (i = 0; i < WKUPM3_MEM_MAX; i++) {
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 16ad66683ad0..89215798eaea 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -374,7 +374,7 @@ struct rproc_ops {
>  	int (*start)(struct rproc *rproc);
>  	int (*stop)(struct rproc *rproc);
>  	void (*kick)(struct rproc *rproc, int vqid);
> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
> +	void * (*da_to_va)(struct rproc *rproc, u64 da, size_t len);
>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
>  			  int offset, int avail);
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 2/8] remoteproc: Use size_t instead of int for rproc_mem_entry len
  2020-03-02  9:38                                     ` [PATCH v5 2/8] remoteproc: Use size_t instead of int for rproc_mem_entry len Clement Leger
@ 2020-03-02 23:07                                       ` Bjorn Andersson
  2020-03-09 19:21                                       ` Mathieu Poirier
  1 sibling, 0 replies; 76+ messages in thread
From: Bjorn Andersson @ 2020-03-02 23:07 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Jonathan Corbet, Shawn Guo, Sascha Hauer,
	linux-remoteproc, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Andy Gross, Patrice Chotard, linux-doc,
	linux-kernel, linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen,
	Loic PALLARDY, s-anna, Mathieu Poirier

On Mon 02 Mar 01:38 PST 2020, Clement Leger wrote:

> Now that rproc_da_to_va uses a size_t for length, use a size_t for len field
> of rproc_mem_entry. Function used to create such structures now takes
> a size_t instead of int to allow full size range to be handled.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>

Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>

> ---
>  drivers/remoteproc/remoteproc_core.c    | 14 ++++++++------
>  drivers/remoteproc/remoteproc_debugfs.c |  2 +-
>  include/linux/remoteproc.h              |  6 +++---
>  3 files changed, 12 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 5ab094fc1b55..4bfaf4a3c4a3 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -318,8 +318,9 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
>  	struct device *dev = &rproc->dev;
>  	struct rproc_vring *rvring = &rvdev->vring[i];
>  	struct fw_rsc_vdev *rsc;
> -	int ret, size, notifyid;
> +	int ret, notifyid;
>  	struct rproc_mem_entry *mem;
> +	size_t size;
>  
>  	/* actual size of vring (in bytes) */
>  	size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
> @@ -746,11 +747,12 @@ static int rproc_alloc_carveout(struct rproc *rproc,
>  	va = dma_alloc_coherent(dev->parent, mem->len, &dma, GFP_KERNEL);
>  	if (!va) {
>  		dev_err(dev->parent,
> -			"failed to allocate dma memory: len 0x%x\n", mem->len);
> +			"failed to allocate dma memory: len 0x%zx\n",
> +			mem->len);
>  		return -ENOMEM;
>  	}
>  
> -	dev_dbg(dev, "carveout va %pK, dma %pad, len 0x%x\n",
> +	dev_dbg(dev, "carveout va %pK, dma %pad, len 0x%zx\n",
>  		va, &dma, mem->len);
>  
>  	if (mem->da != FW_RSC_ADDR_ANY && !rproc->domain) {
> @@ -957,7 +959,7 @@ EXPORT_SYMBOL(rproc_add_carveout);
>   */
>  struct rproc_mem_entry *
>  rproc_mem_entry_init(struct device *dev,
> -		     void *va, dma_addr_t dma, int len, u32 da,
> +		     void *va, dma_addr_t dma, size_t len, u32 da,
>  		     int (*alloc)(struct rproc *, struct rproc_mem_entry *),
>  		     int (*release)(struct rproc *, struct rproc_mem_entry *),
>  		     const char *name, ...)
> @@ -999,7 +1001,7 @@ EXPORT_SYMBOL(rproc_mem_entry_init);
>   * provided by client.
>   */
>  struct rproc_mem_entry *
> -rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, int len,
> +rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, size_t len,
>  			     u32 da, const char *name, ...)
>  {
>  	struct rproc_mem_entry *mem;
> @@ -1270,7 +1272,7 @@ static void rproc_resource_cleanup(struct rproc *rproc)
>  		unmapped = iommu_unmap(rproc->domain, entry->da, entry->len);
>  		if (unmapped != entry->len) {
>  			/* nothing much to do besides complaining */
> -			dev_err(dev, "failed to unmap %u/%zu\n", entry->len,
> +			dev_err(dev, "failed to unmap %zx/%zu\n", entry->len,
>  				unmapped);
>  		}
>  
> diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
> index dd93cf04e17f..82dc34b819df 100644
> --- a/drivers/remoteproc/remoteproc_debugfs.c
> +++ b/drivers/remoteproc/remoteproc_debugfs.c
> @@ -293,7 +293,7 @@ static int rproc_carveouts_show(struct seq_file *seq, void *p)
>  		seq_printf(seq, "\tVirtual address: %pK\n", carveout->va);
>  		seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma);
>  		seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da);
> -		seq_printf(seq, "\tLength: 0x%x Bytes\n\n", carveout->len);
> +		seq_printf(seq, "\tLength: 0x%zx Bytes\n\n", carveout->len);
>  	}
>  
>  	return 0;
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 89215798eaea..bee559330204 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -329,7 +329,7 @@ struct rproc;
>  struct rproc_mem_entry {
>  	void *va;
>  	dma_addr_t dma;
> -	int len;
> +	size_t len;
>  	u32 da;
>  	void *priv;
>  	char name[32];
> @@ -599,13 +599,13 @@ void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem);
>  
>  struct rproc_mem_entry *
>  rproc_mem_entry_init(struct device *dev,
> -		     void *va, dma_addr_t dma, int len, u32 da,
> +		     void *va, dma_addr_t dma, size_t len, u32 da,
>  		     int (*alloc)(struct rproc *, struct rproc_mem_entry *),
>  		     int (*release)(struct rproc *, struct rproc_mem_entry *),
>  		     const char *name, ...);
>  
>  struct rproc_mem_entry *
> -rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, int len,
> +rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, size_t len,
>  			     u32 da, const char *name, ...);
>  
>  int rproc_boot(struct rproc *rproc);
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr
  2020-03-02  9:38                                     ` [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr Clement Leger
@ 2020-03-02 23:08                                       ` Bjorn Andersson
  2020-03-09 19:52                                       ` Mathieu Poirier
  1 sibling, 0 replies; 76+ messages in thread
From: Bjorn Andersson @ 2020-03-02 23:08 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Jonathan Corbet, Shawn Guo, Sascha Hauer,
	linux-remoteproc, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Andy Gross, Patrice Chotard, linux-doc,
	linux-kernel, linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen,
	Loic PALLARDY, s-anna, Mathieu Poirier

On Mon 02 Mar 01:38 PST 2020, Clement Leger wrote:

> elf64 entry is defined as a u64. Since boot_addr is used to store the
> elf entry point, change boot_addr type to u64 to support both elf32
> and elf64. In the same time, fix users that were using this variable.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>

Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>

> ---
>  drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
>  drivers/remoteproc/remoteproc_internal.h   | 2 +-
>  drivers/remoteproc/st_remoteproc.c         | 2 +-
>  include/linux/remoteproc.h                 | 4 ++--
>  4 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index 606aae166eba..c2a9783cfb9a 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -102,7 +102,7 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>   * Note that the boot address is not a configurable property of all remote
>   * processors. Some will always boot at a specific hard-coded address.
>   */
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>  {
>  	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
>  
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 58580210575c..0deae5f237b8 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>  int rproc_trigger_recovery(struct rproc *rproc);
>  
>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
> index ee13d23b43a9..a3268d95a50e 100644
> --- a/drivers/remoteproc/st_remoteproc.c
> +++ b/drivers/remoteproc/st_remoteproc.c
> @@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
>  		}
>  	}
>  
> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>  
>  	return 0;
>  
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index bee559330204..1683d6c386a6 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -382,7 +382,7 @@ struct rproc_ops {
>  				struct rproc *rproc, const struct firmware *fw);
>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>  };
>  
>  /**
> @@ -498,7 +498,7 @@ struct rproc {
>  	int num_traces;
>  	struct list_head carveouts;
>  	struct list_head mappings;
> -	u32 bootaddr;
> +	u64 bootaddr;
>  	struct list_head rvdevs;
>  	struct list_head subdevs;
>  	struct idr notifyids;
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 4/8] remoteproc: Add elf helpers to access elf64 and elf32 fields
  2020-03-02  9:38                                     ` [PATCH v5 4/8] remoteproc: Add elf helpers to access elf64 and elf32 fields Clement Leger
@ 2020-03-02 23:12                                       ` Bjorn Andersson
  2020-03-09 19:56                                       ` Mathieu Poirier
  1 sibling, 0 replies; 76+ messages in thread
From: Bjorn Andersson @ 2020-03-02 23:12 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Jonathan Corbet, Shawn Guo, Sascha Hauer,
	linux-remoteproc, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Andy Gross, Patrice Chotard, linux-doc,
	linux-kernel, linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen,
	Loic PALLARDY, s-anna, Mathieu Poirier

On Mon 02 Mar 01:38 PST 2020, Clement Leger wrote:

> elf32 and elf64 mainly differ by their types. In order to avoid
> copy/pasting the whole loader code, generate static inline functions
> which will access values according to the elf class. It allows to
> keep a common loader basis.
> In order to accommodate both elf types sizes, the maximum size for a
> elf header member is chosen using the maximum value of the field for
> both elf class.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>

Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>

> ---
>  drivers/remoteproc/remoteproc_elf_helpers.h | 96 +++++++++++++++++++++++++++++
>  1 file changed, 96 insertions(+)
>  create mode 100644 drivers/remoteproc/remoteproc_elf_helpers.h
> 
> diff --git a/drivers/remoteproc/remoteproc_elf_helpers.h b/drivers/remoteproc/remoteproc_elf_helpers.h
> new file mode 100644
> index 000000000000..4b6be7b6bf4d
> --- /dev/null
> +++ b/drivers/remoteproc/remoteproc_elf_helpers.h
> @@ -0,0 +1,96 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Remote processor elf helpers defines
> + *
> + * Copyright (C) 2020 Kalray, Inc.
> + */
> +
> +#ifndef REMOTEPROC_ELF_LOADER_H
> +#define REMOTEPROC_ELF_LOADER_H
> +
> +#include <linux/elf.h>
> +#include <linux/types.h>
> +
> +/**
> + * fw_elf_get_class - Get elf class
> + * @fw: the ELF firmware image
> + *
> + * Note that we use and elf32_hdr to access the class since the start of the
> + * struct is the same for both elf class
> + *
> + * Return: elf class of the firmware
> + */
> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> +{
> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> +
> +	return ehdr->e_ident[EI_CLASS];
> +}
> +
> +static inline void elf_hdr_init_ident(struct elf32_hdr *hdr, u8 class)
> +{
> +	memcpy(hdr->e_ident, ELFMAG, SELFMAG);
> +	hdr->e_ident[EI_CLASS] = class;
> +	hdr->e_ident[EI_DATA] = ELFDATA2LSB;
> +	hdr->e_ident[EI_VERSION] = EV_CURRENT;
> +	hdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
> +}
> +
> +/* Generate getter and setter for a specific elf struct/field */
> +#define ELF_GEN_FIELD_GET_SET(__s, __field, __type) \
> +static inline __type elf_##__s##_get_##__field(u8 class, const void *arg) \
> +{ \
> +	if (class == ELFCLASS32) \
> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
> +	else \
> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
> +} \
> +static inline void elf_##__s##_set_##__field(u8 class, void *arg, \
> +					     __type value) \
> +{ \
> +	if (class == ELFCLASS32) \
> +		((struct elf32_##__s *) arg)->__field = (__type) value; \
> +	else \
> +		((struct elf64_##__s *) arg)->__field = (__type) value; \
> +}
> +
> +ELF_GEN_FIELD_GET_SET(hdr, e_entry, u64)
> +ELF_GEN_FIELD_GET_SET(hdr, e_phnum, u16)
> +ELF_GEN_FIELD_GET_SET(hdr, e_shnum, u16)
> +ELF_GEN_FIELD_GET_SET(hdr, e_phoff, u64)
> +ELF_GEN_FIELD_GET_SET(hdr, e_shoff, u64)
> +ELF_GEN_FIELD_GET_SET(hdr, e_shstrndx, u16)
> +ELF_GEN_FIELD_GET_SET(hdr, e_machine, u16)
> +ELF_GEN_FIELD_GET_SET(hdr, e_type, u16)
> +ELF_GEN_FIELD_GET_SET(hdr, e_version, u32)
> +ELF_GEN_FIELD_GET_SET(hdr, e_ehsize, u32)
> +ELF_GEN_FIELD_GET_SET(hdr, e_phentsize, u16)
> +
> +ELF_GEN_FIELD_GET_SET(phdr, p_paddr, u64)
> +ELF_GEN_FIELD_GET_SET(phdr, p_vaddr, u64)
> +ELF_GEN_FIELD_GET_SET(phdr, p_filesz, u64)
> +ELF_GEN_FIELD_GET_SET(phdr, p_memsz, u64)
> +ELF_GEN_FIELD_GET_SET(phdr, p_type, u32)
> +ELF_GEN_FIELD_GET_SET(phdr, p_offset, u64)
> +ELF_GEN_FIELD_GET_SET(phdr, p_flags, u32)
> +ELF_GEN_FIELD_GET_SET(phdr, p_align, u64)
> +
> +ELF_GEN_FIELD_GET_SET(shdr, sh_size, u64)
> +ELF_GEN_FIELD_GET_SET(shdr, sh_offset, u64)
> +ELF_GEN_FIELD_GET_SET(shdr, sh_name, u32)
> +ELF_GEN_FIELD_GET_SET(shdr, sh_addr, u64)
> +
> +#define ELF_STRUCT_SIZE(__s) \
> +static inline unsigned long elf_size_of_##__s(u8 class) \
> +{ \
> +	if (class == ELFCLASS32)\
> +		return sizeof(struct elf32_##__s); \
> +	else \
> +		return sizeof(struct elf64_##__s); \
> +}
> +
> +ELF_STRUCT_SIZE(shdr)
> +ELF_STRUCT_SIZE(phdr)
> +ELF_STRUCT_SIZE(hdr)
> +
> +#endif /* REMOTEPROC_ELF_LOADER_H */
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32
  2020-03-02  9:38                                     ` [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32 Clement Leger
@ 2020-03-02 23:13                                       ` Bjorn Andersson
  2020-03-03  8:02                                         ` Clément Leger
  0 siblings, 1 reply; 76+ messages in thread
From: Bjorn Andersson @ 2020-03-02 23:13 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Jonathan Corbet, Shawn Guo, Sascha Hauer,
	linux-remoteproc, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Andy Gross, Patrice Chotard, linux-doc,
	linux-kernel, linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen,
	Loic PALLARDY, s-anna, Mathieu Poirier

On Mon 02 Mar 01:38 PST 2020, Clement Leger wrote:

> Since this function will be modified to support both elf32 and elf64,
> rename the existing one to elf32 (which is the only supported format
> at the moment). This will allow not to introduce possible side effect
> when adding elf64 support (ie: all backends will still support only
> elf32 if not requested explicitely using rproc_elf_sanity_check).
> 

Is there a reason for preventing ELF64 binaries be loaded?

Regards,
Bjorn

> Signed-off-by: Clement Leger <cleger@kalray.eu>
> ---
>  drivers/remoteproc/remoteproc_core.c       | 2 +-
>  drivers/remoteproc/remoteproc_elf_loader.c | 6 +++---
>  drivers/remoteproc/remoteproc_internal.h   | 2 +-
>  drivers/remoteproc/st_remoteproc.c         | 2 +-
>  drivers/remoteproc/st_slim_rproc.c         | 2 +-
>  drivers/remoteproc/stm32_rproc.c           | 2 +-
>  6 files changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 4bfaf4a3c4a3..99f0b796fbc7 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -2055,7 +2055,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
>  		rproc->ops->load = rproc_elf_load_segments;
>  		rproc->ops->parse_fw = rproc_elf_load_rsc_table;
>  		rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table;
> -		rproc->ops->sanity_check = rproc_elf_sanity_check;
> +		rproc->ops->sanity_check = rproc_elf32_sanity_check;
>  		rproc->ops->get_boot_addr = rproc_elf_get_boot_addr;
>  	}
>  
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index c2a9783cfb9a..5a67745f2638 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -25,13 +25,13 @@
>  #include "remoteproc_internal.h"
>  
>  /**
> - * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> + * rproc_elf_sanity_check() - Sanity Check ELF32 firmware image
>   * @rproc: the remote processor handle
>   * @fw: the ELF firmware image
>   *
>   * Make sure this fw image is sane.
>   */
> -int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
> +int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw)
>  {
>  	const char *name = rproc->firmware;
>  	struct device *dev = &rproc->dev;
> @@ -89,7 +89,7 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
>  
>  	return 0;
>  }
> -EXPORT_SYMBOL(rproc_elf_sanity_check);
> +EXPORT_SYMBOL(rproc_elf32_sanity_check);
>  
>  /**
>   * rproc_elf_get_boot_addr() - Get rproc's boot address.
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 0deae5f237b8..28639c588d58 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -54,7 +54,7 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len);
>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>  int rproc_trigger_recovery(struct rproc *rproc);
>  
> -int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> +int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw);
>  u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
> diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
> index a3268d95a50e..a6cbfa452764 100644
> --- a/drivers/remoteproc/st_remoteproc.c
> +++ b/drivers/remoteproc/st_remoteproc.c
> @@ -233,7 +233,7 @@ static const struct rproc_ops st_rproc_ops = {
>  	.parse_fw		= st_rproc_parse_fw,
>  	.load			= rproc_elf_load_segments,
>  	.find_loaded_rsc_table	= rproc_elf_find_loaded_rsc_table,
> -	.sanity_check		= rproc_elf_sanity_check,
> +	.sanity_check		= rproc_elf32_sanity_check,
>  	.get_boot_addr		= rproc_elf_get_boot_addr,
>  };
>  
> diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
> index 09bcb4d8b9e0..3cca8b65a8db 100644
> --- a/drivers/remoteproc/st_slim_rproc.c
> +++ b/drivers/remoteproc/st_slim_rproc.c
> @@ -203,7 +203,7 @@ static const struct rproc_ops slim_rproc_ops = {
>  	.da_to_va       = slim_rproc_da_to_va,
>  	.get_boot_addr	= rproc_elf_get_boot_addr,
>  	.load		= rproc_elf_load_segments,
> -	.sanity_check	= rproc_elf_sanity_check,
> +	.sanity_check	= rproc_elf32_sanity_check,
>  };
>  
>  /**
> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
> index a18f88044111..9a8b5f5e2572 100644
> --- a/drivers/remoteproc/stm32_rproc.c
> +++ b/drivers/remoteproc/stm32_rproc.c
> @@ -505,7 +505,7 @@ static struct rproc_ops st_rproc_ops = {
>  	.load		= rproc_elf_load_segments,
>  	.parse_fw	= stm32_rproc_parse_fw,
>  	.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
> -	.sanity_check	= rproc_elf_sanity_check,
> +	.sanity_check	= rproc_elf32_sanity_check,
>  	.get_boot_addr	= rproc_elf_get_boot_addr,
>  };
>  
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32
  2020-03-02 23:13                                       ` Bjorn Andersson
@ 2020-03-03  8:02                                         ` Clément Leger
  2020-03-10  0:00                                           ` Bjorn Andersson
  0 siblings, 1 reply; 76+ messages in thread
From: Clément Leger @ 2020-03-03  8:02 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: Ohad Ben-Cohen, Jonathan Corbet, Shawn Guo, Sascha Hauer,
	linux-remoteproc, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Andy Gross, Patrice Chotard, linux-doc,
	linux-kernel, linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen,
	Loic PALLARDY, s-anna, Mathieu Poirier

Hi Bjorn, 

----- On 3 Mar, 2020, at 00:13, Bjorn Andersson bjorn.andersson@linaro.org wrote:

> On Mon 02 Mar 01:38 PST 2020, Clement Leger wrote:
> 
>> Since this function will be modified to support both elf32 and elf64,
>> rename the existing one to elf32 (which is the only supported format
>> at the moment). This will allow not to introduce possible side effect
>> when adding elf64 support (ie: all backends will still support only
>> elf32 if not requested explicitely using rproc_elf_sanity_check).
>> 
> 
> Is there a reason for preventing ELF64 binaries be loaded?

I decided to go this way to let driver maintainer decide if they want
to support elf64 to avoid problems with 64bits addresses/sizes which do
not fit in their native type (size_t for instance). This is probably
not going to happen and there are additionnal checks before calling
rproc_da_to_va. And addresses should be filtered by rproc_da_to_va.
So, actually it seems there is no reason to forbid supporting elf32/64
for all drivers.

Regards,

Clément

> 
> Regards,
> Bjorn
> 
>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> ---
>>  drivers/remoteproc/remoteproc_core.c       | 2 +-
>>  drivers/remoteproc/remoteproc_elf_loader.c | 6 +++---
>>  drivers/remoteproc/remoteproc_internal.h   | 2 +-
>>  drivers/remoteproc/st_remoteproc.c         | 2 +-
>>  drivers/remoteproc/st_slim_rproc.c         | 2 +-
>>  drivers/remoteproc/stm32_rproc.c           | 2 +-
>>  6 files changed, 8 insertions(+), 8 deletions(-)
>> 
>> diff --git a/drivers/remoteproc/remoteproc_core.c
>> b/drivers/remoteproc/remoteproc_core.c
>> index 4bfaf4a3c4a3..99f0b796fbc7 100644
>> --- a/drivers/remoteproc/remoteproc_core.c
>> +++ b/drivers/remoteproc/remoteproc_core.c
>> @@ -2055,7 +2055,7 @@ struct rproc *rproc_alloc(struct device *dev, const char
>> *name,
>>  		rproc->ops->load = rproc_elf_load_segments;
>>  		rproc->ops->parse_fw = rproc_elf_load_rsc_table;
>>  		rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table;
>> -		rproc->ops->sanity_check = rproc_elf_sanity_check;
>> +		rproc->ops->sanity_check = rproc_elf32_sanity_check;
>>  		rproc->ops->get_boot_addr = rproc_elf_get_boot_addr;
>>  	}
>>  
>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
>> b/drivers/remoteproc/remoteproc_elf_loader.c
>> index c2a9783cfb9a..5a67745f2638 100644
>> --- a/drivers/remoteproc/remoteproc_elf_loader.c
>> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
>> @@ -25,13 +25,13 @@
>>  #include "remoteproc_internal.h"
>>  
>>  /**
>> - * rproc_elf_sanity_check() - Sanity Check ELF firmware image
>> + * rproc_elf_sanity_check() - Sanity Check ELF32 firmware image
>>   * @rproc: the remote processor handle
>>   * @fw: the ELF firmware image
>>   *
>>   * Make sure this fw image is sane.
>>   */
>> -int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
>> +int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw)
>>  {
>>  	const char *name = rproc->firmware;
>>  	struct device *dev = &rproc->dev;
>> @@ -89,7 +89,7 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
>> firmware *fw)
>>  
>>  	return 0;
>>  }
>> -EXPORT_SYMBOL(rproc_elf_sanity_check);
>> +EXPORT_SYMBOL(rproc_elf32_sanity_check);
>>  
>>  /**
>>   * rproc_elf_get_boot_addr() - Get rproc's boot address.
>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> b/drivers/remoteproc/remoteproc_internal.h
>> index 0deae5f237b8..28639c588d58 100644
>> --- a/drivers/remoteproc/remoteproc_internal.h
>> +++ b/drivers/remoteproc/remoteproc_internal.h
>> @@ -54,7 +54,7 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len);
>>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>>  int rproc_trigger_recovery(struct rproc *rproc);
>>  
>> -int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
>> +int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw);
>>  u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>> diff --git a/drivers/remoteproc/st_remoteproc.c
>> b/drivers/remoteproc/st_remoteproc.c
>> index a3268d95a50e..a6cbfa452764 100644
>> --- a/drivers/remoteproc/st_remoteproc.c
>> +++ b/drivers/remoteproc/st_remoteproc.c
>> @@ -233,7 +233,7 @@ static const struct rproc_ops st_rproc_ops = {
>>  	.parse_fw		= st_rproc_parse_fw,
>>  	.load			= rproc_elf_load_segments,
>>  	.find_loaded_rsc_table	= rproc_elf_find_loaded_rsc_table,
>> -	.sanity_check		= rproc_elf_sanity_check,
>> +	.sanity_check		= rproc_elf32_sanity_check,
>>  	.get_boot_addr		= rproc_elf_get_boot_addr,
>>  };
>>  
>> diff --git a/drivers/remoteproc/st_slim_rproc.c
>> b/drivers/remoteproc/st_slim_rproc.c
>> index 09bcb4d8b9e0..3cca8b65a8db 100644
>> --- a/drivers/remoteproc/st_slim_rproc.c
>> +++ b/drivers/remoteproc/st_slim_rproc.c
>> @@ -203,7 +203,7 @@ static const struct rproc_ops slim_rproc_ops = {
>>  	.da_to_va       = slim_rproc_da_to_va,
>>  	.get_boot_addr	= rproc_elf_get_boot_addr,
>>  	.load		= rproc_elf_load_segments,
>> -	.sanity_check	= rproc_elf_sanity_check,
>> +	.sanity_check	= rproc_elf32_sanity_check,
>>  };
>>  
>>  /**
>> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
>> index a18f88044111..9a8b5f5e2572 100644
>> --- a/drivers/remoteproc/stm32_rproc.c
>> +++ b/drivers/remoteproc/stm32_rproc.c
>> @@ -505,7 +505,7 @@ static struct rproc_ops st_rproc_ops = {
>>  	.load		= rproc_elf_load_segments,
>>  	.parse_fw	= stm32_rproc_parse_fw,
>>  	.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
>> -	.sanity_check	= rproc_elf_sanity_check,
>> +	.sanity_check	= rproc_elf32_sanity_check,
>>  	.get_boot_addr	= rproc_elf_get_boot_addr,
>>  };
>>  
>> --
>> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type
  2020-03-02  9:39                                     ` [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type Clement Leger
@ 2020-03-03 22:01                                       ` Bjorn Andersson
  2020-03-09 20:32                                       ` Mathieu Poirier
  1 sibling, 0 replies; 76+ messages in thread
From: Bjorn Andersson @ 2020-03-03 22:01 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Jonathan Corbet, Shawn Guo, Sascha Hauer,
	linux-remoteproc, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Andy Gross, Patrice Chotard, linux-doc,
	linux-kernel, linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen,
	Loic PALLARDY, s-anna, Mathieu Poirier

On Mon 02 Mar 01:39 PST 2020, Clement Leger wrote:

> Now that remoteproc can load an elf64, coredump elf class should be
> the same as the loaded elf class. In order to do that, add a
> elf_class field to rproc with default values. If an elf is loaded
> successfully, this field will be updated with the loaded elf class.
> Then, the coredump core code has been modified to use the generic elf
> macro in order to create an elf file with correct class.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>

Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org>

> ---
>  drivers/remoteproc/remoteproc_core.c       | 67 ++++++++++++++++--------------
>  drivers/remoteproc/remoteproc_elf_loader.c |  3 ++
>  include/linux/remoteproc.h                 |  1 +
>  3 files changed, 39 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index b932a64a2be2..f923355aa3f9 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -38,6 +38,7 @@
>  #include <linux/platform_device.h>
>  
>  #include "remoteproc_internal.h"
> +#include "remoteproc_elf_helpers.h"
>  
>  #define HIGH_BITS_MASK 0xFFFFFFFF00000000ULL
>  
> @@ -1566,20 +1567,21 @@ EXPORT_SYMBOL(rproc_coredump_add_custom_segment);
>  static void rproc_coredump(struct rproc *rproc)
>  {
>  	struct rproc_dump_segment *segment;
> -	struct elf32_phdr *phdr;
> -	struct elf32_hdr *ehdr;
> +	void *phdr;
> +	void *ehdr;
>  	size_t data_size;
>  	size_t offset;
>  	void *data;
>  	void *ptr;
> +	u8 class = rproc->elf_class;
>  	int phnum = 0;
>  
>  	if (list_empty(&rproc->dump_segments))
>  		return;
>  
> -	data_size = sizeof(*ehdr);
> +	data_size = elf_size_of_hdr(class);
>  	list_for_each_entry(segment, &rproc->dump_segments, node) {
> -		data_size += sizeof(*phdr) + segment->size;
> +		data_size += elf_size_of_phdr(class) + segment->size;
>  
>  		phnum++;
>  	}
> @@ -1590,33 +1592,33 @@ static void rproc_coredump(struct rproc *rproc)
>  
>  	ehdr = data;
>  
> -	memset(ehdr, 0, sizeof(*ehdr));
> -	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
> -	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
> -	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
> -	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
> -	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
> -	ehdr->e_type = ET_CORE;
> -	ehdr->e_machine = EM_NONE;
> -	ehdr->e_version = EV_CURRENT;
> -	ehdr->e_entry = rproc->bootaddr;
> -	ehdr->e_phoff = sizeof(*ehdr);
> -	ehdr->e_ehsize = sizeof(*ehdr);
> -	ehdr->e_phentsize = sizeof(*phdr);
> -	ehdr->e_phnum = phnum;
> -
> -	phdr = data + ehdr->e_phoff;
> -	offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum;
> +	memset(ehdr, 0, elf_size_of_hdr(class));
> +	/* e_ident field is common for both elf32 and elf64 */
> +	elf_hdr_init_ident(ehdr, class);
> +
> +	elf_hdr_set_e_type(class, ehdr, ET_CORE);
> +	elf_hdr_set_e_machine(class, ehdr, EM_NONE);
> +	elf_hdr_set_e_version(class, ehdr, EV_CURRENT);
> +	elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr);
> +	elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class));
> +	elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class));
> +	elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class));
> +	elf_hdr_set_e_phnum(class, ehdr, phnum);
> +
> +	phdr = data + elf_hdr_get_e_phoff(class, ehdr);
> +	offset = elf_hdr_get_e_phoff(class, ehdr);
> +	offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr);
> +
>  	list_for_each_entry(segment, &rproc->dump_segments, node) {
> -		memset(phdr, 0, sizeof(*phdr));
> -		phdr->p_type = PT_LOAD;
> -		phdr->p_offset = offset;
> -		phdr->p_vaddr = segment->da;
> -		phdr->p_paddr = segment->da;
> -		phdr->p_filesz = segment->size;
> -		phdr->p_memsz = segment->size;
> -		phdr->p_flags = PF_R | PF_W | PF_X;
> -		phdr->p_align = 0;
> +		memset(phdr, 0, elf_size_of_phdr(class));
> +		elf_phdr_set_p_type(class, phdr, PT_LOAD);
> +		elf_phdr_set_p_offset(class, phdr, offset);
> +		elf_phdr_set_p_vaddr(class, phdr, segment->da);
> +		elf_phdr_set_p_paddr(class, phdr, segment->da);
> +		elf_phdr_set_p_filesz(class, phdr, segment->size);
> +		elf_phdr_set_p_memsz(class, phdr, segment->size);
> +		elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X);
> +		elf_phdr_set_p_align(class, phdr, 0);
>  
>  		if (segment->dump) {
>  			segment->dump(rproc, segment, data + offset);
> @@ -1632,8 +1634,8 @@ static void rproc_coredump(struct rproc *rproc)
>  			}
>  		}
>  
> -		offset += phdr->p_filesz;
> -		phdr++;
> +		offset += elf_phdr_get_p_filesz(class, phdr);
> +		phdr += elf_size_of_phdr(class);
>  	}
>  
>  	dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
> @@ -2031,6 +2033,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
>  	rproc->name = name;
>  	rproc->priv = &rproc[1];
>  	rproc->auto_boot = true;
> +	rproc->elf_class = ELFCLASS32;
>  
>  	device_initialize(&rproc->dev);
>  	rproc->dev.parent = dev;
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index 4869fb7d8fe4..16e2c496fd45 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -248,6 +248,9 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  			memset(ptr + filesz, 0, memsz - filesz);
>  	}
>  
> +	if (ret == 0)
> +		rproc->elf_class = class;
> +
>  	return ret;
>  }
>  EXPORT_SYMBOL(rproc_elf_load_segments);
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 1683d6c386a6..ed127b2d35ca 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -514,6 +514,7 @@ struct rproc {
>  	bool auto_boot;
>  	struct list_head dump_segments;
>  	int nb_vdev;
> +	u8 elf_class;
>  };
>  
>  /**
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va
  2020-03-02  9:38                                     ` [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va Clement Leger
  2020-03-02 23:06                                       ` Bjorn Andersson
@ 2020-03-09 17:52                                       ` Mathieu Poirier
  2020-03-27  7:37                                       ` Oleksij Rempel
  2 siblings, 0 replies; 76+ messages in thread
From: Mathieu Poirier @ 2020-03-09 17:52 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Mon, Mar 02, 2020 at 10:38:55AM +0100, Clement Leger wrote:
> With upcoming changes in elf loader for elf64 support, section size will
> be a u64. When used with da_to_va, this will potentially lead to
> overflow if using the current "int" type for len argument. Change
> da_to_va prototype to use a size_t for len and fix all users of this
> function.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> ---
>  drivers/remoteproc/imx_rproc.c           | 11 ++++++-----
>  drivers/remoteproc/keystone_remoteproc.c |  4 ++--
>  drivers/remoteproc/qcom_q6v5_adsp.c      |  2 +-
>  drivers/remoteproc/qcom_q6v5_mss.c       |  2 +-
>  drivers/remoteproc/qcom_q6v5_pas.c       |  2 +-
>  drivers/remoteproc/qcom_q6v5_wcss.c      |  2 +-
>  drivers/remoteproc/qcom_wcnss.c          |  2 +-
>  drivers/remoteproc/remoteproc_core.c     |  2 +-
>  drivers/remoteproc/remoteproc_internal.h |  2 +-
>  drivers/remoteproc/st_slim_rproc.c       |  4 ++--
>  drivers/remoteproc/wkup_m3_rproc.c       |  4 ++--
>  include/linux/remoteproc.h               |  2 +-
>  12 files changed, 20 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
> index 3e72b6f38d4b..8957ed271d20 100644
> --- a/drivers/remoteproc/imx_rproc.c
> +++ b/drivers/remoteproc/imx_rproc.c
> @@ -186,7 +186,7 @@ static int imx_rproc_stop(struct rproc *rproc)
>  }
>  
>  static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
> -			       int len, u64 *sys)
> +			       size_t len, u64 *sys)
>  {
>  	const struct imx_rproc_dcfg *dcfg = priv->dcfg;
>  	int i;
> @@ -203,19 +203,19 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
>  		}
>  	}
>  
> -	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%x\n",
> +	dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%zx\n",
>  		 da, len);
>  	return -ENOENT;
>  }
>  
> -static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct imx_rproc *priv = rproc->priv;
>  	void *va = NULL;
>  	u64 sys;
>  	int i;
>  
> -	if (len <= 0)
> +	if (len == 0)
>  		return NULL;
>  
>  	/*
> @@ -235,7 +235,8 @@ static void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  		}
>  	}
>  
> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%p\n",
> +		da, len, va);
>  
>  	return va;
>  }
> diff --git a/drivers/remoteproc/keystone_remoteproc.c b/drivers/remoteproc/keystone_remoteproc.c
> index 5c4658f00b3d..cd266163a65f 100644
> --- a/drivers/remoteproc/keystone_remoteproc.c
> +++ b/drivers/remoteproc/keystone_remoteproc.c
> @@ -246,7 +246,7 @@ static void keystone_rproc_kick(struct rproc *rproc, int vqid)
>   * can be used either by the remoteproc core for loading (when using kernel
>   * remoteproc loader), or by any rpmsg bus drivers.
>   */
> -static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct keystone_rproc *ksproc = rproc->priv;
>  	void __iomem *va = NULL;
> @@ -255,7 +255,7 @@ static void *keystone_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  	size_t size;
>  	int i;
>  
> -	if (len <= 0)
> +	if (len == 0)
>  		return NULL;
>  
>  	for (i = 0; i < ksproc->num_mems; i++) {
> diff --git a/drivers/remoteproc/qcom_q6v5_adsp.c b/drivers/remoteproc/qcom_q6v5_adsp.c
> index e953886b2eb7..2b01f2282062 100644
> --- a/drivers/remoteproc/qcom_q6v5_adsp.c
> +++ b/drivers/remoteproc/qcom_q6v5_adsp.c
> @@ -270,7 +270,7 @@ static int adsp_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
> index 471128a2e723..3401a17f8ce6 100644
> --- a/drivers/remoteproc/qcom_q6v5_mss.c
> +++ b/drivers/remoteproc/qcom_q6v5_mss.c
> @@ -1148,7 +1148,7 @@ static int q6v5_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *q6v5_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *q6v5_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct q6v5 *qproc = rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c
> index db4b3c4bacd7..4e89d04673a4 100644
> --- a/drivers/remoteproc/qcom_q6v5_pas.c
> +++ b/drivers/remoteproc/qcom_q6v5_pas.c
> @@ -159,7 +159,7 @@ static int adsp_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *adsp_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *adsp_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c
> index f93e1e4a1cc0..f1924b740a10 100644
> --- a/drivers/remoteproc/qcom_q6v5_wcss.c
> +++ b/drivers/remoteproc/qcom_q6v5_wcss.c
> @@ -406,7 +406,7 @@ static int q6v5_wcss_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct q6v5_wcss *wcss = rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/qcom_wcnss.c b/drivers/remoteproc/qcom_wcnss.c
> index dc135754bb9c..0c7afd038f0d 100644
> --- a/drivers/remoteproc/qcom_wcnss.c
> +++ b/drivers/remoteproc/qcom_wcnss.c
> @@ -287,7 +287,7 @@ static int wcnss_stop(struct rproc *rproc)
>  	return ret;
>  }
>  
> -static void *wcnss_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *wcnss_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv;
>  	int offset;
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 307df98347ba..5ab094fc1b55 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -185,7 +185,7 @@ EXPORT_SYMBOL(rproc_va_to_pa);
>   * here the output of the DMA API for the carveouts, which should be more
>   * correct.
>   */
> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct rproc_mem_entry *carveout;
>  	void *ptr = NULL;
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 493ef9262411..58580210575c 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -50,7 +50,7 @@ void rproc_exit_sysfs(void);
>  void rproc_free_vring(struct rproc_vring *rvring);
>  int rproc_alloc_vring(struct rproc_vdev *rvdev, int i);
>  
> -void *rproc_da_to_va(struct rproc *rproc, u64 da, int len);
> +void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len);
>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
>  int rproc_trigger_recovery(struct rproc *rproc);
>  
> diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
> index 04492fead3c8..09bcb4d8b9e0 100644
> --- a/drivers/remoteproc/st_slim_rproc.c
> +++ b/drivers/remoteproc/st_slim_rproc.c
> @@ -174,7 +174,7 @@ static int slim_rproc_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct st_slim_rproc *slim_rproc = rproc->priv;
>  	void *va = NULL;
> @@ -191,7 +191,7 @@ static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
>  		}
>  	}
>  
> -	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%pK\n",
> +	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%pK\n",
>  		da, len, va);
>  
>  	return va;
> diff --git a/drivers/remoteproc/wkup_m3_rproc.c b/drivers/remoteproc/wkup_m3_rproc.c
> index 3984e585c847..b9349d684258 100644
> --- a/drivers/remoteproc/wkup_m3_rproc.c
> +++ b/drivers/remoteproc/wkup_m3_rproc.c
> @@ -80,14 +80,14 @@ static int wkup_m3_rproc_stop(struct rproc *rproc)
>  	return 0;
>  }
>  
> -static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
> +static void *wkup_m3_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len)
>  {
>  	struct wkup_m3_rproc *wkupm3 = rproc->priv;
>  	void *va = NULL;
>  	int i;
>  	u32 offset;
>  
> -	if (len <= 0)
> +	if (len == 0)
>  		return NULL;
>  
>  	for (i = 0; i < WKUPM3_MEM_MAX; i++) {
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 16ad66683ad0..89215798eaea 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -374,7 +374,7 @@ struct rproc_ops {
>  	int (*start)(struct rproc *rproc);
>  	int (*stop)(struct rproc *rproc);
>  	void (*kick)(struct rproc *rproc, int vqid);
> -	void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
> +	void * (*da_to_va)(struct rproc *rproc, u64 da, size_t len);
>  	int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
>  	int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
>  			  int offset, int avail);
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 2/8] remoteproc: Use size_t instead of int for rproc_mem_entry len
  2020-03-02  9:38                                     ` [PATCH v5 2/8] remoteproc: Use size_t instead of int for rproc_mem_entry len Clement Leger
  2020-03-02 23:07                                       ` Bjorn Andersson
@ 2020-03-09 19:21                                       ` Mathieu Poirier
  1 sibling, 0 replies; 76+ messages in thread
From: Mathieu Poirier @ 2020-03-09 19:21 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Mon, Mar 02, 2020 at 10:38:56AM +0100, Clement Leger wrote:
> Now that rproc_da_to_va uses a size_t for length, use a size_t for len field
> of rproc_mem_entry. Function used to create such structures now takes
> a size_t instead of int to allow full size range to be handled.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>

With the checkpatch warning fixed:

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> ---
>  drivers/remoteproc/remoteproc_core.c    | 14 ++++++++------
>  drivers/remoteproc/remoteproc_debugfs.c |  2 +-
>  include/linux/remoteproc.h              |  6 +++---
>  3 files changed, 12 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index 5ab094fc1b55..4bfaf4a3c4a3 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -318,8 +318,9 @@ int rproc_alloc_vring(struct rproc_vdev *rvdev, int i)
>  	struct device *dev = &rproc->dev;
>  	struct rproc_vring *rvring = &rvdev->vring[i];
>  	struct fw_rsc_vdev *rsc;
> -	int ret, size, notifyid;
> +	int ret, notifyid;
>  	struct rproc_mem_entry *mem;
> +	size_t size;
>  
>  	/* actual size of vring (in bytes) */
>  	size = PAGE_ALIGN(vring_size(rvring->len, rvring->align));
> @@ -746,11 +747,12 @@ static int rproc_alloc_carveout(struct rproc *rproc,
>  	va = dma_alloc_coherent(dev->parent, mem->len, &dma, GFP_KERNEL);
>  	if (!va) {
>  		dev_err(dev->parent,
> -			"failed to allocate dma memory: len 0x%x\n", mem->len);
> +			"failed to allocate dma memory: len 0x%zx\n",
> +			mem->len);
>  		return -ENOMEM;
>  	}
>  
> -	dev_dbg(dev, "carveout va %pK, dma %pad, len 0x%x\n",
> +	dev_dbg(dev, "carveout va %pK, dma %pad, len 0x%zx\n",
>  		va, &dma, mem->len);
>  
>  	if (mem->da != FW_RSC_ADDR_ANY && !rproc->domain) {
> @@ -957,7 +959,7 @@ EXPORT_SYMBOL(rproc_add_carveout);
>   */
>  struct rproc_mem_entry *
>  rproc_mem_entry_init(struct device *dev,
> -		     void *va, dma_addr_t dma, int len, u32 da,
> +		     void *va, dma_addr_t dma, size_t len, u32 da,
>  		     int (*alloc)(struct rproc *, struct rproc_mem_entry *),
>  		     int (*release)(struct rproc *, struct rproc_mem_entry *),
>  		     const char *name, ...)
> @@ -999,7 +1001,7 @@ EXPORT_SYMBOL(rproc_mem_entry_init);
>   * provided by client.
>   */
>  struct rproc_mem_entry *
> -rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, int len,
> +rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, size_t len,
>  			     u32 da, const char *name, ...)
>  {
>  	struct rproc_mem_entry *mem;
> @@ -1270,7 +1272,7 @@ static void rproc_resource_cleanup(struct rproc *rproc)
>  		unmapped = iommu_unmap(rproc->domain, entry->da, entry->len);
>  		if (unmapped != entry->len) {
>  			/* nothing much to do besides complaining */
> -			dev_err(dev, "failed to unmap %u/%zu\n", entry->len,
> +			dev_err(dev, "failed to unmap %zx/%zu\n", entry->len,
>  				unmapped);
>  		}
>  
> diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
> index dd93cf04e17f..82dc34b819df 100644
> --- a/drivers/remoteproc/remoteproc_debugfs.c
> +++ b/drivers/remoteproc/remoteproc_debugfs.c
> @@ -293,7 +293,7 @@ static int rproc_carveouts_show(struct seq_file *seq, void *p)
>  		seq_printf(seq, "\tVirtual address: %pK\n", carveout->va);
>  		seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma);
>  		seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da);
> -		seq_printf(seq, "\tLength: 0x%x Bytes\n\n", carveout->len);
> +		seq_printf(seq, "\tLength: 0x%zx Bytes\n\n", carveout->len);
>  	}
>  
>  	return 0;
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 89215798eaea..bee559330204 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -329,7 +329,7 @@ struct rproc;
>  struct rproc_mem_entry {
>  	void *va;
>  	dma_addr_t dma;
> -	int len;
> +	size_t len;
>  	u32 da;
>  	void *priv;
>  	char name[32];
> @@ -599,13 +599,13 @@ void rproc_add_carveout(struct rproc *rproc, struct rproc_mem_entry *mem);
>  
>  struct rproc_mem_entry *
>  rproc_mem_entry_init(struct device *dev,
> -		     void *va, dma_addr_t dma, int len, u32 da,
> +		     void *va, dma_addr_t dma, size_t len, u32 da,
>  		     int (*alloc)(struct rproc *, struct rproc_mem_entry *),
>  		     int (*release)(struct rproc *, struct rproc_mem_entry *),
>  		     const char *name, ...);
>  
>  struct rproc_mem_entry *
> -rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, int len,
> +rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, size_t len,
>  			     u32 da, const char *name, ...);
>  
>  int rproc_boot(struct rproc *rproc);
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr
  2020-03-02  9:38                                     ` [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr Clement Leger
  2020-03-02 23:08                                       ` Bjorn Andersson
@ 2020-03-09 19:52                                       ` Mathieu Poirier
  2020-03-10  7:59                                         ` Clément Leger
  1 sibling, 1 reply; 76+ messages in thread
From: Mathieu Poirier @ 2020-03-09 19:52 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Mon, Mar 02, 2020 at 10:38:57AM +0100, Clement Leger wrote:
> elf64 entry is defined as a u64. Since boot_addr is used to store the
> elf entry point, change boot_addr type to u64 to support both elf32
> and elf64. In the same time, fix users that were using this variable.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>
> ---
>  drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
>  drivers/remoteproc/remoteproc_internal.h   | 2 +-
>  drivers/remoteproc/st_remoteproc.c         | 2 +-
>  include/linux/remoteproc.h                 | 4 ++--
>  4 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index 606aae166eba..c2a9783cfb9a 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -102,7 +102,7 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>   * Note that the boot address is not a configurable property of all remote
>   * processors. Some will always boot at a specific hard-coded address.
>   */
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>  {
>  	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
>  
> diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
> index 58580210575c..0deae5f237b8 100644
> --- a/drivers/remoteproc/remoteproc_internal.h
> +++ b/drivers/remoteproc/remoteproc_internal.h
> @@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>  int rproc_trigger_recovery(struct rproc *rproc);
>  
>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,

The return type of function rproc_get_boot_addr() should also be changed from
u32 to u64.  Or perhaps this is intentional to make sure rproc->bootaddr never
occupies more than 32bit?

> diff --git a/drivers/remoteproc/st_remoteproc.c b/drivers/remoteproc/st_remoteproc.c
> index ee13d23b43a9..a3268d95a50e 100644
> --- a/drivers/remoteproc/st_remoteproc.c
> +++ b/drivers/remoteproc/st_remoteproc.c
> @@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
>  		}
>  	}
>  
> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>  
>  	return 0;
>  
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index bee559330204..1683d6c386a6 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -382,7 +382,7 @@ struct rproc_ops {
>  				struct rproc *rproc, const struct firmware *fw);
>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>  };
>  
>  /**
> @@ -498,7 +498,7 @@ struct rproc {
>  	int num_traces;
>  	struct list_head carveouts;
>  	struct list_head mappings;
> -	u32 bootaddr;
> +	u64 bootaddr;
>  	struct list_head rvdevs;
>  	struct list_head subdevs;
>  	struct idr notifyids;
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 4/8] remoteproc: Add elf helpers to access elf64 and elf32 fields
  2020-03-02  9:38                                     ` [PATCH v5 4/8] remoteproc: Add elf helpers to access elf64 and elf32 fields Clement Leger
  2020-03-02 23:12                                       ` Bjorn Andersson
@ 2020-03-09 19:56                                       ` Mathieu Poirier
  1 sibling, 0 replies; 76+ messages in thread
From: Mathieu Poirier @ 2020-03-09 19:56 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Mon, Mar 02, 2020 at 10:38:58AM +0100, Clement Leger wrote:
> elf32 and elf64 mainly differ by their types. In order to avoid
> copy/pasting the whole loader code, generate static inline functions
> which will access values according to the elf class. It allows to
> keep a common loader basis.
> In order to accommodate both elf types sizes, the maximum size for a
> elf header member is chosen using the maximum value of the field for
> both elf class.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> ---
>  drivers/remoteproc/remoteproc_elf_helpers.h | 96 +++++++++++++++++++++++++++++
>  1 file changed, 96 insertions(+)
>  create mode 100644 drivers/remoteproc/remoteproc_elf_helpers.h
> 
> diff --git a/drivers/remoteproc/remoteproc_elf_helpers.h b/drivers/remoteproc/remoteproc_elf_helpers.h
> new file mode 100644
> index 000000000000..4b6be7b6bf4d
> --- /dev/null
> +++ b/drivers/remoteproc/remoteproc_elf_helpers.h
> @@ -0,0 +1,96 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Remote processor elf helpers defines
> + *
> + * Copyright (C) 2020 Kalray, Inc.
> + */
> +
> +#ifndef REMOTEPROC_ELF_LOADER_H
> +#define REMOTEPROC_ELF_LOADER_H
> +
> +#include <linux/elf.h>
> +#include <linux/types.h>
> +
> +/**
> + * fw_elf_get_class - Get elf class
> + * @fw: the ELF firmware image
> + *
> + * Note that we use and elf32_hdr to access the class since the start of the
> + * struct is the same for both elf class
> + *
> + * Return: elf class of the firmware
> + */
> +static inline u8 fw_elf_get_class(const struct firmware *fw)
> +{
> +	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> +
> +	return ehdr->e_ident[EI_CLASS];
> +}
> +
> +static inline void elf_hdr_init_ident(struct elf32_hdr *hdr, u8 class)
> +{
> +	memcpy(hdr->e_ident, ELFMAG, SELFMAG);
> +	hdr->e_ident[EI_CLASS] = class;
> +	hdr->e_ident[EI_DATA] = ELFDATA2LSB;
> +	hdr->e_ident[EI_VERSION] = EV_CURRENT;
> +	hdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
> +}
> +
> +/* Generate getter and setter for a specific elf struct/field */
> +#define ELF_GEN_FIELD_GET_SET(__s, __field, __type) \
> +static inline __type elf_##__s##_get_##__field(u8 class, const void *arg) \
> +{ \
> +	if (class == ELFCLASS32) \
> +		return (__type) ((const struct elf32_##__s *) arg)->__field; \
> +	else \
> +		return (__type) ((const struct elf64_##__s *) arg)->__field; \
> +} \
> +static inline void elf_##__s##_set_##__field(u8 class, void *arg, \
> +					     __type value) \
> +{ \
> +	if (class == ELFCLASS32) \
> +		((struct elf32_##__s *) arg)->__field = (__type) value; \
> +	else \
> +		((struct elf64_##__s *) arg)->__field = (__type) value; \
> +}
> +
> +ELF_GEN_FIELD_GET_SET(hdr, e_entry, u64)
> +ELF_GEN_FIELD_GET_SET(hdr, e_phnum, u16)
> +ELF_GEN_FIELD_GET_SET(hdr, e_shnum, u16)
> +ELF_GEN_FIELD_GET_SET(hdr, e_phoff, u64)
> +ELF_GEN_FIELD_GET_SET(hdr, e_shoff, u64)
> +ELF_GEN_FIELD_GET_SET(hdr, e_shstrndx, u16)
> +ELF_GEN_FIELD_GET_SET(hdr, e_machine, u16)
> +ELF_GEN_FIELD_GET_SET(hdr, e_type, u16)
> +ELF_GEN_FIELD_GET_SET(hdr, e_version, u32)
> +ELF_GEN_FIELD_GET_SET(hdr, e_ehsize, u32)
> +ELF_GEN_FIELD_GET_SET(hdr, e_phentsize, u16)
> +
> +ELF_GEN_FIELD_GET_SET(phdr, p_paddr, u64)
> +ELF_GEN_FIELD_GET_SET(phdr, p_vaddr, u64)
> +ELF_GEN_FIELD_GET_SET(phdr, p_filesz, u64)
> +ELF_GEN_FIELD_GET_SET(phdr, p_memsz, u64)
> +ELF_GEN_FIELD_GET_SET(phdr, p_type, u32)
> +ELF_GEN_FIELD_GET_SET(phdr, p_offset, u64)
> +ELF_GEN_FIELD_GET_SET(phdr, p_flags, u32)
> +ELF_GEN_FIELD_GET_SET(phdr, p_align, u64)
> +
> +ELF_GEN_FIELD_GET_SET(shdr, sh_size, u64)
> +ELF_GEN_FIELD_GET_SET(shdr, sh_offset, u64)
> +ELF_GEN_FIELD_GET_SET(shdr, sh_name, u32)
> +ELF_GEN_FIELD_GET_SET(shdr, sh_addr, u64)
> +
> +#define ELF_STRUCT_SIZE(__s) \
> +static inline unsigned long elf_size_of_##__s(u8 class) \
> +{ \
> +	if (class == ELFCLASS32)\
> +		return sizeof(struct elf32_##__s); \
> +	else \
> +		return sizeof(struct elf64_##__s); \
> +}
> +
> +ELF_STRUCT_SIZE(shdr)
> +ELF_STRUCT_SIZE(phdr)
> +ELF_STRUCT_SIZE(hdr)
> +
> +#endif /* REMOTEPROC_ELF_LOADER_H */
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type
  2020-03-02  9:39                                     ` [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type Clement Leger
  2020-03-03 22:01                                       ` Bjorn Andersson
@ 2020-03-09 20:32                                       ` Mathieu Poirier
  2020-03-09 23:57                                         ` Bjorn Andersson
  1 sibling, 1 reply; 76+ messages in thread
From: Mathieu Poirier @ 2020-03-09 20:32 UTC (permalink / raw)
  To: Clement Leger
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Mon, Mar 02, 2020 at 10:39:02AM +0100, Clement Leger wrote:
> Now that remoteproc can load an elf64, coredump elf class should be
> the same as the loaded elf class. In order to do that, add a
> elf_class field to rproc with default values. If an elf is loaded
> successfully, this field will be updated with the loaded elf class.
> Then, the coredump core code has been modified to use the generic elf
> macro in order to create an elf file with correct class.
> 
> Signed-off-by: Clement Leger <cleger@kalray.eu>
> ---
>  drivers/remoteproc/remoteproc_core.c       | 67 ++++++++++++++++--------------
>  drivers/remoteproc/remoteproc_elf_loader.c |  3 ++
>  include/linux/remoteproc.h                 |  1 +
>  3 files changed, 39 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> index b932a64a2be2..f923355aa3f9 100644
> --- a/drivers/remoteproc/remoteproc_core.c
> +++ b/drivers/remoteproc/remoteproc_core.c
> @@ -38,6 +38,7 @@
>  #include <linux/platform_device.h>
>  
>  #include "remoteproc_internal.h"
> +#include "remoteproc_elf_helpers.h"
>  
>  #define HIGH_BITS_MASK 0xFFFFFFFF00000000ULL
>  
> @@ -1566,20 +1567,21 @@ EXPORT_SYMBOL(rproc_coredump_add_custom_segment);
>  static void rproc_coredump(struct rproc *rproc)
>  {
>  	struct rproc_dump_segment *segment;
> -	struct elf32_phdr *phdr;
> -	struct elf32_hdr *ehdr;
> +	void *phdr;
> +	void *ehdr;
>  	size_t data_size;
>  	size_t offset;
>  	void *data;
>  	void *ptr;
> +	u8 class = rproc->elf_class;
>  	int phnum = 0;
>  
>  	if (list_empty(&rproc->dump_segments))
>  		return;
>  
> -	data_size = sizeof(*ehdr);
> +	data_size = elf_size_of_hdr(class);
>  	list_for_each_entry(segment, &rproc->dump_segments, node) {
> -		data_size += sizeof(*phdr) + segment->size;
> +		data_size += elf_size_of_phdr(class) + segment->size;
>  
>  		phnum++;
>  	}
> @@ -1590,33 +1592,33 @@ static void rproc_coredump(struct rproc *rproc)
>  
>  	ehdr = data;
>  
> -	memset(ehdr, 0, sizeof(*ehdr));
> -	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
> -	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
> -	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
> -	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
> -	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
> -	ehdr->e_type = ET_CORE;
> -	ehdr->e_machine = EM_NONE;
> -	ehdr->e_version = EV_CURRENT;
> -	ehdr->e_entry = rproc->bootaddr;
> -	ehdr->e_phoff = sizeof(*ehdr);
> -	ehdr->e_ehsize = sizeof(*ehdr);
> -	ehdr->e_phentsize = sizeof(*phdr);
> -	ehdr->e_phnum = phnum;
> -
> -	phdr = data + ehdr->e_phoff;
> -	offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum;
> +	memset(ehdr, 0, elf_size_of_hdr(class));
> +	/* e_ident field is common for both elf32 and elf64 */
> +	elf_hdr_init_ident(ehdr, class);
> +
> +	elf_hdr_set_e_type(class, ehdr, ET_CORE);
> +	elf_hdr_set_e_machine(class, ehdr, EM_NONE);
> +	elf_hdr_set_e_version(class, ehdr, EV_CURRENT);
> +	elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr);
> +	elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class));
> +	elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class));
> +	elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class));
> +	elf_hdr_set_e_phnum(class, ehdr, phnum);
> +
> +	phdr = data + elf_hdr_get_e_phoff(class, ehdr);
> +	offset = elf_hdr_get_e_phoff(class, ehdr);
> +	offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr);
> +
>  	list_for_each_entry(segment, &rproc->dump_segments, node) {
> -		memset(phdr, 0, sizeof(*phdr));
> -		phdr->p_type = PT_LOAD;
> -		phdr->p_offset = offset;
> -		phdr->p_vaddr = segment->da;
> -		phdr->p_paddr = segment->da;
> -		phdr->p_filesz = segment->size;
> -		phdr->p_memsz = segment->size;
> -		phdr->p_flags = PF_R | PF_W | PF_X;
> -		phdr->p_align = 0;
> +		memset(phdr, 0, elf_size_of_phdr(class));
> +		elf_phdr_set_p_type(class, phdr, PT_LOAD);
> +		elf_phdr_set_p_offset(class, phdr, offset);
> +		elf_phdr_set_p_vaddr(class, phdr, segment->da);
> +		elf_phdr_set_p_paddr(class, phdr, segment->da);
> +		elf_phdr_set_p_filesz(class, phdr, segment->size);
> +		elf_phdr_set_p_memsz(class, phdr, segment->size);
> +		elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X);
> +		elf_phdr_set_p_align(class, phdr, 0);
>  
>  		if (segment->dump) {
>  			segment->dump(rproc, segment, data + offset);
> @@ -1632,8 +1634,8 @@ static void rproc_coredump(struct rproc *rproc)
>  			}
>  		}
>  
> -		offset += phdr->p_filesz;
> -		phdr++;
> +		offset += elf_phdr_get_p_filesz(class, phdr);
> +		phdr += elf_size_of_phdr(class);
>  	}
>  
>  	dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
> @@ -2031,6 +2033,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
>  	rproc->name = name;
>  	rproc->priv = &rproc[1];
>  	rproc->auto_boot = true;
> +	rproc->elf_class = ELFCLASS32;

I would initialise this to ELFCLASSNONE to make sure that if a platform driver
overwrites rproc_elf_load_segments or doesn't provide one, we don't falsely
deduce the elf type.  It goes without saying that if elf_class == ELFCLASSNONE,
a coredump is not generated. 

Unless you think this is a seriously bad idea or Bjorn over rules me,

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

Thanks,
Mathieu

>  
>  	device_initialize(&rproc->dev);
>  	rproc->dev.parent = dev;
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index 4869fb7d8fe4..16e2c496fd45 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -248,6 +248,9 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
>  			memset(ptr + filesz, 0, memsz - filesz);
>  	}
>  
> +	if (ret == 0)
> +		rproc->elf_class = class;
> +
>  	return ret;
>  }
>  EXPORT_SYMBOL(rproc_elf_load_segments);
> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> index 1683d6c386a6..ed127b2d35ca 100644
> --- a/include/linux/remoteproc.h
> +++ b/include/linux/remoteproc.h
> @@ -514,6 +514,7 @@ struct rproc {
>  	bool auto_boot;
>  	struct list_head dump_segments;
>  	int nb_vdev;
> +	u8 elf_class;
>  };
>  
>  /**
> -- 
> 2.15.0.276.g89ea799
> 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type
  2020-03-09 20:32                                       ` Mathieu Poirier
@ 2020-03-09 23:57                                         ` Bjorn Andersson
  2020-03-10  8:12                                           ` Clément Leger
  0 siblings, 1 reply; 76+ messages in thread
From: Bjorn Andersson @ 2020-03-09 23:57 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Clement Leger, Ohad Ben-Cohen, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

On Mon 09 Mar 13:32 PDT 2020, Mathieu Poirier wrote:

> On Mon, Mar 02, 2020 at 10:39:02AM +0100, Clement Leger wrote:
> > Now that remoteproc can load an elf64, coredump elf class should be
> > the same as the loaded elf class. In order to do that, add a
> > elf_class field to rproc with default values. If an elf is loaded
> > successfully, this field will be updated with the loaded elf class.
> > Then, the coredump core code has been modified to use the generic elf
> > macro in order to create an elf file with correct class.
> > 
> > Signed-off-by: Clement Leger <cleger@kalray.eu>
> > ---
> >  drivers/remoteproc/remoteproc_core.c       | 67 ++++++++++++++++--------------
> >  drivers/remoteproc/remoteproc_elf_loader.c |  3 ++
> >  include/linux/remoteproc.h                 |  1 +
> >  3 files changed, 39 insertions(+), 32 deletions(-)
> > 
> > diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
> > index b932a64a2be2..f923355aa3f9 100644
> > --- a/drivers/remoteproc/remoteproc_core.c
> > +++ b/drivers/remoteproc/remoteproc_core.c
> > @@ -38,6 +38,7 @@
> >  #include <linux/platform_device.h>
> >  
> >  #include "remoteproc_internal.h"
> > +#include "remoteproc_elf_helpers.h"
> >  
> >  #define HIGH_BITS_MASK 0xFFFFFFFF00000000ULL
> >  
> > @@ -1566,20 +1567,21 @@ EXPORT_SYMBOL(rproc_coredump_add_custom_segment);
> >  static void rproc_coredump(struct rproc *rproc)
> >  {
> >  	struct rproc_dump_segment *segment;
> > -	struct elf32_phdr *phdr;
> > -	struct elf32_hdr *ehdr;
> > +	void *phdr;
> > +	void *ehdr;
> >  	size_t data_size;
> >  	size_t offset;
> >  	void *data;
> >  	void *ptr;
> > +	u8 class = rproc->elf_class;
> >  	int phnum = 0;
> >  
> >  	if (list_empty(&rproc->dump_segments))
> >  		return;
> >  
> > -	data_size = sizeof(*ehdr);
> > +	data_size = elf_size_of_hdr(class);
> >  	list_for_each_entry(segment, &rproc->dump_segments, node) {
> > -		data_size += sizeof(*phdr) + segment->size;
> > +		data_size += elf_size_of_phdr(class) + segment->size;
> >  
> >  		phnum++;
> >  	}
> > @@ -1590,33 +1592,33 @@ static void rproc_coredump(struct rproc *rproc)
> >  
> >  	ehdr = data;
> >  
> > -	memset(ehdr, 0, sizeof(*ehdr));
> > -	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
> > -	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
> > -	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
> > -	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
> > -	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
> > -	ehdr->e_type = ET_CORE;
> > -	ehdr->e_machine = EM_NONE;
> > -	ehdr->e_version = EV_CURRENT;
> > -	ehdr->e_entry = rproc->bootaddr;
> > -	ehdr->e_phoff = sizeof(*ehdr);
> > -	ehdr->e_ehsize = sizeof(*ehdr);
> > -	ehdr->e_phentsize = sizeof(*phdr);
> > -	ehdr->e_phnum = phnum;
> > -
> > -	phdr = data + ehdr->e_phoff;
> > -	offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum;
> > +	memset(ehdr, 0, elf_size_of_hdr(class));
> > +	/* e_ident field is common for both elf32 and elf64 */
> > +	elf_hdr_init_ident(ehdr, class);
> > +
> > +	elf_hdr_set_e_type(class, ehdr, ET_CORE);
> > +	elf_hdr_set_e_machine(class, ehdr, EM_NONE);
> > +	elf_hdr_set_e_version(class, ehdr, EV_CURRENT);
> > +	elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr);
> > +	elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class));
> > +	elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class));
> > +	elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class));
> > +	elf_hdr_set_e_phnum(class, ehdr, phnum);
> > +
> > +	phdr = data + elf_hdr_get_e_phoff(class, ehdr);
> > +	offset = elf_hdr_get_e_phoff(class, ehdr);
> > +	offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr);
> > +
> >  	list_for_each_entry(segment, &rproc->dump_segments, node) {
> > -		memset(phdr, 0, sizeof(*phdr));
> > -		phdr->p_type = PT_LOAD;
> > -		phdr->p_offset = offset;
> > -		phdr->p_vaddr = segment->da;
> > -		phdr->p_paddr = segment->da;
> > -		phdr->p_filesz = segment->size;
> > -		phdr->p_memsz = segment->size;
> > -		phdr->p_flags = PF_R | PF_W | PF_X;
> > -		phdr->p_align = 0;
> > +		memset(phdr, 0, elf_size_of_phdr(class));
> > +		elf_phdr_set_p_type(class, phdr, PT_LOAD);
> > +		elf_phdr_set_p_offset(class, phdr, offset);
> > +		elf_phdr_set_p_vaddr(class, phdr, segment->da);
> > +		elf_phdr_set_p_paddr(class, phdr, segment->da);
> > +		elf_phdr_set_p_filesz(class, phdr, segment->size);
> > +		elf_phdr_set_p_memsz(class, phdr, segment->size);
> > +		elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X);
> > +		elf_phdr_set_p_align(class, phdr, 0);
> >  
> >  		if (segment->dump) {
> >  			segment->dump(rproc, segment, data + offset);
> > @@ -1632,8 +1634,8 @@ static void rproc_coredump(struct rproc *rproc)
> >  			}
> >  		}
> >  
> > -		offset += phdr->p_filesz;
> > -		phdr++;
> > +		offset += elf_phdr_get_p_filesz(class, phdr);
> > +		phdr += elf_size_of_phdr(class);
> >  	}
> >  
> >  	dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
> > @@ -2031,6 +2033,7 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
> >  	rproc->name = name;
> >  	rproc->priv = &rproc[1];
> >  	rproc->auto_boot = true;
> > +	rproc->elf_class = ELFCLASS32;
> 
> I would initialise this to ELFCLASSNONE to make sure that if a platform driver
> overwrites rproc_elf_load_segments or doesn't provide one, we don't falsely
> deduce the elf type.  It goes without saying that if elf_class == ELFCLASSNONE,
> a coredump is not generated. 
> 

I like the idea of making the choice explicit, perhaps even more
explicit than the assumption that the coredumps should be of the same
type as the ELF loaded. Note that it's different consumers of the two
ELF files.

> Unless you think this is a seriously bad idea or Bjorn over rules me,
> 
> Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
> 

Not sure if it count as "over ruling", I accept your suggestion but used
your R-b to merge the patch as is, no need to hold this up any longer.

Clement, can you please follow up with a patch implementing this (don't
forget that the qcom drivers doesn't use rproc_elf_load_segments())

Thanks Clement and thanks for the reviews Mathieu.

Regards,
Bjorn

> Thanks,
> Mathieu
> 
> >  
> >  	device_initialize(&rproc->dev);
> >  	rproc->dev.parent = dev;
> > diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> > index 4869fb7d8fe4..16e2c496fd45 100644
> > --- a/drivers/remoteproc/remoteproc_elf_loader.c
> > +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> > @@ -248,6 +248,9 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
> >  			memset(ptr + filesz, 0, memsz - filesz);
> >  	}
> >  
> > +	if (ret == 0)
> > +		rproc->elf_class = class;
> > +
> >  	return ret;
> >  }
> >  EXPORT_SYMBOL(rproc_elf_load_segments);
> > diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
> > index 1683d6c386a6..ed127b2d35ca 100644
> > --- a/include/linux/remoteproc.h
> > +++ b/include/linux/remoteproc.h
> > @@ -514,6 +514,7 @@ struct rproc {
> >  	bool auto_boot;
> >  	struct list_head dump_segments;
> >  	int nb_vdev;
> > +	u8 elf_class;
> >  };
> >  
> >  /**
> > -- 
> > 2.15.0.276.g89ea799
> > 

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32
  2020-03-03  8:02                                         ` Clément Leger
@ 2020-03-10  0:00                                           ` Bjorn Andersson
  2020-03-10 15:20                                             ` Mathieu Poirier
  0 siblings, 1 reply; 76+ messages in thread
From: Bjorn Andersson @ 2020-03-10  0:00 UTC (permalink / raw)
  To: Cl?ment Leger
  Cc: Ohad Ben-Cohen, Jonathan Corbet, Shawn Guo, Sascha Hauer,
	linux-remoteproc, Pengutronix Kernel Team, Fabio Estevam,
	NXP Linux Team, Andy Gross, Patrice Chotard, linux-doc,
	linux-kernel, linux-arm-kernel, linux-arm-msm, Arnaud Pouliquen,
	Loic PALLARDY, s-anna, Mathieu Poirier

On Tue 03 Mar 00:02 PST 2020, Cl?ment Leger wrote:

> Hi Bjorn, 
> 
> ----- On 3 Mar, 2020, at 00:13, Bjorn Andersson bjorn.andersson@linaro.org wrote:
> 
> > On Mon 02 Mar 01:38 PST 2020, Clement Leger wrote:
> > 
> >> Since this function will be modified to support both elf32 and elf64,
> >> rename the existing one to elf32 (which is the only supported format
> >> at the moment). This will allow not to introduce possible side effect
> >> when adding elf64 support (ie: all backends will still support only
> >> elf32 if not requested explicitely using rproc_elf_sanity_check).
> >> 
> > 
> > Is there a reason for preventing ELF64 binaries be loaded?
> 
> I decided to go this way to let driver maintainer decide if they want
> to support elf64 to avoid problems with 64bits addresses/sizes which do
> not fit in their native type (size_t for instance). This is probably
> not going to happen and there are additionnal checks before calling
> rproc_da_to_va. And addresses should be filtered by rproc_da_to_va.
> So, actually it seems there is no reason to forbid supporting elf32/64
> for all drivers.
> 

I was hoping to hear some additional feedback on this from others.

I've merge the patch as is, but think it would be nice to clean this up
and just have the driver ignore if fed a 32 or 64-elf.

Regards,
Bjorn

> Regards,
> 
> Clément
> 
> > 
> > Regards,
> > Bjorn
> > 
> >> Signed-off-by: Clement Leger <cleger@kalray.eu>
> >> ---
> >>  drivers/remoteproc/remoteproc_core.c       | 2 +-
> >>  drivers/remoteproc/remoteproc_elf_loader.c | 6 +++---
> >>  drivers/remoteproc/remoteproc_internal.h   | 2 +-
> >>  drivers/remoteproc/st_remoteproc.c         | 2 +-
> >>  drivers/remoteproc/st_slim_rproc.c         | 2 +-
> >>  drivers/remoteproc/stm32_rproc.c           | 2 +-
> >>  6 files changed, 8 insertions(+), 8 deletions(-)
> >> 
> >> diff --git a/drivers/remoteproc/remoteproc_core.c
> >> b/drivers/remoteproc/remoteproc_core.c
> >> index 4bfaf4a3c4a3..99f0b796fbc7 100644
> >> --- a/drivers/remoteproc/remoteproc_core.c
> >> +++ b/drivers/remoteproc/remoteproc_core.c
> >> @@ -2055,7 +2055,7 @@ struct rproc *rproc_alloc(struct device *dev, const char
> >> *name,
> >>  		rproc->ops->load = rproc_elf_load_segments;
> >>  		rproc->ops->parse_fw = rproc_elf_load_rsc_table;
> >>  		rproc->ops->find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table;
> >> -		rproc->ops->sanity_check = rproc_elf_sanity_check;
> >> +		rproc->ops->sanity_check = rproc_elf32_sanity_check;
> >>  		rproc->ops->get_boot_addr = rproc_elf_get_boot_addr;
> >>  	}
> >>  
> >> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
> >> b/drivers/remoteproc/remoteproc_elf_loader.c
> >> index c2a9783cfb9a..5a67745f2638 100644
> >> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> >> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> >> @@ -25,13 +25,13 @@
> >>  #include "remoteproc_internal.h"
> >>  
> >>  /**
> >> - * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> >> + * rproc_elf_sanity_check() - Sanity Check ELF32 firmware image
> >>   * @rproc: the remote processor handle
> >>   * @fw: the ELF firmware image
> >>   *
> >>   * Make sure this fw image is sane.
> >>   */
> >> -int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
> >> +int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw)
> >>  {
> >>  	const char *name = rproc->firmware;
> >>  	struct device *dev = &rproc->dev;
> >> @@ -89,7 +89,7 @@ int rproc_elf_sanity_check(struct rproc *rproc, const struct
> >> firmware *fw)
> >>  
> >>  	return 0;
> >>  }
> >> -EXPORT_SYMBOL(rproc_elf_sanity_check);
> >> +EXPORT_SYMBOL(rproc_elf32_sanity_check);
> >>  
> >>  /**
> >>   * rproc_elf_get_boot_addr() - Get rproc's boot address.
> >> diff --git a/drivers/remoteproc/remoteproc_internal.h
> >> b/drivers/remoteproc/remoteproc_internal.h
> >> index 0deae5f237b8..28639c588d58 100644
> >> --- a/drivers/remoteproc/remoteproc_internal.h
> >> +++ b/drivers/remoteproc/remoteproc_internal.h
> >> @@ -54,7 +54,7 @@ void *rproc_da_to_va(struct rproc *rproc, u64 da, size_t len);
> >>  phys_addr_t rproc_va_to_pa(void *cpu_addr);
> >>  int rproc_trigger_recovery(struct rproc *rproc);
> >>  
> >> -int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
> >> +int rproc_elf32_sanity_check(struct rproc *rproc, const struct firmware *fw);
> >>  u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
> >>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
> >>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
> >> diff --git a/drivers/remoteproc/st_remoteproc.c
> >> b/drivers/remoteproc/st_remoteproc.c
> >> index a3268d95a50e..a6cbfa452764 100644
> >> --- a/drivers/remoteproc/st_remoteproc.c
> >> +++ b/drivers/remoteproc/st_remoteproc.c
> >> @@ -233,7 +233,7 @@ static const struct rproc_ops st_rproc_ops = {
> >>  	.parse_fw		= st_rproc_parse_fw,
> >>  	.load			= rproc_elf_load_segments,
> >>  	.find_loaded_rsc_table	= rproc_elf_find_loaded_rsc_table,
> >> -	.sanity_check		= rproc_elf_sanity_check,
> >> +	.sanity_check		= rproc_elf32_sanity_check,
> >>  	.get_boot_addr		= rproc_elf_get_boot_addr,
> >>  };
> >>  
> >> diff --git a/drivers/remoteproc/st_slim_rproc.c
> >> b/drivers/remoteproc/st_slim_rproc.c
> >> index 09bcb4d8b9e0..3cca8b65a8db 100644
> >> --- a/drivers/remoteproc/st_slim_rproc.c
> >> +++ b/drivers/remoteproc/st_slim_rproc.c
> >> @@ -203,7 +203,7 @@ static const struct rproc_ops slim_rproc_ops = {
> >>  	.da_to_va       = slim_rproc_da_to_va,
> >>  	.get_boot_addr	= rproc_elf_get_boot_addr,
> >>  	.load		= rproc_elf_load_segments,
> >> -	.sanity_check	= rproc_elf_sanity_check,
> >> +	.sanity_check	= rproc_elf32_sanity_check,
> >>  };
> >>  
> >>  /**
> >> diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c
> >> index a18f88044111..9a8b5f5e2572 100644
> >> --- a/drivers/remoteproc/stm32_rproc.c
> >> +++ b/drivers/remoteproc/stm32_rproc.c
> >> @@ -505,7 +505,7 @@ static struct rproc_ops st_rproc_ops = {
> >>  	.load		= rproc_elf_load_segments,
> >>  	.parse_fw	= stm32_rproc_parse_fw,
> >>  	.find_loaded_rsc_table = rproc_elf_find_loaded_rsc_table,
> >> -	.sanity_check	= rproc_elf_sanity_check,
> >> +	.sanity_check	= rproc_elf32_sanity_check,
> >>  	.get_boot_addr	= rproc_elf_get_boot_addr,
> >>  };
> >>  
> >> --
> >> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr
  2020-03-09 19:52                                       ` Mathieu Poirier
@ 2020-03-10  7:59                                         ` Clément Leger
  2020-03-10 19:32                                           ` Bjorn Andersson
  0 siblings, 1 reply; 76+ messages in thread
From: Clément Leger @ 2020-03-10  7:59 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Ohad Ben-Cohen, Bjorn Andersson, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna



----- On 9 Mar, 2020, at 20:52, Mathieu Poirier mathieu.poirier@linaro.org wrote:

> On Mon, Mar 02, 2020 at 10:38:57AM +0100, Clement Leger wrote:
>> elf64 entry is defined as a u64. Since boot_addr is used to store the
>> elf entry point, change boot_addr type to u64 to support both elf32
>> and elf64. In the same time, fix users that were using this variable.
>> 
>> Signed-off-by: Clement Leger <cleger@kalray.eu>
>> ---
>>  drivers/remoteproc/remoteproc_elf_loader.c | 2 +-
>>  drivers/remoteproc/remoteproc_internal.h   | 2 +-
>>  drivers/remoteproc/st_remoteproc.c         | 2 +-
>>  include/linux/remoteproc.h                 | 4 ++--
>>  4 files changed, 5 insertions(+), 5 deletions(-)
>> 
>> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c
>> b/drivers/remoteproc/remoteproc_elf_loader.c
>> index 606aae166eba..c2a9783cfb9a 100644
>> --- a/drivers/remoteproc/remoteproc_elf_loader.c
>> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
>> @@ -102,7 +102,7 @@ EXPORT_SYMBOL(rproc_elf_sanity_check);
>>   * Note that the boot address is not a configurable property of all remote
>>   * processors. Some will always boot at a specific hard-coded address.
>>   */
>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
>>  {
>>  	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
>>  
>> diff --git a/drivers/remoteproc/remoteproc_internal.h
>> b/drivers/remoteproc/remoteproc_internal.h
>> index 58580210575c..0deae5f237b8 100644
>> --- a/drivers/remoteproc/remoteproc_internal.h
>> +++ b/drivers/remoteproc/remoteproc_internal.h
>> @@ -55,7 +55,7 @@ phys_addr_t rproc_va_to_pa(void *cpu_addr);
>>  int rproc_trigger_recovery(struct rproc *rproc);
>>  
>>  int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw);
>> -u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>> +u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw);
>>  int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw);
>>  int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw);
>>  struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> 
> The return type of function rproc_get_boot_addr() should also be changed from
> u32 to u64.  Or perhaps this is intentional to make sure rproc->bootaddr never
> occupies more than 32bit?

No, this is a mistake clearly. I haven't been able to test with a 64 bit
boot address since our remote processors always boot in the 32 bits
space. But since the elf64 boot address is on 64 bitsn this was a logical
modification. I will fix that.

> 
>> diff --git a/drivers/remoteproc/st_remoteproc.c
>> b/drivers/remoteproc/st_remoteproc.c
>> index ee13d23b43a9..a3268d95a50e 100644
>> --- a/drivers/remoteproc/st_remoteproc.c
>> +++ b/drivers/remoteproc/st_remoteproc.c
>> @@ -190,7 +190,7 @@ static int st_rproc_start(struct rproc *rproc)
>>  		}
>>  	}
>>  
>> -	dev_info(&rproc->dev, "Started from 0x%x\n", rproc->bootaddr);
>> +	dev_info(&rproc->dev, "Started from 0x%llx\n", rproc->bootaddr);
>>  
>>  	return 0;
>>  
>> diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h
>> index bee559330204..1683d6c386a6 100644
>> --- a/include/linux/remoteproc.h
>> +++ b/include/linux/remoteproc.h
>> @@ -382,7 +382,7 @@ struct rproc_ops {
>>  				struct rproc *rproc, const struct firmware *fw);
>>  	int (*load)(struct rproc *rproc, const struct firmware *fw);
>>  	int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);
>> -	u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>> +	u64 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);
>>  };
>>  
>>  /**
>> @@ -498,7 +498,7 @@ struct rproc {
>>  	int num_traces;
>>  	struct list_head carveouts;
>>  	struct list_head mappings;
>> -	u32 bootaddr;
>> +	u64 bootaddr;
>>  	struct list_head rvdevs;
>>  	struct list_head subdevs;
>>  	struct idr notifyids;
>> --
>> 2.15.0.276.g89ea799

^ permalink raw reply	[flat|nested] 76+ messages in thread

* Re: [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type
  2020-03-09 23:57                                         ` Bjorn Andersson
@ 2020-03-10  8:12                                           ` Clément Leger
  0 siblings, 0 replies; 76+ messages in thread
From: Clément Leger @ 2020-03-10  8:12 UTC (permalink / raw)
  To: Bjorn Andersson
  Cc: Mathieu Poirier, Ohad Ben-Cohen, Jonathan Corbet, Shawn Guo,
	Sascha Hauer, linux-remoteproc, Pengutronix Kernel Team,
	Fabio Estevam, NXP Linux Team, Andy Gross, Patrice Chotard,
	linux-doc, linux-kernel, linux-arm-kernel, linux-arm-msm,
	Arnaud Pouliquen, Loic PALLARDY, s-anna

Hi Bjorn,

----- On 10 Mar, 2020, at 00:57, Bjorn Andersson bjorn.andersson@linaro.org wrote:

> On Mon 09 Mar 13:32 PDT 2020, Mathieu Poirier wrote:
> 
>> On Mon, Mar 02, 2020 at 10:39:02AM +0100, Clement Leger wrote:
>> > Now that remoteproc can load an elf64, coredump elf class should be
>> > the same as the loaded elf class. In order to do that, add a
>> > elf_class field to rproc with default values. If an elf is loaded
>> > successfully, this field will be updated with the loaded elf class.
>> > Then, the coredump core code has been modified to use the generic elf
>> > macro in order to create an elf file with correct class.
>> > 
>> > Signed-off-by: Clement Leger <cleger@kalray.eu>
>> > ---
>> >  drivers/remoteproc/remoteproc_core.c       | 67 ++++++++++++++++--------------
>> >  drivers/remoteproc/remoteproc_elf_loader.c |  3 ++
>> >  include/linux/remoteproc.h                 |  1 +
>> >  3 files changed, 39 insertions(+), 32 deletions(-)
>> > 
>> > diff --git a/drivers/remoteproc/remoteproc_core.c
>> > b/drivers/remoteproc/remoteproc_core.c
>> > index b932a64a2be2..f923355aa3f9 100644
>> > --- a/drivers/remoteproc/remoteproc_core.c
>> > +++ b/drivers/remoteproc/remoteproc_core.c
>> > @@ -38,6 +38,7 @@
>> >  #include <linux/platform_device.h>
>> >  
>> >  #include "remoteproc_internal.h"
>> > +#include "remoteproc_elf_helpers.h"
>> >  
>> >  #define HIGH_BITS_MASK 0xFFFFFFFF00000000ULL
>> >  
>> > @@ -1566,20 +1567,21 @@ EXPORT_SYMBOL(rproc_coredump_add_custom_segment);
>> >  static void rproc_coredump(struct rproc *rproc)
>> >  {
>> >  	struct rproc_dump_segment *segment;
>> > -	struct elf32_phdr *phdr;
>> > -	struct elf32_hdr *ehdr;
>> > +	void *phdr;
>> > +	void *ehdr;
>> >  	size_t data_size;
>> >  	size_t offset;
>> >  	void *data;
>> >  	void *ptr;
>> > +	u8 class = rproc->elf_class;
>> >  	int phnum = 0;
>> >  
>> >  	if (list_empty(&rproc->dump_segments))
>> >  		return;
>> >  
>> > -	data_size = sizeof(*ehdr);
>> > +	data_size = elf_size_of_hdr(class);
>> >  	list_for_each_entry(segment, &rproc->dump_segments, node) {
>> > -		data_size += sizeof(*phdr) + segment->size;
>> > +		data_size += elf_size_of_phdr(class) + segment->size;
>> >  
>> >  		phnum++;
>> >  	}
>> > @@ -1590,33 +1592,33 @@ static void rproc_coredump(struct rproc *rproc)
>> >  
>> >  	ehdr = data;
>> >  
>> > -	memset(ehdr, 0, sizeof(*ehdr));
>> > -	memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
>> > -	ehdr->e_ident[EI_CLASS] = ELFCLASS32;
>> > -	ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
>> > -	ehdr->e_ident[EI_VERSION] = EV_CURRENT;
>> > -	ehdr->e_ident[EI_OSABI] = ELFOSABI_NONE;
>> > -	ehdr->e_type = ET_CORE;
>> > -	ehdr->e_machine = EM_NONE;
>> > -	ehdr->e_version = EV_CURRENT;
>> > -	ehdr->e_entry = rproc->bootaddr;
>> > -	ehdr->e_phoff = sizeof(*ehdr);
>> > -	ehdr->e_ehsize = sizeof(*ehdr);
>> > -	ehdr->e_phentsize = sizeof(*phdr);
>> > -	ehdr->e_phnum = phnum;
>> > -
>> > -	phdr = data + ehdr->e_phoff;
>> > -	offset = ehdr->e_phoff + sizeof(*phdr) * ehdr->e_phnum;
>> > +	memset(ehdr, 0, elf_size_of_hdr(class));
>> > +	/* e_ident field is common for both elf32 and elf64 */
>> > +	elf_hdr_init_ident(ehdr, class);
>> > +
>> > +	elf_hdr_set_e_type(class, ehdr, ET_CORE);
>> > +	elf_hdr_set_e_machine(class, ehdr, EM_NONE);
>> > +	elf_hdr_set_e_version(class, ehdr, EV_CURRENT);
>> > +	elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr);
>> > +	elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class));
>> > +	elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class));
>> > +	elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class));
>> > +	elf_hdr_set_e_phnum(class, ehdr, phnum);
>> > +
>> > +	phdr = data + elf_hdr_get_e_phoff(class, ehdr);
>> > +	offset = elf_hdr_get_e_phoff(class, ehdr);
>> > +	offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr);
>> > +
>> >  	list_for_each_entry(segment, &rproc->dump_segments, node) {
>> > -		memset(phdr, 0, sizeof(*phdr));
>> > -		phdr->p_type = PT_LOAD;
>> > -		phdr->p_offset = offset;
>> > -		phdr->p_vaddr = segment->da;
>> > -		phdr->p_paddr = segment->da;
>> > -		phdr->p_filesz = segment->size;
>> > -		phdr->p_memsz = segment->size;
>> > -		phdr->p_flags = PF_R | PF_W | PF_X;
>> > -		phdr->p_align = 0;
>> > +		memset(phdr, 0, elf_size_of_phdr(class));
>> > +		elf_phdr_set_p_type(class, phdr, PT_LOAD);
>> > +		elf_phdr_set_p_offset(class, phdr, offset);
>> > +		elf_phdr_set_p_vaddr(class, phdr, segment->da);
>> > +		elf_phdr_set_p_paddr(class, phdr, segment->da);
>> > +		elf_phdr_set_p_filesz(class, phdr, segment->size);
>> > +		elf_phdr_set_p_memsz(class, phdr, segment->size);
>> > +		elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X);
>> > +		elf_phdr_set_p_align(class, phdr, 0);
>> >  
>> >  		if (segment->dump) {
>> >  			segment->dump(rproc, segment, data + offset);
>> > @@ -1632,8 +1634,8 @@ static void rproc_coredump(struct rproc *rproc)
>> >  			}
>> >  		}
>> >  
>> > -		offset += phdr->p_filesz;
>> > -		phdr++;
>> > +		offset += elf_phdr_get_p_filesz(class, phdr);
>> > +		phdr += elf_size_of_phdr(class);
>> >  	}
>> >  
>> >  	dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL);
>> > @@ -2031,6 +2033,7 @@ struct rproc *rproc_alloc(struct device *dev, const char
>> > *name,
>> >  	rproc->name = name;
>> >  	rproc->priv = &rproc[1];
>> >  	rproc->auto_boot = true;
>> > +	rproc->elf_class = ELFCLASS32;
>> 
>> I would initialise this to ELFCLASSNONE to make sure that if a platform driver
>> overwrites rproc_elf_load_segments or doesn't provide one, we don't falsely
>> deduce the elf type.  It goes without saying that if elf_class == ELFCLASSNONE,
>> a coredump is not generated.
>> 
> 
> I like the idea of making the choice explicit, perhaps even m