Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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);