hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/remoteproc/remoteproc_elf_loader.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Remote Processor Framework Elf loader
34 *
....@@ -12,15 +13,6 @@
1213 * Robert Tivy <rtivy@ti.com>
1314 * Armando Uribe De Leon <x0095078@ti.com>
1415 * Sjur Brændeland <sjur.brandeland@stericsson.com>
15
- *
16
- * This program is free software; you can redistribute it and/or
17
- * modify it under the terms of the GNU General Public License
18
- * version 2 as published by the Free Software Foundation.
19
- *
20
- * This program is distributed in the hope that it will be useful,
21
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
22
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
- * GNU General Public License for more details.
2416 */
2517
2618 #define pr_fmt(fmt) "%s: " fmt, __func__
....@@ -31,20 +23,29 @@
3123 #include <linux/elf.h>
3224
3325 #include "remoteproc_internal.h"
26
+#include "remoteproc_elf_helpers.h"
3427
3528 /**
36
- * rproc_elf_sanity_check() - Sanity Check ELF firmware image
29
+ * rproc_elf_sanity_check() - Sanity Check for ELF32/ELF64 firmware image
3730 * @rproc: the remote processor handle
3831 * @fw: the ELF firmware image
3932 *
40
- * Make sure this fw image is sane.
33
+ * Make sure this fw image is sane (ie a correct ELF32/ELF64 file).
4134 */
4235 int rproc_elf_sanity_check(struct rproc *rproc, const struct firmware *fw)
4336 {
4437 const char *name = rproc->firmware;
4538 struct device *dev = &rproc->dev;
39
+ /*
40
+ * Elf files are beginning with the same structure. Thus, to simplify
41
+ * header parsing, we can use the elf32_hdr one for both elf64 and
42
+ * elf32.
43
+ */
4644 struct elf32_hdr *ehdr;
45
+ u32 elf_shdr_get_size;
46
+ u64 phoff, shoff;
4747 char class;
48
+ u16 phnum;
4849
4950 if (!fw) {
5051 dev_err(dev, "failed to load %s\n", name);
....@@ -58,10 +59,19 @@
5859
5960 ehdr = (struct elf32_hdr *)fw->data;
6061
61
- /* We only support ELF32 at this point */
62
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
63
+ dev_err(dev, "Image is corrupted (bad magic)\n");
64
+ return -EINVAL;
65
+ }
66
+
6267 class = ehdr->e_ident[EI_CLASS];
63
- if (class != ELFCLASS32) {
68
+ if (class != ELFCLASS32 && class != ELFCLASS64) {
6469 dev_err(dev, "Unsupported class: %d\n", class);
70
+ return -EINVAL;
71
+ }
72
+
73
+ if (class == ELFCLASS64 && fw->size < sizeof(struct elf64_hdr)) {
74
+ dev_err(dev, "elf64 header is too small\n");
6575 return -EINVAL;
6676 }
6777
....@@ -75,25 +85,28 @@
7585 return -EINVAL;
7686 }
7787
78
- if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) {
88
+ phoff = elf_hdr_get_e_phoff(class, fw->data);
89
+ shoff = elf_hdr_get_e_shoff(class, fw->data);
90
+ phnum = elf_hdr_get_e_phnum(class, fw->data);
91
+ elf_shdr_get_size = elf_size_of_shdr(class);
92
+
93
+ if (fw->size < shoff + elf_shdr_get_size) {
7994 dev_err(dev, "Image is too small\n");
8095 return -EINVAL;
8196 }
8297
83
- if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
84
- dev_err(dev, "Image is corrupted (bad magic)\n");
85
- return -EINVAL;
86
- }
87
-
88
- if (ehdr->e_phnum == 0) {
98
+ if (phnum == 0) {
8999 dev_err(dev, "No loadable segments\n");
90100 return -EINVAL;
91101 }
92102
93
- if (ehdr->e_phoff > fw->size) {
103
+ if (phoff > fw->size) {
94104 dev_err(dev, "Firmware size is too small\n");
95105 return -EINVAL;
96106 }
107
+
108
+ dev_dbg(dev, "Firmware is an elf%d file\n",
109
+ class == ELFCLASS32 ? 32 : 64);
97110
98111 return 0;
99112 }
....@@ -110,11 +123,9 @@
110123 * Note that the boot address is not a configurable property of all remote
111124 * processors. Some will always boot at a specific hard-coded address.
112125 */
113
-u32 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
126
+u64 rproc_elf_get_boot_addr(struct rproc *rproc, const struct firmware *fw)
114127 {
115
- struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
116
-
117
- return ehdr->e_entry;
128
+ return elf_hdr_get_e_entry(fw_elf_get_class(fw), fw->data);
118129 }
119130 EXPORT_SYMBOL(rproc_elf_get_boot_addr);
120131
....@@ -145,53 +156,70 @@
145156 int rproc_elf_load_segments(struct rproc *rproc, const struct firmware *fw)
146157 {
147158 struct device *dev = &rproc->dev;
148
- struct elf32_hdr *ehdr;
149
- struct elf32_phdr *phdr;
159
+ const void *ehdr, *phdr;
150160 int i, ret = 0;
161
+ u16 phnum;
151162 const u8 *elf_data = fw->data;
163
+ u8 class = fw_elf_get_class(fw);
164
+ u32 elf_phdr_get_size = elf_size_of_phdr(class);
152165
153
- ehdr = (struct elf32_hdr *)elf_data;
154
- phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
166
+ ehdr = elf_data;
167
+ phnum = elf_hdr_get_e_phnum(class, ehdr);
168
+ phdr = elf_data + elf_hdr_get_e_phoff(class, ehdr);
155169
156170 /* go through the available ELF segments */
157
- for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
158
- u32 da = phdr->p_paddr;
159
- u32 memsz = phdr->p_memsz;
160
- u32 filesz = phdr->p_filesz;
161
- u32 offset = phdr->p_offset;
171
+ for (i = 0; i < phnum; i++, phdr += elf_phdr_get_size) {
172
+ u64 da = elf_phdr_get_p_paddr(class, phdr);
173
+ u64 memsz = elf_phdr_get_p_memsz(class, phdr);
174
+ u64 filesz = elf_phdr_get_p_filesz(class, phdr);
175
+ u64 offset = elf_phdr_get_p_offset(class, phdr);
176
+ u32 type = elf_phdr_get_p_type(class, phdr);
177
+ bool is_iomem = false;
162178 void *ptr;
163179
164
- if (phdr->p_type != PT_LOAD)
180
+ if (type != PT_LOAD)
165181 continue;
166182
167
- dev_dbg(dev, "phdr: type %d da 0x%x memsz 0x%x filesz 0x%x\n",
168
- phdr->p_type, da, memsz, filesz);
183
+ dev_dbg(dev, "phdr: type %d da 0x%llx memsz 0x%llx filesz 0x%llx\n",
184
+ type, da, memsz, filesz);
169185
170186 if (filesz > memsz) {
171
- dev_err(dev, "bad phdr filesz 0x%x memsz 0x%x\n",
187
+ dev_err(dev, "bad phdr filesz 0x%llx memsz 0x%llx\n",
172188 filesz, memsz);
173189 ret = -EINVAL;
174190 break;
175191 }
176192
177193 if (offset + filesz > fw->size) {
178
- dev_err(dev, "truncated fw: need 0x%x avail 0x%zx\n",
194
+ dev_err(dev, "truncated fw: need 0x%llx avail 0x%zx\n",
179195 offset + filesz, fw->size);
180196 ret = -EINVAL;
181197 break;
182198 }
183199
200
+ if (!rproc_u64_fit_in_size_t(memsz)) {
201
+ dev_err(dev, "size (%llx) does not fit in size_t type\n",
202
+ memsz);
203
+ ret = -EOVERFLOW;
204
+ break;
205
+ }
206
+
184207 /* grab the kernel address for this device address */
185
- ptr = rproc_da_to_va(rproc, da, memsz);
208
+ ptr = rproc_da_to_va(rproc, da, memsz, &is_iomem);
186209 if (!ptr) {
187
- dev_err(dev, "bad phdr da 0x%x mem 0x%x\n", da, memsz);
210
+ dev_err(dev, "bad phdr da 0x%llx mem 0x%llx\n", da,
211
+ memsz);
188212 ret = -EINVAL;
189213 break;
190214 }
191215
192216 /* put the segment where the remote processor expects it */
193
- if (phdr->p_filesz)
194
- memcpy(ptr, elf_data + phdr->p_offset, filesz);
217
+ if (filesz) {
218
+ if (is_iomem)
219
+ memcpy_toio((void __iomem *)ptr, elf_data + offset, filesz);
220
+ else
221
+ memcpy(ptr, elf_data + offset, filesz);
222
+ }
195223
196224 /*
197225 * Zero out remaining memory for this segment.
....@@ -200,32 +228,47 @@
200228 * did this for us. albeit harmless, we may consider removing
201229 * this.
202230 */
203
- if (memsz > filesz)
204
- memset(ptr + filesz, 0, memsz - filesz);
231
+ if (memsz > filesz) {
232
+ if (is_iomem)
233
+ memset_io((void __iomem *)(ptr + filesz), 0, memsz - filesz);
234
+ else
235
+ memset(ptr + filesz, 0, memsz - filesz);
236
+ }
205237 }
206238
207239 return ret;
208240 }
209241 EXPORT_SYMBOL(rproc_elf_load_segments);
210242
211
-static struct elf32_shdr *
212
-find_table(struct device *dev, struct elf32_hdr *ehdr, size_t fw_size)
243
+static const void *
244
+find_table(struct device *dev, const struct firmware *fw)
213245 {
214
- struct elf32_shdr *shdr;
246
+ const void *shdr, *name_table_shdr;
215247 int i;
216248 const char *name_table;
217249 struct resource_table *table = NULL;
218
- const u8 *elf_data = (void *)ehdr;
250
+ const u8 *elf_data = (void *)fw->data;
251
+ u8 class = fw_elf_get_class(fw);
252
+ size_t fw_size = fw->size;
253
+ const void *ehdr = elf_data;
254
+ u16 shnum = elf_hdr_get_e_shnum(class, ehdr);
255
+ u32 elf_shdr_get_size = elf_size_of_shdr(class);
256
+ u16 shstrndx = elf_hdr_get_e_shstrndx(class, ehdr);
219257
220258 /* look for the resource table and handle it */
221
- shdr = (struct elf32_shdr *)(elf_data + ehdr->e_shoff);
222
- name_table = elf_data + shdr[ehdr->e_shstrndx].sh_offset;
259
+ /* First, get the section header according to the elf class */
260
+ shdr = elf_data + elf_hdr_get_e_shoff(class, ehdr);
261
+ /* Compute name table section header entry in shdr array */
262
+ name_table_shdr = shdr + (shstrndx * elf_shdr_get_size);
263
+ /* Finally, compute the name table section address in elf */
264
+ name_table = elf_data + elf_shdr_get_sh_offset(class, name_table_shdr);
223265
224
- for (i = 0; i < ehdr->e_shnum; i++, shdr++) {
225
- u32 size = shdr->sh_size;
226
- u32 offset = shdr->sh_offset;
266
+ for (i = 0; i < shnum; i++, shdr += elf_shdr_get_size) {
267
+ u64 size = elf_shdr_get_sh_size(class, shdr);
268
+ u64 offset = elf_shdr_get_sh_offset(class, shdr);
269
+ u32 name = elf_shdr_get_sh_name(class, shdr);
227270
228
- if (strcmp(name_table + shdr->sh_name, ".resource_table"))
271
+ if (strcmp(name_table + name, ".resource_table"))
229272 continue;
230273
231274 table = (struct resource_table *)(elf_data + offset);
....@@ -255,8 +298,7 @@
255298 }
256299
257300 /* make sure the offsets array isn't truncated */
258
- if (table->num * sizeof(table->offset[0]) +
259
- sizeof(struct resource_table) > size) {
301
+ if (struct_size(table, offset, table->num) > size) {
260302 dev_err(dev, "resource table incomplete\n");
261303 return NULL;
262304 }
....@@ -279,21 +321,21 @@
279321 */
280322 int rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw)
281323 {
282
- struct elf32_hdr *ehdr;
283
- struct elf32_shdr *shdr;
324
+ const void *shdr;
284325 struct device *dev = &rproc->dev;
285326 struct resource_table *table = NULL;
286327 const u8 *elf_data = fw->data;
287328 size_t tablesz;
329
+ u8 class = fw_elf_get_class(fw);
330
+ u64 sh_offset;
288331
289
- ehdr = (struct elf32_hdr *)elf_data;
290
-
291
- shdr = find_table(dev, ehdr, fw->size);
332
+ shdr = find_table(dev, fw);
292333 if (!shdr)
293334 return -EINVAL;
294335
295
- table = (struct resource_table *)(elf_data + shdr->sh_offset);
296
- tablesz = shdr->sh_size;
336
+ sh_offset = elf_shdr_get_sh_offset(class, shdr);
337
+ table = (struct resource_table *)(elf_data + sh_offset);
338
+ tablesz = elf_shdr_get_sh_size(class, shdr);
297339
298340 /*
299341 * Create a copy of the resource table. When a virtio device starts
....@@ -326,13 +368,24 @@
326368 struct resource_table *rproc_elf_find_loaded_rsc_table(struct rproc *rproc,
327369 const struct firmware *fw)
328370 {
329
- struct elf32_hdr *ehdr = (struct elf32_hdr *)fw->data;
330
- struct elf32_shdr *shdr;
371
+ const void *shdr;
372
+ u64 sh_addr, sh_size;
373
+ u8 class = fw_elf_get_class(fw);
374
+ struct device *dev = &rproc->dev;
331375
332
- shdr = find_table(&rproc->dev, ehdr, fw->size);
376
+ shdr = find_table(&rproc->dev, fw);
333377 if (!shdr)
334378 return NULL;
335379
336
- return rproc_da_to_va(rproc, shdr->sh_addr, shdr->sh_size);
380
+ sh_addr = elf_shdr_get_sh_addr(class, shdr);
381
+ sh_size = elf_shdr_get_sh_size(class, shdr);
382
+
383
+ if (!rproc_u64_fit_in_size_t(sh_size)) {
384
+ dev_err(dev, "size (%llx) does not fit in size_t type\n",
385
+ sh_size);
386
+ return NULL;
387
+ }
388
+
389
+ return rproc_da_to_va(rproc, sh_addr, sh_size, NULL);
337390 }
338391 EXPORT_SYMBOL(rproc_elf_find_loaded_rsc_table);