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