LCOV - code coverage report
Current view: top level - drivers/remoteproc - remoteproc_elf_loader.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 0 121 0.0 %
Date: 2022-03-28 16:04:14 Functions: 0 6 0.0 %
Branches: 0 56 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Remote Processor Framework Elf loader
       4                 :            :  *
       5                 :            :  * Copyright (C) 2011 Texas Instruments, Inc.
       6                 :            :  * Copyright (C) 2011 Google, Inc.
       7                 :            :  *
       8                 :            :  * Ohad Ben-Cohen <ohad@wizery.com>
       9                 :            :  * Brian Swetland <swetland@google.com>
      10                 :            :  * Mark Grosen <mgrosen@ti.com>
      11                 :            :  * Fernando Guzman Lugo <fernando.lugo@ti.com>
      12                 :            :  * Suman Anna <s-anna@ti.com>
      13                 :            :  * Robert Tivy <rtivy@ti.com>
      14                 :            :  * Armando Uribe De Leon <x0095078@ti.com>
      15                 :            :  * Sjur Brændeland <sjur.brandeland@stericsson.com>
      16                 :            :  */
      17                 :            : 
      18                 :            : #define pr_fmt(fmt)    "%s: " fmt, __func__
      19                 :            : 
      20                 :            : #include <linux/module.h>
      21                 :            : #include <linux/firmware.h>
      22                 :            : #include <linux/remoteproc.h>
      23                 :            : #include <linux/elf.h>
      24                 :            : 
      25                 :            : #include "remoteproc_internal.h"
      26                 :            : 
      27                 :            : /**
      28                 :            :  * rproc_elf_sanity_check() - Sanity Check ELF firmware image
      29                 :            :  * @rproc: the remote processor handle
      30                 :            :  * @fw: the ELF firmware image
      31                 :            :  *
      32                 :            :  * Make sure this fw image is sane.
      33                 :            :  */
      34                 :          0 : int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
      35                 :            : {
      36                 :          0 :         const char *name = rproc->firmware;
      37                 :          0 :         struct device *dev = &rproc->dev;
      38                 :          0 :         struct elf32_hdr *ehdr;
      39                 :          0 :         char class;
      40                 :            : 
      41         [ #  # ]:          0 :         if (!fw) {
      42                 :          0 :                 dev_err(dev, "failed to load %s\n", name);
      43                 :          0 :                 return -EINVAL;
      44                 :            :         }
      45                 :            : 
      46         [ #  # ]:          0 :         if (fw->size < sizeof(struct elf32_hdr)) {
      47                 :          0 :                 dev_err(dev, "Image is too small\n");
      48                 :          0 :                 return -EINVAL;
      49                 :            :         }
      50                 :            : 
      51                 :          0 :         ehdr = (struct elf32_hdr *)fw->data;
      52                 :            : 
      53                 :            :         /* We only support ELF32 at this point */
      54                 :          0 :         class = ehdr->e_ident[EI_CLASS];
      55         [ #  # ]:          0 :         if (class != ELFCLASS32) {
      56                 :          0 :                 dev_err(dev, "Unsupported class: %d\n", class);
      57                 :          0 :                 return -EINVAL;
      58                 :            :         }
      59                 :            : 
      60                 :            :         /* We assume the firmware has the same endianness as the host */
      61                 :            : # ifdef __LITTLE_ENDIAN
      62         [ #  # ]:          0 :         if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
      63                 :            : # else /* BIG ENDIAN */
      64                 :            :         if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
      65                 :            : # endif
      66                 :          0 :                 dev_err(dev, "Unsupported firmware endianness\n");
      67                 :          0 :                 return -EINVAL;
      68                 :            :         }
      69                 :            : 
      70         [ #  # ]:          0 :         if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
      71                 :          0 :                 dev_err(dev, "Image is too small\n");
      72                 :          0 :                 return -EINVAL;
      73                 :            :         }
      74                 :            : 
      75         [ #  # ]:          0 :         if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
      76                 :          0 :                 dev_err(dev, "Image is corrupted (bad magic)\n");
      77                 :          0 :                 return -EINVAL;
      78                 :            :         }
      79                 :            : 
      80         [ #  # ]:          0 :         if (ehdr->e_phnum == 0) {
      81                 :          0 :                 dev_err(dev, "No loadable segments\n");
      82                 :          0 :                 return -EINVAL;
      83                 :            :         }
      84                 :            : 
      85         [ #  # ]:          0 :         if (ehdr->e_phoff > fw->size) {
      86                 :          0 :                 dev_err(dev, "Firmware size is too small\n");
      87                 :          0 :                 return -EINVAL;
      88                 :            :         }
      89                 :            : 
      90                 :            :         return 0;
      91                 :            : }
      92                 :            : EXPORT_SYMBOL(rproc_elf_sanity_check);
      93                 :            : 
      94                 :            : /**
      95                 :            :  * rproc_elf_get_boot_addr() - Get rproc's boot address.
      96                 :            :  * @rproc: the remote processor handle
      97                 :            :  * @fw: the ELF firmware image
      98                 :            :  *
      99                 :            :  * This function returns the entry point address of the ELF
     100                 :            :  * image.
     101                 :            :  *
     102                 :            :  * Note that the boot address is not a configurable property of all remote
     103                 :            :  * processors. Some will always boot at a specific hard-coded address.
     104                 :            :  */
     105                 :          0 : u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
     106                 :            : {
     107                 :          0 :         struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
     108                 :            : 
     109                 :          0 :         return ehdr->e_entry;
     110                 :            : }
     111                 :            : EXPORT_SYMBOL(rproc_elf_get_boot_addr);
     112                 :            : 
     113                 :            : /**
     114                 :            :  * rproc_elf_load_segments() - load firmware segments to memory
     115                 :            :  * @rproc: remote processor which will be booted using these fw segments
     116                 :            :  * @fw: the ELF firmware image
     117                 :            :  *
     118                 :            :  * This function loads the firmware segments to memory, where the remote
     119                 :            :  * processor expects them.
     120                 :            :  *
     121                 :            :  * Some remote processors will expect their code and data to be placed
     122                 :            :  * in specific device addresses, and can't have them dynamically assigned.
     123                 :            :  *
     124                 :            :  * We currently support only those kind of remote processors, and expect
     125                 :            :  * the program header's paddr member to contain those addresses. We then go
     126                 :            :  * through the physically contiguous "carveout" memory regions which we
     127                 :            :  * allocated (and mapped) earlier on behalf of the remote processor,
     128                 :            :  * and "translate" device address to kernel addresses, so we can copy the
     129                 :            :  * segments where they are expected.
     130                 :            :  *
     131                 :            :  * Currently we only support remote processors that required carveout
     132                 :            :  * allocations and got them mapped onto their iommus. Some processors
     133                 :            :  * might be different: they might not have iommus, and would prefer to
     134                 :            :  * directly allocate memory for every segment/resource. This is not yet
     135                 :            :  * supported, though.
     136                 :            :  */
     137                 :          0 : int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
     138                 :            : {
     139                 :          0 :         struct device *dev = &rproc->dev;
     140                 :          0 :         struct elf32_hdr *ehdr;
     141                 :          0 :         struct elf32_phdr *phdr;
     142                 :          0 :         int i, ret = 0;
     143                 :          0 :         const u8 *elf_data = fw->data;
     144                 :            : 
     145                 :          0 :         ehdr = (struct elf32_hdr *)elf_data;
     146                 :          0 :         phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
     147                 :            : 
     148                 :            :         /* go through the available ELF segments */
     149         [ #  # ]:          0 :         for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
     150                 :          0 :                 u32 da = phdr->p_paddr;
     151                 :          0 :                 u32 memsz = phdr->p_memsz;
     152                 :          0 :                 u32 filesz = phdr->p_filesz;
     153                 :          0 :                 u32 offset = phdr->p_offset;
     154                 :          0 :                 void *ptr;
     155                 :            : 
     156         [ #  # ]:          0 :                 if (phdr->p_type != PT_LOAD)
     157                 :          0 :                         continue;
     158                 :            : 
     159                 :          0 :                 dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
     160                 :            :                         phdr->p_type, da, memsz, filesz);
     161                 :            : 
     162         [ #  # ]:          0 :                 if (filesz > memsz) {
     163                 :          0 :                         dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
     164                 :            :                                 filesz, memsz);
     165                 :          0 :                         ret = -EINVAL;
     166                 :          0 :                         break;
     167                 :            :                 }
     168                 :            : 
     169         [ #  # ]:          0 :                 if (offset + filesz > fw->size) {
     170                 :          0 :                         dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
     171                 :            :                                 offset + filesz, fw->size);
     172                 :          0 :                         ret = -EINVAL;
     173                 :          0 :                         break;
     174                 :            :                 }
     175                 :            : 
     176                 :            :                 /* grab the kernel address for this device address */
     177                 :          0 :                 ptr = rproc_da_to_va(rproc, da, memsz);
     178         [ #  # ]:          0 :                 if (!ptr) {
     179                 :          0 :                         dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
     180                 :          0 :                         ret = -EINVAL;
     181                 :          0 :                         break;
     182                 :            :                 }
     183                 :            : 
     184                 :            :                 /* put the segment where the remote processor expects it */
     185         [ #  # ]:          0 :                 if (phdr->p_filesz)
     186                 :          0 :                         memcpy(ptr, elf_data + phdr->p_offset, filesz);
     187                 :            : 
     188                 :            :                 /*
     189                 :            :                  * Zero out remaining memory for this segment.
     190                 :            :                  *
     191                 :            :                  * This isn't strictly required since dma_alloc_coherent already
     192                 :            :                  * did this for us. albeit harmless, we may consider removing
     193                 :            :                  * this.
     194                 :            :                  */
     195         [ #  # ]:          0 :                 if (memsz > filesz)
     196                 :          0 :                         memset(ptr + filesz, 0, memsz - filesz);
     197                 :            :         }
     198                 :            : 
     199                 :          0 :         return ret;
     200                 :            : }
     201                 :            : EXPORT_SYMBOL(rproc_elf_load_segments);
     202                 :            : 
     203                 :            : static struct elf32_shdr *
     204                 :          0 : find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
     205                 :            : {
     206                 :          0 :         struct elf32_shdr *shdr;
     207                 :          0 :         int i;
     208                 :          0 :         const char *name_table;
     209                 :          0 :         struct resource_table *table = NULL;
     210                 :          0 :         const u8 *elf_data = (void *)ehdr;
     211                 :            : 
     212                 :            :         /* look for the resource table and handle it */
     213                 :          0 :         shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
     214                 :          0 :         name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
     215                 :            : 
     216         [ #  # ]:          0 :         for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
     217                 :          0 :                 u32 size = shdr->sh_size;
     218                 :          0 :                 u32 offset = shdr->sh_offset;
     219                 :            : 
     220         [ #  # ]:          0 :                 if (strcmp(name_table + shdr->sh_name, ".resource_table"))
     221                 :          0 :                         continue;
     222                 :            : 
     223                 :          0 :                 table = (struct resource_table *)(elf_data + offset);
     224                 :            : 
     225                 :            :                 /* make sure we have the entire table */
     226   [ #  #  #  # ]:          0 :                 if (offset + size > fw_size || offset + size < size) {
     227                 :          0 :                         dev_err(dev, "resource table truncated\n");
     228                 :          0 :                         return NULL;
     229                 :            :                 }
     230                 :            : 
     231                 :            :                 /* make sure table has at least the header */
     232         [ #  # ]:          0 :                 if (sizeof(struct resource_table) > size) {
     233                 :          0 :                         dev_err(dev, "header-less resource table\n");
     234                 :          0 :                         return NULL;
     235                 :            :                 }
     236                 :            : 
     237                 :            :                 /* we don't support any version beyond the first */
     238         [ #  # ]:          0 :                 if (table->ver != 1) {
     239                 :          0 :                         dev_err(dev, "unsupported fw ver: %d\n", table->ver);
     240                 :          0 :                         return NULL;
     241                 :            :                 }
     242                 :            : 
     243                 :            :                 /* make sure reserved bytes are zeroes */
     244   [ #  #  #  # ]:          0 :                 if (table->reserved[0] || table->reserved[1]) {
     245                 :          0 :                         dev_err(dev, "non zero reserved bytes\n");
     246                 :          0 :                         return NULL;
     247                 :            :                 }
     248                 :            : 
     249                 :            :                 /* make sure the offsets array isn't truncated */
     250   [ #  #  #  # ]:          0 :                 if (struct_size(table, offset, table->num) > size) {
     251                 :          0 :                         dev_err(dev, "resource table incomplete\n");
     252                 :          0 :                         return NULL;
     253                 :            :                 }
     254                 :            : 
     255                 :            :                 return shdr;
     256                 :            :         }
     257                 :            : 
     258                 :            :         return NULL;
     259                 :            : }
     260                 :            : 
     261                 :            : /**
     262                 :            :  * rproc_elf_load_rsc_table() - load the resource table
     263                 :            :  * @rproc: the rproc handle
     264                 :            :  * @fw: the ELF firmware image
     265                 :            :  *
     266                 :            :  * This function finds the resource table inside the remote processor's
     267                 :            :  * firmware, load it into the @cached_table and update @table_ptr.
     268                 :            :  *
     269                 :            :  * Return: 0 on success, negative errno on failure.
     270                 :            :  */
     271                 :          0 : int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
     272                 :            : {
     273                 :          0 :         struct elf32_hdr *ehdr;
     274                 :          0 :         struct elf32_shdr *shdr;
     275                 :          0 :         struct device *dev = &rproc->dev;
     276                 :          0 :         struct resource_table *table = NULL;
     277                 :          0 :         const u8 *elf_data = fw->data;
     278                 :          0 :         size_t tablesz;
     279                 :            : 
     280                 :          0 :         ehdr = (struct elf32_hdr *)elf_data;
     281                 :            : 
     282                 :          0 :         shdr = find_table(dev, ehdr, fw->size);
     283         [ #  # ]:          0 :         if (!shdr)
     284                 :            :                 return -EINVAL;
     285                 :            : 
     286                 :          0 :         table = (struct resource_table *)(elf_data + shdr->sh_offset);
     287                 :          0 :         tablesz = shdr->sh_size;
     288                 :            : 
     289                 :            :         /*
     290                 :            :          * Create a copy of the resource table. When a virtio device starts
     291                 :            :          * and calls vring_new_virtqueue() the address of the allocated vring
     292                 :            :          * will be stored in the cached_table. Before the device is started,
     293                 :            :          * cached_table will be copied into device memory.
     294                 :            :          */
     295                 :          0 :         rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
     296         [ #  # ]:          0 :         if (!rproc->cached_table)
     297                 :            :                 return -ENOMEM;
     298                 :            : 
     299                 :          0 :         rproc->table_ptr = rproc->cached_table;
     300                 :          0 :         rproc->table_sz = tablesz;
     301                 :            : 
     302                 :          0 :         return 0;
     303                 :            : }
     304                 :            : EXPORT_SYMBOL(rproc_elf_load_rsc_table);
     305                 :            : 
     306                 :            : /**
     307                 :            :  * rproc_elf_find_loaded_rsc_table() - find the loaded resource table
     308                 :            :  * @rproc: the rproc handle
     309                 :            :  * @fw: the ELF firmware image
     310                 :            :  *
     311                 :            :  * This function finds the location of the loaded resource table. Don't
     312                 :            :  * call this function if the table wasn't loaded yet - it's a bug if you do.
     313                 :            :  *
     314                 :            :  * Returns the pointer to the resource table if it is found or NULL otherwise.
     315                 :            :  * If the table wasn't loaded yet the result is unspecified.
     316                 :            :  */
     317                 :          0 : struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
     318                 :            :                                                        const struct firmware *fw)
     319                 :            : {
     320                 :          0 :         struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
     321                 :          0 :         struct elf32_shdr *shdr;
     322                 :            : 
     323                 :          0 :         shdr = find_table(&rproc->dev, ehdr, fw->size);
     324         [ #  # ]:          0 :         if (!shdr)
     325                 :            :                 return NULL;
     326                 :            : 
     327                 :          0 :         return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
     328                 :            : }
     329                 :            : EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);

Generated by: LCOV version 1.14