blob: b38a226065df7f5f23de3efb915383180a0775bc [file] [log] [blame]
Fabien Dessenneedbbdad2019-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
Lokesh Vutladb1f8202019-09-04 16:01:29 +053067/* Basic function to verify ELF64 image format */
68int rproc_elf64_sanity_check(ulong addr, ulong size)
69{
70 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
71 char class;
72
73 if (!addr) {
74 pr_debug("Invalid fw address?\n");
75 return -EFAULT;
76 }
77
78 if (size < sizeof(Elf64_Ehdr)) {
79 pr_debug("Image is too small\n");
80 return -ENOSPC;
81 }
82
83 class = ehdr->e_ident[EI_CLASS];
84
85 if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS64) {
86 pr_debug("Not an executable ELF64 image\n");
87 return -EPROTONOSUPPORT;
88 }
89
90 /* We assume the firmware has the same endianness as the host */
91# ifdef __LITTLE_ENDIAN
92 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
93# else /* BIG ENDIAN */
94 if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
95# endif
96 pr_debug("Unsupported firmware endianness\n");
97 return -EILSEQ;
98 }
99
100 if (size < ehdr->e_shoff + sizeof(Elf64_Shdr)) {
101 pr_debug("Image is too small\n");
102 return -ENOSPC;
103 }
104
105 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
106 pr_debug("Image is corrupted (bad magic)\n");
107 return -EBADF;
108 }
109
110 if (ehdr->e_phnum == 0) {
111 pr_debug("No loadable segments\n");
112 return -ENOEXEC;
113 }
114
115 if (ehdr->e_phoff > size) {
116 pr_debug("Firmware size is too small\n");
117 return -ENOSPC;
118 }
119
120 return 0;
121}
122
Lokesh Vutla8db0a472019-09-04 16:01:30 +0530123/* Basic function to verify ELF image format */
124int rproc_elf_sanity_check(ulong addr, ulong size)
125{
126 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
127
128 if (!addr) {
129 dev_err(dev, "Invalid firmware address\n");
130 return -EFAULT;
131 }
132
133 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
134 return rproc_elf64_sanity_check(addr, size);
135 else
136 return rproc_elf32_sanity_check(addr, size);
137}
138
Lokesh Vutlab506cba2019-09-04 16:01:28 +0530139int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
Fabien Dessenneedbbdad2019-05-31 15:11:33 +0200140{
141 Elf32_Ehdr *ehdr; /* Elf header structure pointer */
142 Elf32_Phdr *phdr; /* Program header structure pointer */
143 const struct dm_rproc_ops *ops;
Lokesh Vutlab506cba2019-09-04 16:01:28 +0530144 unsigned int i, ret;
145
146 ret = rproc_elf32_sanity_check(addr, size);
147 if (ret) {
148 dev_err(dev, "Invalid ELF32 Image %d\n", ret);
149 return ret;
150 }
Fabien Dessenneedbbdad2019-05-31 15:11:33 +0200151
152 ehdr = (Elf32_Ehdr *)addr;
153 phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
154
155 ops = rproc_get_ops(dev);
156
157 /* Load each program header */
158 for (i = 0; i < ehdr->e_phnum; ++i) {
159 void *dst = (void *)(uintptr_t)phdr->p_paddr;
160 void *src = (void *)addr + phdr->p_offset;
161
162 if (phdr->p_type != PT_LOAD)
163 continue;
164
165 if (ops->device_to_virt)
Lokesh Vutlae18166f2019-09-04 16:01:27 +0530166 dst = ops->device_to_virt(dev, (ulong)dst,
167 phdr->p_memsz);
Fabien Dessenneedbbdad2019-05-31 15:11:33 +0200168
169 dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
170 i, dst, phdr->p_filesz);
171 if (phdr->p_filesz)
172 memcpy(dst, src, phdr->p_filesz);
173 if (phdr->p_filesz != phdr->p_memsz)
174 memset(dst + phdr->p_filesz, 0x00,
175 phdr->p_memsz - phdr->p_filesz);
176 flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
177 roundup((unsigned long)dst + phdr->p_filesz,
178 ARCH_DMA_MINALIGN) -
179 rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
180 ++phdr;
181 }
182
183 return 0;
184}
Lokesh Vutladb1f8202019-09-04 16:01:29 +0530185
186int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
187{
188 const struct dm_rproc_ops *ops = rproc_get_ops(dev);
189 u64 da, memsz, filesz, offset;
190 Elf64_Ehdr *ehdr;
191 Elf64_Phdr *phdr;
192 int i, ret = 0;
193 void *ptr;
194
195 dev_dbg(dev, "%s: addr = 0x%lx size = 0x%lx\n", __func__, addr, size);
196
197 if (rproc_elf64_sanity_check(addr, size))
198 return -EINVAL;
199
200 ehdr = (Elf64_Ehdr *)addr;
201 phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
202
203 /* go through the available ELF segments */
204 for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
205 da = phdr->p_paddr;
206 memsz = phdr->p_memsz;
207 filesz = phdr->p_filesz;
208 offset = phdr->p_offset;
209
210 if (phdr->p_type != PT_LOAD)
211 continue;
212
213 dev_dbg(dev, "%s:phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
214 __func__, phdr->p_type, da, memsz, filesz);
215
216 ptr = (void *)(uintptr_t)da;
217 if (ops->device_to_virt) {
218 ptr = ops->device_to_virt(dev, da, phdr->p_memsz);
219 if (!ptr) {
220 dev_err(dev, "bad da 0x%llx mem 0x%llx\n", da,
221 memsz);
222 ret = -EINVAL;
223 break;
224 }
225 }
226
227 if (filesz)
228 memcpy(ptr, (void *)addr + offset, filesz);
229 if (filesz != memsz)
230 memset(ptr + filesz, 0x00, memsz - filesz);
231
232 flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN),
233 roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) -
234 rounddown((ulong)ptr, ARCH_DMA_MINALIGN));
235 }
236
237 return ret;
238}
Lokesh Vutla8db0a472019-09-04 16:01:30 +0530239
240int rproc_elf_load_image(struct udevice *dev, ulong addr, ulong size)
241{
242 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
243
244 if (!addr) {
245 dev_err(dev, "Invalid firmware address\n");
246 return -EFAULT;
247 }
248
249 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
250 return rproc_elf64_load_image(dev, addr, size);
251 else
252 return rproc_elf32_load_image(dev, addr, size);
253}
Lokesh Vutla3275e5d2019-09-04 16:01:31 +0530254
255static ulong rproc_elf32_get_boot_addr(ulong addr)
256{
257 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
258
259 return ehdr->e_entry;
260}
261
262static ulong rproc_elf64_get_boot_addr(ulong addr)
263{
264 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
265
266 return ehdr->e_entry;
267}
268
269ulong rproc_elf_get_boot_addr(struct udevice *dev, ulong addr)
270{
271 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
272
273 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
274 return rproc_elf64_get_boot_addr(addr);
275 else
276 return rproc_elf32_get_boot_addr(addr);
277}