arm: mach-k3: Enable dcache in SPL
[oweals/u-boot.git] / drivers / remoteproc / rproc-elf-loader.c
1 // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2 /*
3  * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
4  */
5 #include <common.h>
6 #include <cpu_func.h>
7 #include <dm.h>
8 #include <elf.h>
9 #include <remoteproc.h>
10 #include <dm/device_compat.h>
11 #include <linux/compat.h>
12
13 /**
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  */
39 struct resource_table {
40         u32 ver;
41         u32 num;
42         u32 reserved[2];
43         u32 offset[0];
44 } __packed;
45
46 /* Basic function to verify ELF32 image format */
47 int 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
103 /* Basic function to verify ELF64 image format */
104 int 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
159 /* Basic function to verify ELF image format */
160 int 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
175 int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
176 {
177         Elf32_Ehdr *ehdr; /* Elf header structure pointer */
178         Elf32_Phdr *phdr; /* Program header structure pointer */
179         const struct dm_rproc_ops *ops;
180         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         }
187
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 */
194         for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
195                 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)
202                         dst = ops->device_to_virt(dev, (ulong)dst,
203                                                   phdr->p_memsz);
204
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));
216         }
217
218         return 0;
219 }
220
221 int 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 }
274
275 int 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 }
289
290 static ulong rproc_elf32_get_boot_addr(ulong addr)
291 {
292         Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
293
294         return ehdr->e_entry;
295 }
296
297 static ulong rproc_elf64_get_boot_addr(ulong addr)
298 {
299         Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
300
301         return ehdr->e_entry;
302 }
303
304 ulong 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 }
313
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  */
319 static 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 */
388 int 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  */
428 static 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 */
497 int 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 */
533 int 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 }