On 2/4/19 8:22 AM, Roger Quadros wrote:
> From: David Lechner <[email protected]>
> 
> 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 <[email protected]>
> Signed-off-by: Roger Quadros <[email protected]>
> ---
>  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 */
> 

Reply via email to