2019-08-19 11:48:51

by Clément Leger

[permalink] [raw]
Subject: [PATCH] rproc: Add elf64 support in elf loader

From: Clément Leger <[email protected]>

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 <[email protected]>
Tested-by: Arnaud POULIQUEN <[email protected]>
---
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


2019-09-13 11:58:31

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH] rproc: Add elf64 support in elf loader

Ping ?

----- On 19 Aug, 2019, at 13:45, Clément Leger [email protected] wrote:

> From: Clément Leger <[email protected]>
>
> 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 <[email protected]>
> Tested-by: Arnaud POULIQUEN <[email protected]>
> ---
> 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

2019-10-04 08:33:22

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH] rproc: Add elf64 support in elf loader

Ping ?

----- On 13 Sep, 2019, at 12:58, Clément Leger [email protected] wrote:

> Ping ?
>
> ----- On 19 Aug, 2019, at 13:45, Clément Leger [email protected] wrote:
>
>> From: Clément Leger <[email protected]>
>>
>> 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 <[email protected]>
>> Tested-by: Arnaud POULIQUEN <[email protected]>
>> ---
>> 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

2019-10-04 18:43:31

by Clément Leger

[permalink] [raw]
Subject: [PATCH v2] remoteproc: Add elf64 support in elf loader

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 <[email protected]>
Tested-by: Arnaud POULIQUEN <[email protected]>
---
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

2020-01-09 09:32:21

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v2] remoteproc: Add elf64 support in elf loader

Ping ?

----- On 4 Oct, 2019, at 20:42, Clément Leger [email protected] 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 <[email protected]>
> Tested-by: Arnaud POULIQUEN <[email protected]>
> ---
> 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

2020-01-24 01:19:53

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2] remoteproc: Add elf64 support in elf loader

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 <[email protected]>
> Tested-by: Arnaud POULIQUEN <[email protected]>
> ---
> 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
>

2020-01-24 08:39:43

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v2] remoteproc: Add elf64 support in elf loader

Hi Mathieu,

----- On 24 Jan, 2020, at 01:53, Mathieu Poirier [email protected] 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 <[email protected]>
>> Tested-by: Arnaud POULIQUEN <[email protected]>
>> ---
>> 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

2020-01-24 20:59:06

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2] remoteproc: Add elf64 support in elf loader

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 [email protected] 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 <[email protected]>
> >> Tested-by: Arnaud POULIQUEN <[email protected]>
> >> ---
> >> 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

2020-01-24 22:00:00

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2] remoteproc: Add elf64 support in elf loader

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 [email protected] 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 <[email protected]>
> >> Tested-by: Arnaud POULIQUEN <[email protected]>
> >> ---
> >> 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

2020-01-27 08:53:58

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v2] remoteproc: Add elf64 support in elf loader

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 [email protected] 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 [email protected]
>> 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 <[email protected]>
>> >> Tested-by: Arnaud POULIQUEN <[email protected]>
>> >> ---
>> >> 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

2020-01-28 17:15:45

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2] remoteproc: Add elf64 support in elf loader

On Mon, 27 Jan 2020 at 01:33, Clément Leger <[email protected]> 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 [email protected] 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 [email protected]
> >> 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 <[email protected]>
> >> >> Tested-by: Arnaud POULIQUEN <[email protected]>
> >> >> ---
> >> >> 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

2020-01-29 08:56:33

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v2] remoteproc: Add elf64 support in elf loader

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 [email protected] wrote:

> On Mon, 27 Jan 2020 at 01:33, Clément Leger <[email protected]> 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 [email protected]
>> 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 [email protected]
>> >> 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 <[email protected]>
>> >> >> Tested-by: Arnaud POULIQUEN <[email protected]>
>> >> >> ---
>> >> >> 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

