• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
rproc_elf_sanity_check(struct rproc * rproc,const struct firmware * fw)34 int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
35 {
36 	const char *name = rproc->firmware;
37 	struct device *dev = &rproc->dev;
38 	struct elf32_hdr *ehdr;
39 	char class;
40 
41 	if (!fw) {
42 		dev_err(dev, "failed to load %s\n", name);
43 		return -EINVAL;
44 	}
45 
46 	if (fw->size < sizeof(struct elf32_hdr)) {
47 		dev_err(dev, "Image is too small\n");
48 		return -EINVAL;
49 	}
50 
51 	ehdr = (struct elf32_hdr *)fw->data;
52 
53 	/* We only support ELF32 at this point */
54 	class = ehdr->e_ident[EI_CLASS];
55 	if (class != ELFCLASS32) {
56 		dev_err(dev, "Unsupported class: %d\n", class);
57 		return -EINVAL;
58 	}
59 
60 	/* We assume the firmware has the same endianness as the host */
61 # ifdef __LITTLE_ENDIAN
62 	if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
63 # else /* BIG ENDIAN */
64 	if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
65 # endif
66 		dev_err(dev, "Unsupported firmware endianness\n");
67 		return -EINVAL;
68 	}
69 
70 	if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
71 		dev_err(dev, "Image is too small\n");
72 		return -EINVAL;
73 	}
74 
75 	if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
76 		dev_err(dev, "Image is corrupted (bad magic)\n");
77 		return -EINVAL;
78 	}
79 
80 	if (ehdr->e_phnum == 0) {
81 		dev_err(dev, "No loadable segments\n");
82 		return -EINVAL;
83 	}
84 
85 	if (ehdr->e_phoff > fw->size) {
86 		dev_err(dev, "Firmware size is too small\n");
87 		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 u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
106 {
107 	struct elf32_hdr *ehdr  = (struct elf32_hdr *)fw->data;
108 
109 	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 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
138 {
139 	struct device *dev = &rproc->dev;
140 	struct elf32_hdr *ehdr;
141 	struct elf32_phdr *phdr;
142 	int i, ret = 0;
143 	const u8 *elf_data = fw->data;
144 
145 	ehdr = (struct elf32_hdr *)elf_data;
146 	phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
147 
148 	/* go through the available ELF segments */
149 	for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
150 		u32 da = phdr->p_paddr;
151 		u32 memsz = phdr->p_memsz;
152 		u32 filesz = phdr->p_filesz;
153 		u32 offset = phdr->p_offset;
154 		void *ptr;
155 
156 		if (phdr->p_type != PT_LOAD)
157 			continue;
158 
159 		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 		if (filesz > memsz) {
163 			dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
164 				filesz, memsz);
165 			ret = -EINVAL;
166 			break;
167 		}
168 
169 		if (offset + filesz > fw->size) {
170 			dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
171 				offset + filesz, fw->size);
172 			ret = -EINVAL;
173 			break;
174 		}
175 
176 		/* grab the kernel address for this device address */
177 		ptr = rproc_da_to_va(rproc, da, memsz);
178 		if (!ptr) {
179 			dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
180 			ret = -EINVAL;
181 			break;
182 		}
183 
184 		/* put the segment where the remote processor expects it */
185 		if (phdr->p_filesz)
186 			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 		if (memsz > filesz)
196 			memset(ptr + filesz, 0, memsz - filesz);
197 	}
198 
199 	return ret;
200 }
201 EXPORT_SYMBOL(rproc_elf_load_segments);
202 
203 static struct elf32_shdr *
204 find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
205 {
206 	struct elf32_shdr *shdr;
207 	int i;
208 	const char *name_table;
209 	struct resource_table *table = NULL;
210 	const u8 *elf_data = (void *)ehdr;
211 
212 	/* look for the resource table and handle it */
213 	shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
214 	name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
215 
216 	for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
217 		u32 size = shdr->sh_size;
218 		u32 offset = shdr->sh_offset;
219 
220 		if (strcmp(name_table + shdr->sh_name, ".resource_table"))
221 			continue;
222 
223 		table = (struct resource_table *)(elf_data + offset);
224 
225 		/* make sure we have the entire table */
226 		if (offset + size > fw_size || offset + size < size) {
227 			dev_err(dev, "resource table truncated\n");
228 			return NULL;
229 		}
230 
231 		/* make sure table has at least the header */
232 		if (sizeof(struct resource_table) > size) {
233 			dev_err(dev, "header-less resource table\n");
234 			return NULL;
235 		}
236 
237 		/* we don't support any version beyond the first */
238 		if (table->ver != 1) {
239 			dev_err(dev, "unsupported fw ver: %d\n", table->ver);
240 			return NULL;
241 		}
242 
243 		/* make sure reserved bytes are zeroes */
244 		if (table->reserved[0] || table->reserved[1]) {
245 			dev_err(dev, "non zero reserved bytes\n");
246 			return NULL;
247 		}
248 
249 		/* make sure the offsets array isn't truncated */
250 		if (struct_size(table, offset, table->num) > size) {
251 			dev_err(dev, "resource table incomplete\n");
252 			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 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
272 {
273 	struct elf32_hdr *ehdr;
274 	struct elf32_shdr *shdr;
275 	struct device *dev = &rproc->dev;
276 	struct resource_table *table = NULL;
277 	const u8 *elf_data = fw->data;
278 	size_t tablesz;
279 
280 	ehdr = (struct elf32_hdr *)elf_data;
281 
282 	shdr = find_table(dev, ehdr, fw->size);
283 	if (!shdr)
284 		return -EINVAL;
285 
286 	table = (struct resource_table *)(elf_data + shdr->sh_offset);
287 	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 	rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
296 	if (!rproc->cached_table)
297 		return -ENOMEM;
298 
299 	rproc->table_ptr = rproc->cached_table;
300 	rproc->table_sz = tablesz;
301 
302 	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 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
318 						       const struct firmware *fw)
319 {
320 	struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
321 	struct elf32_shdr *shdr;
322 
323 	shdr = find_table(&rproc->dev, ehdr, fw->size);
324 	if (!shdr)
325 		return NULL;
326 
327 	return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
328 }
329 EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);
330