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