2020-01-29 16:37:50

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v2] remoteproc: Add elf64 support in elf loader

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 [email protected] wrote:
>
> > On Mon, 27 Jan 2020 at 01:33, Cl?ment Leger <[email protected]> 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 [email protected]
> >> 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 [email protected]
> >> >> 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 <[email protected]>
> >> >> >> Tested-by: Arnaud POULIQUEN <[email protected]>
> >> >> >> ---
> >> >> >> 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

2020-02-04 14:37:11

by Clément Leger

[permalink] [raw]
Subject: [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va

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 <[email protected]>
---
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

2020-02-04 14:37:49

by Clément Leger

[permalink] [raw]
Subject: [PATCH v2 2/2] remoteproc: Add elf64 support in elf loader

From: Clément Leger <[email protected]>

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 <[email protected]>
Tested-by: Arnaud POULIQUEN <[email protected]>
---
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

2020-02-04 16:29:44

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va

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 <[email protected]>
> ---
> 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);
>

2020-02-04 17:13:12

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va

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 [email protected] 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 <[email protected]>
>> ---
>> 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);

2020-02-04 17:45:07

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH v2 1/2] remoteproc: Use u64 len for da_to_va



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 [email protected] 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 <[email protected]>
>>> ---
>>> 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);

2020-02-04 17:45:33

by Clément Leger

[permalink] [raw]
Subject: [PATCH v3 0/2] remoteproc: Add elf64 support to elf loader

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

2020-02-04 17:46:05

by Clément Leger

[permalink] [raw]
Subject: [PATCH v3 1/2] remoteproc: Use u64 len for da_to_va

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 <[email protected]>
---
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

2020-02-04 17:46:53

by Clément Leger

[permalink] [raw]
Subject: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader

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 <[email protected]>
Tested-by: Arnaud POULIQUEN <[email protected]>
---
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

2020-02-05 21:08:19

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v3 1/2] remoteproc: Use u64 len for da_to_va

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 <[email protected]>
> ---
> 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
>

2020-02-05 22:51:33

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader

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 <[email protected]>
> Tested-by: Arnaud POULIQUEN <[email protected]>
> ---
> 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
>

2020-02-06 08:39:20

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader

Hi Mathieu,

----- On 5 Feb, 2020, at 23:49, Mathieu Poirier [email protected] 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 <[email protected]>
>> Tested-by: Arnaud POULIQUEN <[email protected]>
>> ---
>> 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

2020-02-06 15:08:29

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader

Hi Mathieu,

----- On 6 Feb, 2020, at 09:37, Clément Leger [email protected] wrote:

> Hi Mathieu,
>
> ----- On 5 Feb, 2020, at 23:49, Mathieu Poirier [email protected]
> 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 <[email protected]>
>>> Tested-by: Arnaud POULIQUEN <[email protected]>
>>> ---
>>> 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

2020-02-06 17:49:49

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader

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 [email protected] wrote:
>
> > Hi Mathieu,
> >
> > ----- On 5 Feb, 2020, at 23:49, Mathieu Poirier [email protected]
> > 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 <[email protected]>
> >>> Tested-by: Arnaud POULIQUEN <[email protected]>
> >>> ---
> >>> 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

2020-02-07 08:00:22

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v3 2/2] remoteproc: Add elf64 support in elf loader



----- On 6 Feb, 2020, at 18:48, Mathieu Poirier [email protected] 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 [email protected] wrote:
>>
>> > Hi Mathieu,
>> >
>> > ----- On 5 Feb, 2020, at 23:49, Mathieu Poirier [email protected]
>> > 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 <[email protected]>
>> >>> Tested-by: Arnaud POULIQUEN <[email protected]>
>> >>> ---
>> >>> 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

2020-02-10 16:25:27

by Clément Leger

[permalink] [raw]
Subject: [PATCH v4 0/5] remoteproc: Add elf64 support

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

2020-02-10 16:25:31

by Clément Leger

[permalink] [raw]
Subject: [PATCH v4 4/5] remoteproc: Add elf64 support in elf loader

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 <[email protected]>
Tested-by: Arnaud POULIQUEN <[email protected]>
---
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

