linux/drivers/remoteproc/remoteproc_elf_loader.c
<<
>>
Prefs
   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#include "remoteproc_elf_helpers.h"
  27
  28/**
  29 * rproc_elf_sanity_check() - Sanity Check for ELF32/ELF64 firmware image
  30 * @rproc: the remote processor handle
  31 * @fw: the ELF firmware image
  32 *
  33 * Make sure this fw image is sane (ie a correct ELF32/ELF64 file).
  34 */
  35int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
  36{
  37        const char *name = rproc->firmware;
  38        struct device *dev = &rproc->dev;
  39        /*
  40         * Elf files are beginning with the same structure. Thus, to simplify
  41         * header parsing, we can use the elf32_hdr one for both elf64 and
  42         * elf32.
  43         */
  44        struct elf32_hdr *ehdr;
  45        u32 elf_shdr_get_size;
  46        u64 phoff, shoff;
  47        char class;
  48        u16 phnum;
  49
  50        if (!fw) {
  51                dev_err(dev, "failed to load %s\n", name);
  52                return -EINVAL;
  53        }
  54
  55        if (fw->size < sizeof(struct elf32_hdr)) {
  56                dev_err(dev, "Image is too small\n");
  57                return -EINVAL;
  58        }
  59
  60        ehdr = (struct elf32_hdr *)fw->data;
  61
  62        if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
  63                dev_err(dev, "Image is corrupted (bad magic)\n");
  64                return -EINVAL;
  65        }
  66
  67        class = ehdr->e_ident[EI_CLASS];
  68        if (class != ELFCLASS32 && class != ELFCLASS64) {
  69                dev_err(dev, "Unsupported class: %d\n", class);
  70                return -EINVAL;
  71        }
  72
  73        if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
  74                dev_err(dev, "elf64 header is too small\n");
  75                return -EINVAL;
  76        }
  77
  78        /* We assume the firmware has the same endianness as the host */
  79# ifdef __LITTLE_ENDIAN
  80        if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
  81# else /* BIG ENDIAN */
  82        if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
  83# endif
  84                dev_err(dev, "Unsupported firmware endianness\n");
  85                return -EINVAL;
  86        }
  87
  88        phoff = elf_hdr_get_e_phoff(class, fw->data);
  89        shoff = elf_hdr_get_e_shoff(class, fw->data);
  90        phnum =  elf_hdr_get_e_phnum(class, fw->data);
  91        elf_shdr_get_size = elf_size_of_shdr(class);
  92
  93        if (fw->size < shoff + elf_shdr_get_size) {
  94                dev_err(dev, "Image is too small\n");
  95                return -EINVAL;
  96        }
  97
  98        if (phnum == 0) {
  99                dev_err(dev, "No loadable segments\n");
 100                return -EINVAL;
 101        }
 102
 103        if (phoff > fw->size) {
 104                dev_err(dev, "Firmware size is too small\n");
 105                return -EINVAL;
 106        }
 107
 108        dev_dbg(dev, "Firmware is an elf%d file\n",
 109                class == ELFCLASS32 ? 32 : 64);
 110
 111        return 0;
 112}
 113EXPORT_SYMBOL(rproc_elf_sanity_check);
 114
 115/**
 116 * rproc_elf_get_boot_addr() - Get rproc's boot address.
 117 * @rproc: the remote processor handle
 118 * @fw: the ELF firmware image
 119 *
 120 * This function returns the entry point address of the ELF
 121 * image.
 122 *
 123 * Note that the boot address is not a configurable property of all remote
 124 * processors. Some will always boot at a specific hard-coded address.
 125 */
 126u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
 127{
 128        return elf_hdr_get_e_entry(fw_elf_get_class(fw), fw->data);
 129}
 130EXPORT_SYMBOL(rproc_elf_get_boot_addr);
 131
 132/**
 133 * rproc_elf_load_segments() - load firmware segments to memory
 134 * @rproc: remote processor which will be booted using these fw segments
 135 * @fw: the ELF firmware image
 136 *
 137 * This function loads the firmware segments to memory, where the remote
 138 * processor expects them.
 139 *
 140 * Some remote processors will expect their code and data to be placed
 141 * in specific device addresses, and can't have them dynamically assigned.
 142 *
 143 * We currently support only those kind of remote processors, and expect
 144 * the program header's paddr member to contain those addresses. We then go
 145 * through the physically contiguous "carveout" memory regions which we
 146 * allocated (and mapped) earlier on behalf of the remote processor,
 147 * and "translate" device address to kernel addresses, so we can copy the
 148 * segments where they are expected.
 149 *
 150 * Currently we only support remote processors that required carveout
 151 * allocations and got them mapped onto their iommus. Some processors
 152 * might be different: they might not have iommus, and would prefer to
 153 * directly allocate memory for every segment/resource. This is not yet
 154 * supported, though.
 155 */
 156int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
 157{
 158        struct device *dev = &rproc->dev;
 159        const void *ehdr, *phdr;
 160        int i, ret = 0;
 161        u16 phnum;
 162        const u8 *elf_data = fw->data;
 163        u8 class = fw_elf_get_class(fw);
 164        u32 elf_phdr_get_size = elf_size_of_phdr(class);
 165
 166        ehdr = elf_data;
 167        phnum = elf_hdr_get_e_phnum(class, ehdr);
 168        phdr = elf_data + elf_hdr_get_e_phoff(class, ehdr);
 169
 170        /* go through the available ELF segments */
 171        for (i = 0; i < phnum; i++, phdr += elf_phdr_get_size) {
 172                u64 da = elf_phdr_get_p_paddr(class, phdr);
 173                u64 memsz = elf_phdr_get_p_memsz(class, phdr);
 174                u64 filesz = elf_phdr_get_p_filesz(class, phdr);
 175                u64 offset = elf_phdr_get_p_offset(class, phdr);
 176                u32 type = elf_phdr_get_p_type(class, phdr);
 177                void *ptr;
 178
 179                if (type != PT_LOAD)
 180                        continue;
 181
 182                dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
 183                        type, da, memsz, filesz);
 184
 185                if (filesz > memsz) {
 186                        dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
 187                                filesz, memsz);
 188                        ret = -EINVAL;
 189                        break;
 190                }
 191
 192                if (offset + filesz > fw->size) {
 193                        dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
 194                                offset + filesz, fw->size);
 195                        ret = -EINVAL;
 196                        break;
 197                }
 198
 199                if (!rproc_u64_fit_in_size_t(memsz)) {
 200                        dev_err(dev, "size (%llx) does not fit in size_t type\n",
 201                                memsz);
 202                        ret = -EOVERFLOW;
 203                        break;
 204                }
 205
 206                /* grab the kernel address for this device address */
 207                ptr = rproc_da_to_va(rproc, da, memsz);
 208                if (!ptr) {
 209                        dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
 210                                memsz);
 211                        ret = -EINVAL;
 212                        break;
 213                }
 214
 215                /* put the segment where the remote processor expects it */
 216                if (filesz)
 217                        memcpy(ptr, elf_data + offset, filesz);
 218
 219                /*
 220                 * Zero out remaining memory for this segment.
 221                 *
 222                 * This isn't strictly required since dma_alloc_coherent already
 223                 * did this for us. albeit harmless, we may consider removing
 224                 * this.
 225                 */
 226                if (memsz > filesz)
 227                        memset(ptr + filesz, 0, memsz - filesz);
 228        }
 229
 230        return ret;
 231}
 232EXPORT_SYMBOL(rproc_elf_load_segments);
 233
 234static const void *
 235find_table(struct device *dev, const struct firmware *fw)
 236{
 237        const void *shdr, *name_table_shdr;
 238        int i;
 239        const char *name_table;
 240        struct resource_table *table = NULL;
 241        const u8 *elf_data = (void *)fw->data;
 242        u8 class = fw_elf_get_class(fw);
 243        size_t fw_size = fw->size;
 244        const void *ehdr = elf_data;
 245        u16 shnum = elf_hdr_get_e_shnum(class, ehdr);
 246        u32 elf_shdr_get_size = elf_size_of_shdr(class);
 247        u16 shstrndx = elf_hdr_get_e_shstrndx(class, ehdr);
 248
 249        /* look for the resource table and handle it */
 250        /* First, get the section header according to the elf class */
 251        shdr = elf_data + elf_hdr_get_e_shoff(class, ehdr);
 252        /* Compute name table section header entry in shdr array */
 253        name_table_shdr = shdr + (shstrndx * elf_shdr_get_size);
 254        /* Finally, compute the name table section address in elf */
 255        name_table = elf_data + elf_shdr_get_sh_offset(class, name_table_shdr);
 256
 257        for (i = 0; i < shnum; i++, shdr += elf_shdr_get_size) {
 258                u64 size = elf_shdr_get_sh_size(class, shdr);
 259                u64 offset = elf_shdr_get_sh_offset(class, shdr);
 260                u32 name = elf_shdr_get_sh_name(class, shdr);
 261
 262                if (strcmp(name_table + name, ".resource_table"))
 263                        continue;
 264
 265                table = (struct resource_table *)(elf_data + offset);
 266
 267                /* make sure we have the entire table */
 268                if (offset + size > fw_size || offset + size < size) {
 269                        dev_err(dev, "resource table truncated\n");
 270                        return NULL;
 271                }
 272
 273                /* make sure table has at least the header */
 274                if (sizeof(struct resource_table) > size) {
 275                        dev_err(dev, "header-less resource table\n");
 276                        return NULL;
 277                }
 278
 279                /* we don't support any version beyond the first */
 280                if (table->ver != 1) {
 281                        dev_err(dev, "unsupported fw ver: %d\n", table->ver);
 282                        return NULL;
 283                }
 284
 285                /* make sure reserved bytes are zeroes */
 286                if (table->reserved[0] || table->reserved[1]) {
 287                        dev_err(dev, "non zero reserved bytes\n");
 288                        return NULL;
 289                }
 290
 291                /* make sure the offsets array isn't truncated */
 292                if (struct_size(table, offset, table->num) > size) {
 293                        dev_err(dev, "resource table incomplete\n");
 294                        return NULL;
 295                }
 296
 297                return shdr;
 298        }
 299
 300        return NULL;
 301}
 302
 303/**
 304 * rproc_elf_load_rsc_table() - load the resource table
 305 * @rproc: the rproc handle
 306 * @fw: the ELF firmware image
 307 *
 308 * This function finds the resource table inside the remote processor's
 309 * firmware, load it into the @cached_table and update @table_ptr.
 310 *
 311 * Return: 0 on success, negative errno on failure.
 312 */
 313int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
 314{
 315        const void *shdr;
 316        struct device *dev = &rproc->dev;
 317        struct resource_table *table = NULL;
 318        const u8 *elf_data = fw->data;
 319        size_t tablesz;
 320        u8 class = fw_elf_get_class(fw);
 321        u64 sh_offset;
 322
 323        shdr = find_table(dev, fw);
 324        if (!shdr)
 325                return -EINVAL;
 326
 327        sh_offset = elf_shdr_get_sh_offset(class, shdr);
 328        table = (struct resource_table *)(elf_data + sh_offset);
 329        tablesz = elf_shdr_get_sh_size(class, shdr);
 330
 331        /*
 332         * Create a copy of the resource table. When a virtio device starts
 333         * and calls vring_new_virtqueue() the address of the allocated vring
 334         * will be stored in the cached_table. Before the device is started,
 335         * cached_table will be copied into device memory.
 336         */
 337        rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
 338        if (!rproc->cached_table)
 339                return -ENOMEM;
 340
 341        rproc->table_ptr = rproc->cached_table;
 342        rproc->table_sz = tablesz;
 343
 344        return 0;
 345}
 346EXPORT_SYMBOL(rproc_elf_load_rsc_table);
 347
 348/**
 349 * rproc_elf_find_loaded_rsc_table() - find the loaded resource table
 350 * @rproc: the rproc handle
 351 * @fw: the ELF firmware image
 352 *
 353 * This function finds the location of the loaded resource table. Don't
 354 * call this function if the table wasn't loaded yet - it's a bug if you do.
 355 *
 356 * Returns the pointer to the resource table if it is found or NULL otherwise.
 357 * If the table wasn't loaded yet the result is unspecified.
 358 */
 359struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
 360                                                       const struct firmware *fw)
 361{
 362        const void *shdr;
 363        u64 sh_addr, sh_size;
 364        u8 class = fw_elf_get_class(fw);
 365        struct device *dev = &rproc->dev;
 366
 367        shdr = find_table(&rproc->dev, fw);
 368        if (!shdr)
 369                return NULL;
 370
 371        sh_addr = elf_shdr_get_sh_addr(class, shdr);
 372        sh_size = elf_shdr_get_sh_size(class, shdr);
 373
 374        if (!rproc_u64_fit_in_size_t(sh_size)) {
 375                dev_err(dev, "size (%llx) does not fit in size_t type\n",
 376                        sh_size);
 377                return NULL;
 378        }
 379
 380        return rproc_da_to_va(rproc, sh_addr, sh_size);
 381}
 382EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
 383