blob: f2e033aa741e14f83d8e33d4bfffbc9c5eba8d59 [file] [log] [blame]
Fabien Dessenne7a7c4cb2019-05-31 15:11:33 +02001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2/*
3 * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
4 */
5#include <common.h>
Simon Glass1eb69ae2019-11-14 12:57:39 -07006#include <cpu_func.h>
Fabien Dessenne7a7c4cb2019-05-31 15:11:33 +02007#include <dm.h>
8#include <elf.h>
9#include <remoteproc.h>
Simon Glass336d4612020-02-03 07:36:16 -070010#include <dm/device_compat.h>
11#include <linux/compat.h>
Fabien Dessenne7a7c4cb2019-05-31 15:11:33 +020012
Fabien Dessenneffcb8802019-10-30 14:38:28 +010013/**
14 * struct resource_table - firmware resource table header
15 * @ver: version number
16 * @num: number of resource entries
17 * @reserved: reserved (must be zero)
18 * @offset: array of offsets pointing at the various resource entries
19 *
20 * A resource table is essentially a list of system resources required
21 * by the remote processor. It may also include configuration entries.
22 * If needed, the remote processor firmware should contain this table
23 * as a dedicated ".resource_table" ELF section.
24 *
25 * Some resources entries are mere announcements, where the host is informed
26 * of specific remoteproc configuration. Other entries require the host to
27 * do something (e.g. allocate a system resource). Sometimes a negotiation
28 * is expected, where the firmware requests a resource, and once allocated,
29 * the host should provide back its details (e.g. address of an allocated
30 * memory region).
31 *
32 * The header of the resource table, as expressed by this structure,
33 * contains a version number (should we need to change this format in the
34 * future), the number of available resource entries, and their offsets
35 * in the table.
36 *
37 * Immediately following this header are the resource entries themselves.
38 */
39struct resource_table {
40 u32 ver;
41 u32 num;
42 u32 reserved[2];
43 u32 offset[0];
44} __packed;
45
Fabien Dessenne7a7c4cb2019-05-31 15:11:33 +020046/* Basic function to verify ELF32 image format */
47int rproc_elf32_sanity_check(ulong addr, ulong size)
48{
49 Elf32_Ehdr *ehdr;
50 char class;
51
52 if (!addr) {
53 pr_debug("Invalid fw address?\n");
54 return -EFAULT;
55 }
56
57 if (size < sizeof(Elf32_Ehdr)) {
58 pr_debug("Image is too small\n");
59 return -ENOSPC;
60 }
61
62 ehdr = (Elf32_Ehdr *)addr;
63 class = ehdr->e_ident[EI_CLASS];
64
65 if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
66 pr_debug("Not an executable ELF32 image\n");
67 return -EPROTONOSUPPORT;
68 }
69
70 /* We assume the firmware has the same endianness as the host */
71# ifdef __LITTLE_ENDIAN
72 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
73# else /* BIG ENDIAN */
74 if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
75# endif
76 pr_debug("Unsupported firmware endianness\n");
77 return -EILSEQ;
78 }
79
80 if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
81 pr_debug("Image is too small\n");
82 return -ENOSPC;
83 }
84
85 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
86 pr_debug("Image is corrupted (bad magic)\n");
87 return -EBADF;
88 }
89
90 if (ehdr->e_phnum == 0) {
91 pr_debug("No loadable segments\n");
92 return -ENOEXEC;
93 }
94
95 if (ehdr->e_phoff > size) {
96 pr_debug("Firmware size is too small\n");
97 return -ENOSPC;
98 }
99
100 return 0;
101}
102
Lokesh Vutlae3c4d6f2019-09-04 16:01:29 +0530103/* Basic function to verify ELF64 image format */
104int rproc_elf64_sanity_check(ulong addr, ulong size)
105{
106 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
107 char class;
108
109 if (!addr) {
110 pr_debug("Invalid fw address?\n");
111 return -EFAULT;
112 }
113
114 if (size < sizeof(Elf64_Ehdr)) {
115 pr_debug("Image is too small\n");
116 return -ENOSPC;
117 }
118
119 class = ehdr->e_ident[EI_CLASS];
120
121 if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS64) {
122 pr_debug("Not an executable ELF64 image\n");
123 return -EPROTONOSUPPORT;
124 }
125
126 /* We assume the firmware has the same endianness as the host */
127# ifdef __LITTLE_ENDIAN
128 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
129# else /* BIG ENDIAN */
130 if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
131# endif
132 pr_debug("Unsupported firmware endianness\n");
133 return -EILSEQ;
134 }
135
136 if (size < ehdr->e_shoff + sizeof(Elf64_Shdr)) {
137 pr_debug("Image is too small\n");
138 return -ENOSPC;
139 }
140
141 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
142 pr_debug("Image is corrupted (bad magic)\n");
143 return -EBADF;
144 }
145
146 if (ehdr->e_phnum == 0) {
147 pr_debug("No loadable segments\n");
148 return -ENOEXEC;
149 }
150
151 if (ehdr->e_phoff > size) {
152 pr_debug("Firmware size is too small\n");
153 return -ENOSPC;
154 }
155
156 return 0;
157}
158
Lokesh Vutla856c0ad2019-09-04 16:01:30 +0530159/* Basic function to verify ELF image format */
160int rproc_elf_sanity_check(ulong addr, ulong size)
161{
162 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
163
164 if (!addr) {
165 dev_err(dev, "Invalid firmware address\n");
166 return -EFAULT;
167 }
168
169 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
170 return rproc_elf64_sanity_check(addr, size);
171 else
172 return rproc_elf32_sanity_check(addr, size);
173}
174
Lokesh Vutla14d963d2019-09-04 16:01:28 +0530175int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
Fabien Dessenne7a7c4cb2019-05-31 15:11:33 +0200176{
177 Elf32_Ehdr *ehdr; /* Elf header structure pointer */
178 Elf32_Phdr *phdr; /* Program header structure pointer */
179 const struct dm_rproc_ops *ops;
Lokesh Vutla14d963d2019-09-04 16:01:28 +0530180 unsigned int i, ret;
181
182 ret = rproc_elf32_sanity_check(addr, size);
183 if (ret) {
184 dev_err(dev, "Invalid ELF32 Image %d\n", ret);
185 return ret;
186 }
Fabien Dessenne7a7c4cb2019-05-31 15:11:33 +0200187
188 ehdr = (Elf32_Ehdr *)addr;
189 phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
190
191 ops = rproc_get_ops(dev);
192
193 /* Load each program header */
Fabien Dessenne83b539c2019-09-04 09:53:22 +0200194 for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
Fabien Dessenne7a7c4cb2019-05-31 15:11:33 +0200195 void *dst = (void *)(uintptr_t)phdr->p_paddr;
196 void *src = (void *)addr + phdr->p_offset;
197
198 if (phdr->p_type != PT_LOAD)
199 continue;
200
201 if (ops->device_to_virt)
Lokesh Vutlac08eb932019-09-04 16:01:27 +0530202 dst = ops->device_to_virt(dev, (ulong)dst,
203 phdr->p_memsz);
Fabien Dessenne7a7c4cb2019-05-31 15:11:33 +0200204
205 dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
206 i, dst, phdr->p_filesz);
207 if (phdr->p_filesz)
208 memcpy(dst, src, phdr->p_filesz);
209 if (phdr->p_filesz != phdr->p_memsz)
210 memset(dst + phdr->p_filesz, 0x00,
211 phdr->p_memsz - phdr->p_filesz);
212 flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
213 roundup((unsigned long)dst + phdr->p_filesz,
214 ARCH_DMA_MINALIGN) -
215 rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
Fabien Dessenne7a7c4cb2019-05-31 15:11:33 +0200216 }
217
218 return 0;
219}
Lokesh Vutlae3c4d6f2019-09-04 16:01:29 +0530220
221int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
222{
223 const struct dm_rproc_ops *ops = rproc_get_ops(dev);
224 u64 da, memsz, filesz, offset;
225 Elf64_Ehdr *ehdr;
226 Elf64_Phdr *phdr;
227 int i, ret = 0;
228 void *ptr;
229
230 dev_dbg(dev, "%s: addr = 0x%lx size = 0x%lx\n", __func__, addr, size);
231
232 if (rproc_elf64_sanity_check(addr, size))
233 return -EINVAL;
234
235 ehdr = (Elf64_Ehdr *)addr;
236 phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
237
238 /* go through the available ELF segments */
239 for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
240 da = phdr->p_paddr;
241 memsz = phdr->p_memsz;
242 filesz = phdr->p_filesz;
243 offset = phdr->p_offset;
244
245 if (phdr->p_type != PT_LOAD)
246 continue;
247
248 dev_dbg(dev, "%s:phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
249 __func__, phdr->p_type, da, memsz, filesz);
250
251 ptr = (void *)(uintptr_t)da;
252 if (ops->device_to_virt) {
253 ptr = ops->device_to_virt(dev, da, phdr->p_memsz);
254 if (!ptr) {
255 dev_err(dev, "bad da 0x%llx mem 0x%llx\n", da,
256 memsz);
257 ret = -EINVAL;
258 break;
259 }
260 }
261
262 if (filesz)
263 memcpy(ptr, (void *)addr + offset, filesz);
264 if (filesz != memsz)
265 memset(ptr + filesz, 0x00, memsz - filesz);
266
267 flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN),
268 roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) -
269 rounddown((ulong)ptr, ARCH_DMA_MINALIGN));
270 }
271
272 return ret;
273}
Lokesh Vutla856c0ad2019-09-04 16:01:30 +0530274
275int rproc_elf_load_image(struct udevice *dev, ulong addr, ulong size)
276{
277 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
278
279 if (!addr) {
280 dev_err(dev, "Invalid firmware address\n");
281 return -EFAULT;
282 }
283
284 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
285 return rproc_elf64_load_image(dev, addr, size);
286 else
287 return rproc_elf32_load_image(dev, addr, size);
288}
Lokesh Vutla81e39fb2019-09-04 16:01:31 +0530289
290static ulong rproc_elf32_get_boot_addr(ulong addr)
291{
292 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
293
294 return ehdr->e_entry;
295}
296
297static ulong rproc_elf64_get_boot_addr(ulong addr)
298{
299 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
300
301 return ehdr->e_entry;
302}
303
304ulong rproc_elf_get_boot_addr(struct udevice *dev, ulong addr)
305{
306 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
307
308 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
309 return rproc_elf64_get_boot_addr(addr);
310 else
311 return rproc_elf32_get_boot_addr(addr);
312}
Fabien Dessenneffcb8802019-10-30 14:38:28 +0100313
314/*
315 * Search for the resource table in an ELF32 image.
316 * Returns the address of the resource table section if found, NULL if there is
317 * no resource table section, or error pointer.
318 */
319static Elf32_Shdr *rproc_elf32_find_rsc_table(struct udevice *dev,
320 ulong fw_addr, ulong fw_size)
321{
322 int ret;
323 unsigned int i;
324 const char *name_table;
325 struct resource_table *table;
326 const u8 *elf_data = (void *)fw_addr;
327 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr;
328 Elf32_Shdr *shdr;
329
330 ret = rproc_elf32_sanity_check(fw_addr, fw_size);
331 if (ret) {
332 pr_debug("Invalid ELF32 Image %d\n", ret);
333 return ERR_PTR(ret);
334 }
335
336 /* look for the resource table and handle it */
337 shdr = (Elf32_Shdr *)(elf_data + ehdr->e_shoff);
338 name_table = (const char *)(elf_data +
339 shdr[ehdr->e_shstrndx].sh_offset);
340
341 for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
342 u32 size = shdr->sh_size;
343 u32 offset = shdr->sh_offset;
344
345 if (strcmp(name_table + shdr->sh_name, ".resource_table"))
346 continue;
347
348 table = (struct resource_table *)(elf_data + offset);
349
350 /* make sure we have the entire table */
351 if (offset + size > fw_size) {
352 pr_debug("resource table truncated\n");
353 return ERR_PTR(-ENOSPC);
354 }
355
356 /* make sure table has at least the header */
357 if (sizeof(*table) > size) {
358 pr_debug("header-less resource table\n");
359 return ERR_PTR(-ENOSPC);
360 }
361
362 /* we don't support any version beyond the first */
363 if (table->ver != 1) {
364 pr_debug("unsupported fw ver: %d\n", table->ver);
365 return ERR_PTR(-EPROTONOSUPPORT);
366 }
367
368 /* make sure reserved bytes are zeroes */
369 if (table->reserved[0] || table->reserved[1]) {
370 pr_debug("non zero reserved bytes\n");
371 return ERR_PTR(-EBADF);
372 }
373
374 /* make sure the offsets array isn't truncated */
375 if (table->num * sizeof(table->offset[0]) +
376 sizeof(*table) > size) {
377 pr_debug("resource table incomplete\n");
378 return ERR_PTR(-ENOSPC);
379 }
380
381 return shdr;
382 }
383
384 return NULL;
385}
386
387/* Load the resource table from an ELF32 image */
388int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr,
389 ulong fw_size, ulong *rsc_addr, ulong *rsc_size)
390{
391 const struct dm_rproc_ops *ops;
392 Elf32_Shdr *shdr;
393 void *src, *dst;
394
395 shdr = rproc_elf32_find_rsc_table(dev, fw_addr, fw_size);
396 if (!shdr)
397 return -ENODATA;
398 if (IS_ERR(shdr))
399 return PTR_ERR(shdr);
400
401 ops = rproc_get_ops(dev);
402 *rsc_addr = (ulong)shdr->sh_addr;
403 *rsc_size = (ulong)shdr->sh_size;
404
405 src = (void *)fw_addr + shdr->sh_offset;
406 if (ops->device_to_virt)
407 dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size);
408 else
409 dst = (void *)rsc_addr;
410
411 dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n",
412 (ulong)dst, *rsc_size);
413
414 memcpy(dst, src, *rsc_size);
415 flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
416 roundup((unsigned long)dst + *rsc_size,
417 ARCH_DMA_MINALIGN) -
418 rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
419
420 return 0;
421}
422
423/*
424 * Search for the resource table in an ELF64 image.
425 * Returns the address of the resource table section if found, NULL if there is
426 * no resource table section, or error pointer.
427 */
428static Elf64_Shdr *rproc_elf64_find_rsc_table(struct udevice *dev,
429 ulong fw_addr, ulong fw_size)
430{
431 int ret;
432 unsigned int i;
433 const char *name_table;
434 struct resource_table *table;
435 const u8 *elf_data = (void *)fw_addr;
436 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)fw_addr;
437 Elf64_Shdr *shdr;
438
439 ret = rproc_elf64_sanity_check(fw_addr, fw_size);
440 if (ret) {
441 pr_debug("Invalid ELF64 Image %d\n", ret);
442 return ERR_PTR(ret);
443 }
444
445 /* look for the resource table and handle it */
446 shdr = (Elf64_Shdr *)(elf_data + ehdr->e_shoff);
447 name_table = (const char *)(elf_data +
448 shdr[ehdr->e_shstrndx].sh_offset);
449
450 for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
451 u64 size = shdr->sh_size;
452 u64 offset = shdr->sh_offset;
453
454 if (strcmp(name_table + shdr->sh_name, ".resource_table"))
455 continue;
456
457 table = (struct resource_table *)(elf_data + offset);
458
459 /* make sure we have the entire table */
460 if (offset + size > fw_size) {
461 pr_debug("resource table truncated\n");
462 return ERR_PTR(-ENOSPC);
463 }
464
465 /* make sure table has at least the header */
466 if (sizeof(*table) > size) {
467 pr_debug("header-less resource table\n");
468 return ERR_PTR(-ENOSPC);
469 }
470
471 /* we don't support any version beyond the first */
472 if (table->ver != 1) {
473 pr_debug("unsupported fw ver: %d\n", table->ver);
474 return ERR_PTR(-EPROTONOSUPPORT);
475 }
476
477 /* make sure reserved bytes are zeroes */
478 if (table->reserved[0] || table->reserved[1]) {
479 pr_debug("non zero reserved bytes\n");
480 return ERR_PTR(-EBADF);
481 }
482
483 /* make sure the offsets array isn't truncated */
484 if (table->num * sizeof(table->offset[0]) +
485 sizeof(*table) > size) {
486 pr_debug("resource table incomplete\n");
487 return ERR_PTR(-ENOSPC);
488 }
489
490 return shdr;
491 }
492
493 return NULL;
494}
495
496/* Load the resource table from an ELF64 image */
497int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr,
498 ulong fw_size, ulong *rsc_addr, ulong *rsc_size)
499{
500 const struct dm_rproc_ops *ops;
501 Elf64_Shdr *shdr;
502 void *src, *dst;
503
504 shdr = rproc_elf64_find_rsc_table(dev, fw_addr, fw_size);
505 if (!shdr)
506 return -ENODATA;
507 if (IS_ERR(shdr))
508 return PTR_ERR(shdr);
509
510 ops = rproc_get_ops(dev);
511 *rsc_addr = (ulong)shdr->sh_addr;
512 *rsc_size = (ulong)shdr->sh_size;
513
514 src = (void *)fw_addr + shdr->sh_offset;
515 if (ops->device_to_virt)
516 dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size);
517 else
518 dst = (void *)rsc_addr;
519
520 dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n",
521 (ulong)dst, *rsc_size);
522
523 memcpy(dst, src, *rsc_size);
524 flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
525 roundup((unsigned long)dst + *rsc_size,
526 ARCH_DMA_MINALIGN) -
527 rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
528
529 return 0;
530}
531
532/* Load the resource table from an ELF32 or ELF64 image */
533int rproc_elf_load_rsc_table(struct udevice *dev, ulong fw_addr,
534 ulong fw_size, ulong *rsc_addr, ulong *rsc_size)
535
536{
537 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)fw_addr;
538
539 if (!fw_addr)
540 return -EFAULT;
541
542 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
543 return rproc_elf64_load_rsc_table(dev, fw_addr, fw_size,
544 rsc_addr, rsc_size);
545 else
546 return rproc_elf32_load_rsc_table(dev, fw_addr, fw_size,
547 rsc_addr, rsc_size);
548}