2020-02-11 17:07:18

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] remoteproc: Add elf64 support

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
>

2020-02-11 23:13:25

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] remoteproc: Add elf64 support

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
> >

2020-02-12 08:16:04

by Arnaud POULIQUEN

[permalink] [raw]
Subject: Re: [PATCH v4 0/5] remoteproc: Add elf64 support



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
>>>

2020-03-02 09:39:34

by Clément Leger

[permalink] [raw]
Subject: [PATCH v5 0/8] remoteproc: Add elf64 support

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

2020-03-02 09:39:46

by Clément Leger

[permalink] [raw]
Subject: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32

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 <[email protected]>
---
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

2020-03-02 09:39:56

by Clément Leger

[permalink] [raw]
Subject: [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type

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 <[email protected]>
---
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

2020-03-02 09:39:57

by Clément Leger

[permalink] [raw]
Subject: [PATCH v5 6/8] remoteproc: Add elf64 support in elf loader

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 <[email protected]>
Tested-by: Arnaud POULIQUEN <[email protected]>
---
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

2020-03-02 09:40:13

by Clément Leger

[permalink] [raw]
Subject: [PATCH v5 4/8] remoteproc: Add elf helpers to access elf64 and elf32 fields

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 <[email protected]>
---
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

2020-03-02 09:40:17

by Clément Leger

[permalink] [raw]
Subject: [PATCH v5 2/8] remoteproc: Use size_t instead of int for rproc_mem_entry len

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 <[email protected]>
---
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

2020-03-02 09:40:34

by Clément Leger

[permalink] [raw]
Subject: [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va

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 <[email protected]>
---
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

2020-03-02 09:40:40

by Clément Leger

[permalink] [raw]
Subject: [PATCH v5 7/8] remoteproc: Allow overriding only sanity_check

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 <[email protected]>
---
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

2020-03-02 09:41:04

by Clément Leger

[permalink] [raw]
Subject: [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr

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 <[email protected]>
---
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

2020-03-02 23:06:59

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va

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 <[email protected]>

Reviewed-by: Bjorn Andersson <[email protected]>

> ---
> 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
>

2020-03-02 23:08:36

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v5 2/8] remoteproc: Use size_t instead of int for rproc_mem_entry len

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 <[email protected]>

Reviewed-by: Bjorn Andersson <[email protected]>

> ---
> 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
>

2020-03-02 23:08:51

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr

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 <[email protected]>

Reviewed-by: Bjorn Andersson <[email protected]>

> ---
> 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
>

2020-03-02 23:13:13

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v5 4/8] remoteproc: Add elf helpers to access elf64 and elf32 fields

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 <[email protected]>

Reviewed-by: Bjorn Andersson <[email protected]>

> ---
> 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
>

2020-03-02 23:14:15

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32

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 <[email protected]>
> ---
> 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
>

2020-03-03 08:02:55

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32

Hi Bjorn,

----- On 3 Mar, 2020, at 00:13, Bjorn Andersson [email protected] 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 <[email protected]>
>> ---
>> 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

2020-03-03 22:03:00

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type

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 <[email protected]>

Reviewed-by: Bjorn Andersson <[email protected]>

> ---
> 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
>

2020-03-09 17:57:10

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va

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 <[email protected]>

Reviewed-by: Mathieu Poirier <[email protected]>

> ---
> 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
>

2020-03-09 19:23:24

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v5 2/8] remoteproc: Use size_t instead of int for rproc_mem_entry len

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 <[email protected]>

With the checkpatch warning fixed:

Reviewed-by: Mathieu Poirier <[email protected]>

> ---
> 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
>

2020-03-09 19:53:25

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr

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 <[email protected]>
> ---
> 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
>

2020-03-09 19:57:46

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v5 4/8] remoteproc: Add elf helpers to access elf64 and elf32 fields

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 <[email protected]>

Reviewed-by: Mathieu Poirier <[email protected]>

> ---
> 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
>

