Re: [PATCH v2 06/14] remoteproc: add page lookup for TI PRU to ELF loader

From: Andrew F. Davis
Date: Mon Feb 04 2019 - 10:20:26 EST


On 2/4/19 8:22 AM, Roger Quadros wrote:
> From: David Lechner <david@xxxxxxxxxxxxxx>
>
> This adds a special handler to the default remoteproc ELF firmware
> loader that looks up the memory map on TI PRU firmware files.
>
> These processors have multiple memory maps that share the same address
> space, so we need to know the page in addition to the physical address
> in order to translate the address to a local CPU address.
>
> Signed-off-by: David Lechner <david@xxxxxxxxxxxxxx>
> Signed-off-by: Roger Quadros <rogerq@xxxxxx>
> ---
> drivers/remoteproc/remoteproc_elf_loader.c | 117 +++++++++++++++++++++++++++--
> include/uapi/linux/elf-em.h | 1 +
> 2 files changed, 112 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/remoteproc/remoteproc_elf_loader.c b/drivers/remoteproc/remoteproc_elf_loader.c
> index 8888d39..79c9d39 100644
> --- a/drivers/remoteproc/remoteproc_elf_loader.c
> +++ b/drivers/remoteproc/remoteproc_elf_loader.c
> @@ -32,6 +32,103 @@
>
> #include "remoteproc_internal.h"
>
> +#define SHT_TI_PHATTRS 0x7F000004
> +#define SHT_TI_SH_PAGE 0x7F000007
> +
> +struct elf32_ti_phattrs {
> + Elf32_Half pha_seg_id; /* Segment id */
> + Elf32_Half pha_tag_id; /* Attribute kind id */
> + union {
> + Elf32_Off pha_offset; /* byte offset within the section */
> + Elf32_Word pha_value; /* Constant tag value */
> + } pha_un;
> +};
> +
> +/* this struct is reverse engineered, so not sure what most of the values are */

Do we really not know? Someone should go check this, if they are not
used then for now label them "unused", not "unknown".

Andrew

> +struct ti_section_page {
> + u32 unk0;
> + u32 unk1;
> + u32 unk2;
> + u32 unk3;
> + u32 unk4;
> + u16 size;
> + u16 unk5;
> + u16 unk6;
> + u8 data[0]; /* array of size */
> +};
> +
> +/**
> + * rproc_elf_segment_to_map() - Gets memory map for segment
> + * @id: segment id
> + * @elf_data: pointer to ELF file data
> + *
> + * Returns the memory map for the segment.
> + */
> +static int rproc_elf_segment_to_map(u32 id, const u8 *elf_data)
> +{
> + struct elf32_hdr *ehdr;
> + struct elf32_shdr *shdr;
> + struct elf32_ti_phattrs *ti_attrs = NULL;
> + int i;
> +
> + ehdr = (struct elf32_hdr *)elf_data;
> + shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> +
> + if (ehdr->e_machine != EM_TI_PRU)
> + return 0;
> +
> + for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> + if (shdr->sh_type == SHT_TI_PHATTRS) {
> + ti_attrs = (struct elf32_ti_phattrs *)(elf_data + shdr->sh_offset);
> + break;
> + }
> + }
> +
> + if (!ti_attrs)
> + return 0;
> +
> + /* list is terminated by tag id == 0 (PHA_NULL) */
> + for (; ti_attrs->pha_tag_id; ti_attrs++) {
> + if (ti_attrs->pha_tag_id == 3 && ti_attrs->pha_seg_id == id)
> + return ti_attrs->pha_un.pha_value;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * rproc_elf_section_to_map() - Gets memory map for section
> + * @id: segment id
> + * @elf_data: pointer to ELF file data
> + *
> + * Returns the memory map for the section.
> + */
> +static int rproc_elf_section_to_map(u32 id, const u8 *elf_data)
> +{
> + struct elf32_hdr *ehdr;
> + struct elf32_shdr *shdr;
> + struct ti_section_page *map = NULL;
> + int i;
> +
> + ehdr = (struct elf32_hdr *)elf_data;
> + shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
> +
> + if (ehdr->e_machine != EM_TI_PRU)
> + return 0;
> +
> + for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
> + if (shdr->sh_type == SHT_TI_SH_PAGE) {
> + map = (struct ti_section_page *)(elf_data + shdr->sh_offset);
> + break;
> + }
> + }
> +
> + if (!map || id >= map->size)
> + return 0;
> +
> + return map->data[id];
> +}
> +
> /**
> * rproc_elf_sanity_check() - Sanity Check ELF firmware image
> * @rproc: the remote processor handle
> @@ -147,7 +244,7 @@ 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;
> - int i, ret = 0;
> + int i, map, ret = 0;
> const u8 *elf_data = fw->data;
>
> ehdr = (struct elf32_hdr *)elf_data;
> @@ -181,8 +278,10 @@ int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
> break;
> }
>
> + map = rproc_elf_segment_to_map(i, elf_data);
> +
> /* grab the kernel address for this device address */
> - ptr = rproc_da_to_va(rproc, da, memsz, 0);
> + ptr = rproc_da_to_va(rproc, da, memsz, map);
> if (!ptr) {
> dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
> ret = -EINVAL;
> @@ -209,7 +308,7 @@ 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)
> +find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size, int *id)
> {
> struct elf32_shdr *shdr;
> int i;
> @@ -261,6 +360,9 @@ find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
> return NULL;
> }
>
> + if (id)
> + *id = i;
> +
> return shdr;
> }
>
> @@ -288,7 +390,7 @@ int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
>
> ehdr = (struct elf32_hdr *)elf_data;
>
> - shdr = find_table(dev, ehdr, fw->size);
> + shdr = find_table(dev, ehdr, fw->size, NULL);
> if (!shdr)
> return -EINVAL;
>
> @@ -328,11 +430,14 @@ struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
> {
> struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
> struct elf32_shdr *shdr;
> + int id, map;
>
> - shdr = find_table(&rproc->dev, ehdr, fw->size);
> + shdr = find_table(&rproc->dev, ehdr, fw->size, &id);
> if (!shdr)
> return NULL;
>
> - return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, 0);
> + map = rproc_elf_section_to_map(id, fw->data);
> +
> + return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size, map);
> }
> EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
> diff --git a/include/uapi/linux/elf-em.h b/include/uapi/linux/elf-em.h
> index 0c3000fa..70b487a 100644
> --- a/include/uapi/linux/elf-em.h
> +++ b/include/uapi/linux/elf-em.h
> @@ -38,6 +38,7 @@
> #define EM_BLACKFIN 106 /* ADI Blackfin Processor */
> #define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */
> #define EM_TI_C6000 140 /* TI C6X DSPs */
> +#define EM_TI_PRU 144 /* TI Programmable Realtime Unit */
> #define EM_AARCH64 183 /* ARM 64 bit */
> #define EM_TILEPRO 188 /* Tilera TILEPro */
> #define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */
>