blob: 67937a75957d4a95668cb3213247bedabcb3a207 [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>
6#include <dm.h>
7#include <elf.h>
8#include <remoteproc.h>
9
10/* Basic function to verify ELF32 image format */
11int rproc_elf32_sanity_check(ulong addr, ulong size)
12{
13 Elf32_Ehdr *ehdr;
14 char class;
15
16 if (!addr) {
17 pr_debug("Invalid fw address?\n");
18 return -EFAULT;
19 }
20
21 if (size < sizeof(Elf32_Ehdr)) {
22 pr_debug("Image is too small\n");
23 return -ENOSPC;
24 }
25
26 ehdr = (Elf32_Ehdr *)addr;
27 class = ehdr->e_ident[EI_CLASS];
28
29 if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
30 pr_debug("Not an executable ELF32 image\n");
31 return -EPROTONOSUPPORT;
32 }
33
34 /* We assume the firmware has the same endianness as the host */
35# ifdef __LITTLE_ENDIAN
36 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
37# else /* BIG ENDIAN */
38 if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
39# endif
40 pr_debug("Unsupported firmware endianness\n");
41 return -EILSEQ;
42 }
43
44 if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
45 pr_debug("Image is too small\n");
46 return -ENOSPC;
47 }
48
49 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
50 pr_debug("Image is corrupted (bad magic)\n");
51 return -EBADF;
52 }
53
54 if (ehdr->e_phnum == 0) {
55 pr_debug("No loadable segments\n");
56 return -ENOEXEC;
57 }
58
59 if (ehdr->e_phoff > size) {
60 pr_debug("Firmware size is too small\n");
61 return -ENOSPC;
62 }
63
64 return 0;
65}
66
67/* A very simple elf loader, assumes the image is valid */
68int rproc_elf32_load_image(struct udevice *dev, unsigned long addr)
69{
70 Elf32_Ehdr *ehdr; /* Elf header structure pointer */
71 Elf32_Phdr *phdr; /* Program header structure pointer */
72 const struct dm_rproc_ops *ops;
73 unsigned int i;
74
75 ehdr = (Elf32_Ehdr *)addr;
76 phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
77
78 ops = rproc_get_ops(dev);
79
80 /* Load each program header */
81 for (i = 0; i < ehdr->e_phnum; ++i) {
82 void *dst = (void *)(uintptr_t)phdr->p_paddr;
83 void *src = (void *)addr + phdr->p_offset;
84
85 if (phdr->p_type != PT_LOAD)
86 continue;
87
88 if (ops->device_to_virt)
89 dst = ops->device_to_virt(dev, (ulong)dst);
90
91 dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
92 i, dst, phdr->p_filesz);
93 if (phdr->p_filesz)
94 memcpy(dst, src, phdr->p_filesz);
95 if (phdr->p_filesz != phdr->p_memsz)
96 memset(dst + phdr->p_filesz, 0x00,
97 phdr->p_memsz - phdr->p_filesz);
98 flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
99 roundup((unsigned long)dst + phdr->p_filesz,
100 ARCH_DMA_MINALIGN) -
101 rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
102 ++phdr;
103 }
104
105 return 0;
106}