2020-03-09 20:33:15

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type

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 <[email protected]>
> ---
> 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 <[email protected]>

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
>

2020-03-09 23:58:25

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type

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 <[email protected]>
> > ---
> > 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 <[email protected]>
>

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
> >

2020-03-10 00:01:24

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32

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

> Hi Bjorn,
>
> ----- On 3 Mar, 2020, at 00:13, Bjorn Andersson [email protected] 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 <[email protected]>
> >> ---
> >> 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

2020-03-10 07:59:44

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr



----- On 9 Mar, 2020, at 20:52, Mathieu Poirier [email protected] 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 <[email protected]>
>> ---
>> 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

2020-03-10 08:14:19

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v5 8/8] remoteproc: Adapt coredump to generate correct elf type

Hi Bjorn,

----- On 10 Mar, 2020, at 00:57, Bjorn Andersson [email protected] 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 <[email protected]>
>> > ---
>> > 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,

Ok, I tried to do the equivalent of what was existing (ie elf32 by default).
But IMHO, letting the driver choose the elf type is a better idea.

>>
>> Reviewed-by: Mathieu Poirier <[email protected]>
>>
>
> 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())

I was going to send a v7, please tell me if you want to hold it a bit more.
If not, I will address the remaining comments in next commits.

>
> 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

2020-03-10 15:22:26

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32

On Mon, Mar 09, 2020 at 05:00:05PM -0700, Bjorn Andersson wrote:
> On Tue 03 Mar 00:02 PST 2020, Cl?ment Leger wrote:
>
> > Hi Bjorn,
> >
> > ----- On 3 Mar, 2020, at 00:13, Bjorn Andersson [email protected] 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 didn't follow up on this one because I agreed with your assesment and didn't
think it was needed.

Simply put I would rather see rproc_elf_sanity_check() gain support for elf64
and let the platform code decide what to do with format they don't support
rather than spinning a new function.

>
> 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.

It would be really nice to see this cleaned up in time for the coming merge
window...

Thanks
Mathieu

>
> Regards,
> Bjorn
>
> > Regards,
> >
> > Cl?ment
> >
> > >
> > > Regards,
> > > Bjorn
> > >
> > >> Signed-off-by: Clement Leger <[email protected]>
> > >> ---
> > >> 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

2020-03-10 15:39:23

by Clément Leger

[permalink] [raw]
Subject: Re: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32

Hi Mathieu,

----- On 10 Mar, 2020, at 16:20, Mathieu Poirier [email protected] wrote:

> On Mon, Mar 09, 2020 at 05:00:05PM -0700, Bjorn Andersson wrote:
>> On Tue 03 Mar 00:02 PST 2020, Cl?ment Leger wrote:
>>
>> > Hi Bjorn,
>> >
>> > ----- On 3 Mar, 2020, at 00:13, Bjorn Andersson [email protected]
>> > 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 didn't follow up on this one because I agreed with your assesment and didn't
> think it was needed.
>
> Simply put I would rather see rproc_elf_sanity_check() gain support for elf64
> and let the platform code decide what to do with format they don't support
> rather than spinning a new function.
>
>>
>> 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.
>
> It would be really nice to see this cleaned up in time for the coming merge
> window...

I could have sent a V7, but Bjorn was faster than my comment ;)
Bjorn, Is there any way to revert that or it's already pushed ?
I already have a clean V7.

Thanks,

Clément

>
> Thanks
> Mathieu
>
>>
>> Regards,
>> Bjorn
>>
>> > Regards,
>> >
>> > Clément
>> >
>> > >
>> > > Regards,
>> > > Bjorn
>> > >
>> > >> Signed-off-by: Clement Leger <[email protected]>
>> > >> ---
>> > >> 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

2020-03-10 19:18:54

by Mathieu Poirier

[permalink] [raw]
Subject: Re: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32

