blob: e8026cdfbb4631d122906afb2caa5cae76fb420d [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>
Simon Glass63334482019-11-14 12:57:39 -07006#include <cpu_func.h>
Fabien Dessenneedbbdad2019-05-31 15:11:33 +02007#include <dm.h>
8#include <elf.h>
9#include <remoteproc.h>
10
11/* Basic function to verify ELF32 image format */
12int rproc_elf32_sanity_check(ulong addr, ulong size)
13{
14 Elf32_Ehdr *ehdr;
15 char class;
16
17 if (!addr) {
18 pr_debug("Invalid fw address?\n");
19 return -EFAULT;
20 }
21
22 if (size < sizeof(Elf32_Ehdr)) {
23 pr_debug("Image is too small\n");
24 return -ENOSPC;
25 }
26
27 ehdr = (Elf32_Ehdr *)addr;
28 class = ehdr->e_ident[EI_CLASS];
29
30 if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS32) {
31 pr_debug("Not an executable ELF32 image\n");
32 return -EPROTONOSUPPORT;
33 }
34
35 /* We assume the firmware has the same endianness as the host */
36# ifdef __LITTLE_ENDIAN
37 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
38# else /* BIG ENDIAN */
39 if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
40# endif
41 pr_debug("Unsupported firmware endianness\n");
42 return -EILSEQ;
43 }
44
45 if (size < ehdr->e_shoff + sizeof(Elf32_Shdr)) {
46 pr_debug("Image is too small\n");
47 return -ENOSPC;
48 }
49
50 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
51 pr_debug("Image is corrupted (bad magic)\n");
52 return -EBADF;
53 }
54
55 if (ehdr->e_phnum == 0) {
56 pr_debug("No loadable segments\n");
57 return -ENOEXEC;
58 }
59
60 if (ehdr->e_phoff > size) {
61 pr_debug("Firmware size is too small\n");
62 return -ENOSPC;
63 }
64
65 return 0;
66}
67
Lokesh Vutladb1f8202019-09-04 16:01:29 +053068/* Basic function to verify ELF64 image format */
69int rproc_elf64_sanity_check(ulong addr, ulong size)
70{
71 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
72 char class;
73
74 if (!addr) {
75 pr_debug("Invalid fw address?\n");
76 return -EFAULT;
77 }
78
79 if (size < sizeof(Elf64_Ehdr)) {
80 pr_debug("Image is too small\n");
81 return -ENOSPC;
82 }
83
84 class = ehdr->e_ident[EI_CLASS];
85
86 if (!IS_ELF(*ehdr) || ehdr->e_type != ET_EXEC || class != ELFCLASS64) {
87 pr_debug("Not an executable ELF64 image\n");
88 return -EPROTONOSUPPORT;
89 }
90
91 /* We assume the firmware has the same endianness as the host */
92# ifdef __LITTLE_ENDIAN
93 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
94# else /* BIG ENDIAN */
95 if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB) {
96# endif
97 pr_debug("Unsupported firmware endianness\n");
98 return -EILSEQ;
99 }
100
101 if (size < ehdr->e_shoff + sizeof(Elf64_Shdr)) {
102 pr_debug("Image is too small\n");
103 return -ENOSPC;
104 }
105
106 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
107 pr_debug("Image is corrupted (bad magic)\n");
108 return -EBADF;
109 }
110
111 if (ehdr->e_phnum == 0) {
112 pr_debug("No loadable segments\n");
113 return -ENOEXEC;
114 }
115
116 if (ehdr->e_phoff > size) {
117 pr_debug("Firmware size is too small\n");
118 return -ENOSPC;
119 }
120
121 return 0;
122}
123
Lokesh Vutla8db0a472019-09-04 16:01:30 +0530124/* Basic function to verify ELF image format */
125int rproc_elf_sanity_check(ulong addr, ulong size)
126{
127 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
128
129 if (!addr) {
130 dev_err(dev, "Invalid firmware address\n");
131 return -EFAULT;
132 }
133
134 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
135 return rproc_elf64_sanity_check(addr, size);
136 else
137 return rproc_elf32_sanity_check(addr, size);
138}
139
Lokesh Vutlab506cba2019-09-04 16:01:28 +0530140int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
Fabien Dessenneedbbdad2019-05-31 15:11:33 +0200141{
142 Elf32_Ehdr *ehdr; /* Elf header structure pointer */
143 Elf32_Phdr *phdr; /* Program header structure pointer */
144 const struct dm_rproc_ops *ops;
Lokesh Vutlab506cba2019-09-04 16:01:28 +0530145 unsigned int i, ret;
146
147 ret = rproc_elf32_sanity_check(addr, size);
148 if (ret) {
149 dev_err(dev, "Invalid ELF32 Image %d\n", ret);
150 return ret;
151 }
Fabien Dessenneedbbdad2019-05-31 15:11:33 +0200152
153 ehdr = (Elf32_Ehdr *)addr;
154 phdr = (Elf32_Phdr *)(addr + ehdr->e_phoff);
155
156 ops = rproc_get_ops(dev);
157
158 /* Load each program header */
159 for (i = 0; i < ehdr->e_phnum; ++i) {
160 void *dst = (void *)(uintptr_t)phdr->p_paddr;
161 void *src = (void *)addr + phdr->p_offset;
162
163 if (phdr->p_type != PT_LOAD)
164 continue;
165
166 if (ops->device_to_virt)
Lokesh Vutlae18166f2019-09-04 16:01:27 +0530167 dst = ops->device_to_virt(dev, (ulong)dst,
168 phdr->p_memsz);
Fabien Dessenneedbbdad2019-05-31 15:11:33 +0200169
170 dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n",
171 i, dst, phdr->p_filesz);
172 if (phdr->p_filesz)
173 memcpy(dst, src, phdr->p_filesz);
174 if (phdr->p_filesz != phdr->p_memsz)
175 memset(dst + phdr->p_filesz, 0x00,
176 phdr->p_memsz - phdr->p_filesz);
177 flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN),
178 roundup((unsigned long)dst + phdr->p_filesz,
179 ARCH_DMA_MINALIGN) -
180 rounddown((unsigned long)dst, ARCH_DMA_MINALIGN));
181 ++phdr;
182 }
183
184 return 0;
185}
Lokesh Vutladb1f8202019-09-04 16:01:29 +0530186
187int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size)
188{
189 const struct dm_rproc_ops *ops = rproc_get_ops(dev);
190 u64 da, memsz, filesz, offset;
191 Elf64_Ehdr *ehdr;
192 Elf64_Phdr *phdr;
193 int i, ret = 0;
194 void *ptr;
195
196 dev_dbg(dev, "%s: addr = 0x%lx size = 0x%lx\n", __func__, addr, size);
197
198 if (rproc_elf64_sanity_check(addr, size))
199 return -EINVAL;
200
201 ehdr = (Elf64_Ehdr *)addr;
202 phdr = (Elf64_Phdr *)(addr + (ulong)ehdr->e_phoff);
203
204 /* go through the available ELF segments */
205 for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
206 da = phdr->p_paddr;
207 memsz = phdr->p_memsz;
208 filesz = phdr->p_filesz;
209 offset = phdr->p_offset;
210
211 if (phdr->p_type != PT_LOAD)
212 continue;
213
214 dev_dbg(dev, "%s:phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
215 __func__, phdr->p_type, da, memsz, filesz);
216
217 ptr = (void *)(uintptr_t)da;
218 if (ops->device_to_virt) {
219 ptr = ops->device_to_virt(dev, da, phdr->p_memsz);
220 if (!ptr) {
221 dev_err(dev, "bad da 0x%llx mem 0x%llx\n", da,
222 memsz);
223 ret = -EINVAL;
224 break;
225 }
226 }
227
228 if (filesz)
229 memcpy(ptr, (void *)addr + offset, filesz);
230 if (filesz != memsz)
231 memset(ptr + filesz, 0x00, memsz - filesz);
232
233 flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN),
234 roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) -
235 rounddown((ulong)ptr, ARCH_DMA_MINALIGN));
236 }
237
238 return ret;
239}
Lokesh Vutla8db0a472019-09-04 16:01:30 +0530240
241int rproc_elf_load_image(struct udevice *dev, ulong addr, ulong size)
242{
243 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
244
245 if (!addr) {
246 dev_err(dev, "Invalid firmware address\n");
247 return -EFAULT;
248 }
249
250 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
251 return rproc_elf64_load_image(dev, addr, size);
252 else
253 return rproc_elf32_load_image(dev, addr, size);
254}
Lokesh Vutla3275e5d2019-09-04 16:01:31 +0530255
256static ulong rproc_elf32_get_boot_addr(ulong addr)
257{
258 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
259
260 return ehdr->e_entry;
261}
262
263static ulong rproc_elf64_get_boot_addr(ulong addr)
264{
265 Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
266
267 return ehdr->e_entry;
268}
269
270ulong rproc_elf_get_boot_addr(struct udevice *dev, ulong addr)
271{
272 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
273
274 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
275 return rproc_elf64_get_boot_addr(addr);
276 else
277 return rproc_elf32_get_boot_addr(addr);
278}