Merge tag 'dm-pull-3dec19' of https://gitlab.denx.de/u-boot/custodians/u-boot-dm
[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
11 /* Basic function to verify ELF32 image format */
12 int 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
68 /* Basic function to verify ELF64 image format */
69 int 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
124 /* Basic function to verify ELF image format */
125 int 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
140 int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size)
141 {
142         Elf32_Ehdr *ehdr; /* Elf header structure pointer */
143         Elf32_Phdr *phdr; /* Program header structure pointer */
144         const struct dm_rproc_ops *ops;
145         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         }
152
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)
167                         dst = ops->device_to_virt(dev, (ulong)dst,
168                                                   phdr->p_memsz);
169
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 }
186
187 int 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 }
240
241 int 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 }
255
256 static ulong rproc_elf32_get_boot_addr(ulong addr)
257 {
258         Elf32_Ehdr *ehdr = (Elf32_Ehdr *)addr;
259
260         return ehdr->e_entry;
261 }
262
263 static ulong rproc_elf64_get_boot_addr(ulong addr)
264 {
265         Elf64_Ehdr *ehdr = (Elf64_Ehdr *)addr;
266
267         return ehdr->e_entry;
268 }
269
270 ulong 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 }