On Tue, 10 Mar 2020 at 09:38, Clément Leger <[email protected]> wrote:
>
> Hi Mathieu,
>
> ----- On 10 Mar, 2020, at 16:20, Mathieu Poirier [email protected] wrote:
>
> > On Mon, Mar 09, 2020 at 05:00:05PM -0700, Bjorn Andersson wrote:
> >> On Tue 03 Mar 00:02 PST 2020, Cl?ment Leger wrote:
> >>
> >> > Hi Bjorn,
> >> >
> >> > ----- On 3 Mar, 2020, at 00:13, Bjorn Andersson [email protected]
> >> > 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 didn't follow up on this one because I agreed with your assesment and didn't
> > think it was needed.
> >
> > Simply put I would rather see rproc_elf_sanity_check() gain support for elf64
> > and let the platform code decide what to do with format they don't support
> > rather than spinning a new function.
> >
> >>
> >> 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.
> >
> > It would be really nice to see this cleaned up in time for the coming merge
> > window...
>
> I could have sent a V7, but Bjorn was faster than my comment ;)
> Bjorn, Is there any way to revert that or it's already pushed ?
> I already have a clean V7.

Just send another patchset that applies on top of this one.

>
> Thanks,
>
> Clément
>
> >
> > Thanks
> > Mathieu
> >
> >>
> >> Regards,
> >> Bjorn
> >>
> >> > Regards,
> >> >
> >> > Clément
> >> >
> >> > >
> >> > > Regards,
> >> > > Bjorn
> >> > >
> >> > >> Signed-off-by: Clement Leger <[email protected]>
> >> > >> ---
> >> > >> 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

2020-03-10 19:31:24

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v5 5/8] remoteproc: Rename rproc_elf_sanity_check for elf32

On Tue 10 Mar 08:38 PDT 2020, Cl?ment Leger wrote:

> Hi Mathieu,
>
> ----- On 10 Mar, 2020, at 16:20, Mathieu Poirier [email protected] wrote:
>
> > On Mon, Mar 09, 2020 at 05:00:05PM -0700, Bjorn Andersson wrote:
> >> On Tue 03 Mar 00:02 PST 2020, Cl?ment Leger wrote:
> >>
> >> > Hi Bjorn,
> >> >
> >> > ----- On 3 Mar, 2020, at 00:13, Bjorn Andersson [email protected]
> >> > 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 didn't follow up on this one because I agreed with your assesment and didn't
> > think it was needed.
> >
> > Simply put I would rather see rproc_elf_sanity_check() gain support for elf64
> > and let the platform code decide what to do with format they don't support
> > rather than spinning a new function.
> >
> >>
> >> 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.
> >
> > It would be really nice to see this cleaned up in time for the coming merge
> > window...
>
> I could have sent a V7, but Bjorn was faster than my comment ;)

I figured it had been maturing on the list long enough and expected the
cleanup to be a nice incremental patch.

> Bjorn, Is there any way to revert that or it's already pushed ?
> I already have a clean V7.
>

Please base your changes on what's in rproc-next (and today's
linux-next).

Thank you,
Bjorn

2020-03-10 19:34:28

by Bjorn Andersson

[permalink] [raw]
Subject: Re: [PATCH v5 3/8] remoteproc: Use u64 type for boot_addr

On Tue 10 Mar 00:59 PDT 2020, Cl?ment Leger wrote:

>
>
> ----- On 9 Mar, 2020, at 20:52, Mathieu Poirier [email protected] 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 <[email protected]>
> >> ---
> >> 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.
>

Sorry, I forgot to reply to this one. I fixed it up while applying the
patch.

Thanks,
Bjorn

> >
> >> 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

2020-03-27 07:40:01

by Oleksij Rempel

[permalink] [raw]
Subject: Re: [PATCH v5 1/8] remoteproc: Use size_t type for len in da_to_va

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 <[email protected]>
> ---
> drivers/remoteproc/imx_rproc.c | 11 ++++++-----

Reviewed-by: Oleksij Rempel <[email protected]>

> 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
>
>
>

--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |