[PATCH V3 2/6] remoteproc: elf_loader: introduce rproc_elf_find_shdr

From: Peng Fan (OSS)
Date: Thu Feb 09 2023 - 01:37:25 EST


From: Peng Fan <peng.fan@xxxxxxx>

Introduce API rproc_elf_find_shdr to get the shdr pointer. This API
could be used to find the ".resource_table" section, and could also
be used by i.MX driver to find the ".interrupts" section.

Signed-off-by: Peng Fan <peng.fan@xxxxxxx>
---
drivers/remoteproc/remoteproc_elf_loader.c | 93 +++++++++++++---------
drivers/remoteproc/remoteproc_internal.h | 2 +
2 files changed, 56 insertions(+), 39 deletions(-)

diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
index 5a412d7b6e0b..c09fd5733aee 100644
--- a/drivers/remoteproc/remoteproc_elf_loader.c
+++ b/drivers/remoteproc/remoteproc_elf_loader.c
@@ -244,22 +244,19 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
}
EXPORT_SYMBOL(rproc_elf_load_segments);

-static const void *
-find_table(struct device *dev, const struct firmware *fw)
+const void *
+rproc_elf_find_shdr(struct rproc *rproc, const struct firmware *fw, const char *sh_name)
{
const void *shdr, *name_table_shdr;
int i;
const char *name_table;
- struct resource_table *table = NULL;
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 */
/* 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 */
@@ -268,49 +265,68 @@ find_table(struct device *dev, const struct firmware *fw)
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"))
+ if (strcmp(name_table + name, sh_name))
continue;

- table = (struct resource_table *)(elf_data + offset);
+ return shdr;
+ }

- /* make sure we have the entire table */
- if (offset + size > fw_size || offset + size < size) {
- dev_err(dev, "resource table truncated\n");
- return NULL;
- }
+ return NULL;
+}
+EXPORT_SYMBOL(rproc_elf_find_shdr);

- /* make sure table has at least the header */
- if (sizeof(struct resource_table) > size) {
- dev_err(dev, "header-less resource table\n");
- return NULL;
- }
+static const void *
+find_table(struct rproc *rproc, const struct firmware *fw)
+{
+ const u8 *elf_data = (void *)fw->data;
+ u8 class = fw_elf_get_class(fw);
+ size_t fw_size = fw->size;
+ struct resource_table *table = NULL;
+ struct device *dev = &rproc->dev;
+ const void *shdr;
+ u64 size, offset;

- /* we don't support any version beyond the first */
- if (table->ver != 1) {
- dev_err(dev, "unsupported fw ver: %d\n", table->ver);
- return NULL;
- }
+ shdr = rproc_elf_find_shdr(rproc, fw, ".resource_table");
+ if (!shdr)
+ return NULL;

- /* make sure reserved bytes are zeroes */
- if (table->reserved[0] || table->reserved[1]) {
- dev_err(dev, "non zero reserved bytes\n");
- return NULL;
- }
+ size = elf_shdr_get_sh_size(class, shdr);
+ offset = elf_shdr_get_sh_offset(class, shdr);
+ table = (struct resource_table *)(elf_data + offset);

- /* make sure the offsets array isn't truncated */
- if (struct_size(table, offset, table->num) > size) {
- dev_err(dev, "resource table incomplete\n");
- return NULL;
- }
+ /* make sure we have the entire table */
+ if (offset + size > fw_size || offset + size < size) {
+ dev_err(dev, "resource table truncated\n");
+ return NULL;
+ }

- return shdr;
+ /* make sure table has at least the header */
+ if (sizeof(struct resource_table) > size) {
+ dev_err(dev, "header-less resource table\n");
+ return NULL;
}

- return NULL;
+ /* we don't support any version beyond the first */
+ if (table->ver != 1) {
+ dev_err(dev, "unsupported fw ver: %d\n", table->ver);
+ return NULL;
+ }
+
+ /* make sure reserved bytes are zeroes */
+ if (table->reserved[0] || table->reserved[1]) {
+ dev_err(dev, "non zero reserved bytes\n");
+ return NULL;
+ }
+
+ /* make sure the offsets array isn't truncated */
+ if (struct_size(table, offset, table->num) > size) {
+ dev_err(dev, "resource table incomplete\n");
+ return NULL;
+ }
+
+ return shdr;
}

/**
@@ -326,14 +342,13 @@ find_table(struct device *dev, const struct firmware *fw)
int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
{
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;

- shdr = find_table(dev, fw);
+ shdr = find_table(rproc, fw);
if (!shdr)
return -EINVAL;

@@ -377,7 +392,7 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
u8 class = fw_elf_get_class(fw);
struct device *dev = &rproc->dev;

- shdr = find_table(&rproc->dev, fw);
+ shdr = find_table(rproc, fw);
if (!shdr)
return NULL;

diff --git a/drivers/remoteproc/remoteproc_internal.h b/drivers/remoteproc/remoteproc_internal.h
index d4dbb8d1d80c..2a4f75a401d3 100644
--- a/drivers/remoteproc/remoteproc_internal.h
+++ b/drivers/remoteproc/remoteproc_internal.h
@@ -117,6 +117,8 @@ int rproc_trigger_recovery(struct rproc *rproc);

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);
+const void *rproc_elf_find_shdr(struct rproc *rproc, const struct firmware *fw,
+ const char *sh_name);
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,
--
2.37.1