blob: 4efed7a02150059e1437fafdcee65e916a0dfd2b [file] [log] [blame]
Liam Girdwood05ef4342018-02-13 20:29:40 +00001/*
2 * Copyright (c) 2017, Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
14 * Keyon Jie <yang.jie@linux.intel.com>
15 */
16
17#include <stdio.h>
18#include <string.h>
19#include "rimage.h"
20#include "cse.h"
21#include "manifest.h"
22
23static int elf_read_sections(struct image *image, struct module *module)
24{
25 Elf32_Ehdr *hdr = &module->hdr;
26 Elf32_Shdr *section = module->section;
27 size_t count;
28 int i, ret;
29 uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR);
30 int man_section_idx;
31
32 /* read in section header */
33 ret = fseek(module->fd, hdr->e_shoff, SEEK_SET);
34 if (ret < 0) {
35 fprintf(stderr, "error: can't seek to %s section header %d\n",
36 module->elf_file, ret);
37 return ret;
38 }
39
40 /* allocate space for each section header */
41 section = calloc(sizeof(Elf32_Shdr), hdr->e_shnum);
42 if (section == NULL)
43 return -ENOMEM;
44 module->section = section;
45
46 /* read in sections */
47 count = fread(section, sizeof(Elf32_Shdr), hdr->e_shnum, module->fd);
48 if (count != hdr->e_shnum) {
49 fprintf(stderr, "error: failed to read %s section header %d\n",
50 module->elf_file, -errno);
51 return -errno;
52 }
53
Liam Girdwood0e26f152018-04-06 21:16:12 +010054 /* read in strings */
55 module->strings = calloc(1, section[hdr->e_shstrndx].sh_size);
56 if (!module->strings) {
57 fprintf(stderr, "error: failed %s to read ELF strings for %d\n",
58 module->elf_file, -errno);
59 return -errno;
60 }
61
62 ret = fseek(module->fd, section[hdr->e_shstrndx].sh_offset, SEEK_SET);
63 if (ret < 0) {
64 fprintf(stderr, "error: can't seek to %s stringss %d\n",
65 module->elf_file, ret);
66 return ret;
67 }
68
69 count = fread(module->strings, 1, section[hdr->e_shstrndx].sh_size,
70 module->fd);
71 if (count != section[hdr->e_shstrndx].sh_size) {
72 fprintf(stderr, "error: failed to read %s strings %d\n",
73 module->elf_file, -errno);
74 return -errno;
75 }
76
Liam Girdwood05ef4342018-02-13 20:29:40 +000077 /* find manifest module data */
78 man_section_idx = elf_find_section(image, module, ".bss");
79 if (man_section_idx < 0) {
Marcin Maka45e9bc42018-05-22 17:07:40 +010080 /* no bss - it is OK for boot_ldr */
81 module->bss_start = 0;
82 module->bss_end = 0;
83 } else {
84 module->bss_index = man_section_idx;
Liam Girdwood05ef4342018-02-13 20:29:40 +000085 }
Liam Girdwood05ef4342018-02-13 20:29:40 +000086
87 fprintf(stdout, " BSS module metadata section at index %d\n",
88 man_section_idx);
89
90 /* parse each section */
91 for (i = 0; i < hdr->e_shnum; i++) {
92
93 /* only write valid sections */
94 if (!(section[i].sh_flags & valid))
95 continue;
96
97 switch (section[i].sh_type) {
98 case SHT_NOBITS:
99 /* bss */
100 module->bss_size += section[i].sh_size;
101 module->num_bss++;
102 break;
103 case SHT_PROGBITS:
104 /* text or data */
105 module->fw_size += section[i].sh_size;
106
107 if (section[i].sh_flags & SHF_EXECINSTR)
108 module->text_size += section[i].sh_size;
109 else
110 module->data_size += section[i].sh_size;
111 break;
112 default:
113 continue;
114 }
115
116 module->num_sections++;
117
118 if (!image->verbose)
119 continue;
120
121 fprintf(stdout, " %s section-%d: \ttype\t 0x%8.8x\n", module->elf_file,
122 i, section[i].sh_type);
123 fprintf(stdout, " %s section-%d: \tflags\t 0x%8.8x\n", module->elf_file,
124 i, section[i].sh_flags);
125 fprintf(stdout, " %s section-%d: \taddr\t 0x%8.8x\n", module->elf_file,
126 i, section[i].sh_addr);
127 fprintf(stdout, " %s section-%d: \toffset\t 0x%8.8x\n", module->elf_file,
128 i, section[i].sh_offset);
129 fprintf(stdout, " %s section-%d: \tsize\t 0x%8.8x\n", module->elf_file,
130 i, section[i].sh_size);
131 fprintf(stdout, " %s section-%d: \tlink\t 0x%8.8x\n", module->elf_file,
132 i, section[i].sh_link);
133 fprintf(stdout, " %s section-%d: \tinfo\t 0x%8.8x\n\n", module->elf_file,
134 i, section[i].sh_info);
135 }
136
137 return 0;
138}
139
140static int elf_read_programs(struct image *image, struct module *module)
141{
142 Elf32_Ehdr *hdr = &module->hdr;
143 Elf32_Phdr *prg = module->prg;
144 size_t count;
145 int i, ret;
146
147 /* read in program header */
148 ret = fseek(module->fd, hdr->e_phoff, SEEK_SET);
149 if (ret < 0) {
150 fprintf(stderr, "error: cant seek to %s program header %d\n",
151 module->elf_file, ret);
152 return ret;
153 }
154
155 /* allocate space for programs */
156 prg = calloc(sizeof(Elf32_Phdr), hdr->e_phnum);
157 if (prg == NULL)
158 return -ENOMEM;
159 module->prg = prg;
160
161 /* read in programs */
162 count = fread(prg, sizeof(Elf32_Phdr), hdr->e_phnum, module->fd);
163 if (count != hdr->e_phnum) {
164 fprintf(stderr, "error: failed to read %s program header %d\n",
165 module->elf_file, -errno);
166 return -errno;
167 }
168
169 /* check each program */
170 for (i = 0; i < hdr->e_phnum; i++) {
171
172 if (prg[i].p_filesz == 0)
173 continue;
174
175 if (!image->verbose)
176 continue;
177
178 fprintf(stdout, "%s program-%d: \ttype\t 0x%8.8x\n",
179 module->elf_file, i, prg[i].p_type);
180 fprintf(stdout, "%s program-%d: \toffset\t 0x%8.8x\n",
181 module->elf_file, i, prg[i].p_offset);
182 fprintf(stdout, "%s program-%d: \tvaddr\t 0x%8.8x\n",
183 module->elf_file, i, prg[i].p_vaddr);
184 fprintf(stdout, "%s program-%d: \tpaddr\t 0x%8.8x\n",
185 module->elf_file, i, prg[i].p_paddr);
186 fprintf(stdout, "%s program-%d: \tfsize\t 0x%8.8x\n",
187 module->elf_file, i, prg[i].p_filesz);
188 fprintf(stdout, "%s program-%d: \tmsize\t 0x%8.8x\n",
189 module->elf_file, i, prg[i].p_memsz);
190 fprintf(stdout, "%s program-%d: \tflags\t 0x%8.8x\n\n",
191 module->elf_file, i, prg[i].p_flags);
192 }
193
194 return 0;
195}
196
197static int elf_read_hdr(struct image *image, struct module *module)
198{
199 Elf32_Ehdr *hdr = &module->hdr;
200 size_t count;
201
202 /* read in elf header */
203 count = fread(hdr, sizeof(*hdr), 1, module->fd);
204 if (count != 1) {
205 fprintf(stderr, "error: failed to read %s elf header %d\n",
206 module->elf_file, -errno);
207 return -errno;
208 }
209
210 if (!image->verbose)
211 return 0;
212
213 fprintf(stdout, "%s elf: \tentry point\t 0x%8.8x\n",
214 module->elf_file, hdr->e_entry);
215 fprintf(stdout, "%s elf: \tprogram offset\t 0x%8.8x\n",
216 module->elf_file, hdr->e_phoff);
217 fprintf(stdout, "%s elf: \tsection offset\t 0x%8.8x\n",
218 module->elf_file, hdr->e_shoff);
219 fprintf(stdout, "%s elf: \tprogram size\t 0x%8.8x\n",
220 module->elf_file, hdr->e_phentsize);
221 fprintf(stdout, "%s elf: \tprogram count\t 0x%8.8x\n",
222 module->elf_file, hdr->e_phnum);
223 fprintf(stdout, "%s elf: \tsection size\t 0x%8.8x\n",
224 module->elf_file, hdr->e_shentsize);
225 fprintf(stdout, "%s elf: \tsection count\t 0x%8.8x\n",
226 module->elf_file, hdr->e_shnum);
227 fprintf(stdout, "%s elf: \tstring index\t 0x%8.8x\n\n",
228 module->elf_file, hdr->e_shstrndx);
229
230 return 0;
231}
232
233int elf_is_rom(struct image *image, Elf32_Shdr *section)
234{
235 uint32_t start, end;
236
237 start = section->sh_addr;
238 end = section->sh_addr + section->sh_size;
239
240 if (start < image->adsp->rom_base ||
241 start > image->adsp->rom_base + image->adsp->rom_size)
242 return 0;
243 if (end < image->adsp->rom_base ||
244 end > image->adsp->rom_base + image->adsp->rom_size)
245 return 0;
246 return 1;
247}
248
249static void elf_module_size(struct image *image, struct module *module,
250 Elf32_Shdr *section, int index)
251{
252 switch (section->sh_type) {
253 case SHT_PROGBITS:
254 /* text or data */
255 if (section->sh_flags & SHF_EXECINSTR) {
256 /* text */
257 if (module->text_start > section->sh_addr)
258 module->text_start = section->sh_addr;
259 if (module->text_end < section->sh_addr + section->sh_size)
260 module->text_end = section->sh_addr + section->sh_size;
261
Liam Girdwood0e26f152018-04-06 21:16:12 +0100262 fprintf(stdout, "\tTEXT\t");
Liam Girdwood05ef4342018-02-13 20:29:40 +0000263 } else {
264 /* initialized data, also calc the writable sections */
265 if (module->data_start > section->sh_addr)
266 module->data_start = section->sh_addr;
267 if (module->data_end < section->sh_addr + section->sh_size)
268 module->data_end = section->sh_addr + section->sh_size;
269
Liam Girdwood0e26f152018-04-06 21:16:12 +0100270 fprintf(stdout, "\tDATA\t");
Liam Girdwood05ef4342018-02-13 20:29:40 +0000271 }
272 break;
273 case SHT_NOBITS:
274 /* bss */
275 if (index == module->bss_index) {
276 /* updated the .bss segment */
277 module->bss_start = section->sh_addr;
278 module->bss_end = section->sh_addr + section->sh_size;
Liam Girdwood0e26f152018-04-06 21:16:12 +0100279 fprintf(stdout, "\tBSS\t");
Liam Girdwood05ef4342018-02-13 20:29:40 +0000280 } else {
Liam Girdwood0e26f152018-04-06 21:16:12 +0100281 fprintf(stdout, "\tHEAP\t");
Liam Girdwood05ef4342018-02-13 20:29:40 +0000282 }
283 break;
284 default:
285 break;
286 }
287}
288
Liam Girdwood7db25d82018-04-12 21:07:35 +0100289static void elf_module_size_reloc(struct image *image, struct module *module,
290 Elf32_Shdr *section, int index)
291{
292 switch (section->sh_type) {
293 case SHT_PROGBITS:
294 /* text or data */
295 if (section->sh_flags & SHF_EXECINSTR) {
296 /* text */
297 module->text_start = 0;
298 module->text_end += section->sh_size;
299
300 fprintf(stdout, "\tTEXT\t");
301 } else {
302 /* initialized data, also calc the writable sections */
303 module->data_start = 0;
304 module->data_end += section->sh_size;
305
306 fprintf(stdout, "\tDATA\t");
307 }
308 break;
309 case SHT_NOBITS:
310 /* bss */
311 if (index == module->bss_index) {
312 /* updated the .bss segment */
313 module->bss_start = section->sh_addr;
314 module->bss_end = section->sh_addr + section->sh_size;
315 fprintf(stdout, "\tBSS\t");
316 } else {
317 fprintf(stdout, "\tHEAP\t");
318 }
319 break;
320 default:
321 break;
322 }
323}
324
Liam Girdwood05ef4342018-02-13 20:29:40 +0000325static void elf_module_limits(struct image *image, struct module *module)
326{
327 Elf32_Shdr *section;
328 uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR);
329 int i;
330
Marcin Maka45e9bc42018-05-22 17:07:40 +0100331 module->text_start = module->data_start = 0xffffffff;
332 module->bss_start = 0;
Liam Girdwood05ef4342018-02-13 20:29:40 +0000333 module->text_end = module->data_end = module->bss_end = 0;
334
335 fprintf(stdout, " Found %d sections, listing valid sections......\n",
336 module->hdr.e_shnum);
337
Liam Girdwood0e26f152018-04-06 21:16:12 +0100338 fprintf(stdout, "\tNo\tStart\t\tEnd\t\tBytes\tType\tName\n");
Liam Girdwood05ef4342018-02-13 20:29:40 +0000339
340 /* iterate all sections and get size of segments */
341 for (i = 0; i < module->hdr.e_shnum; i++) {
342
343 section = &module->section[i];
344
Liam Girdwood7db25d82018-04-12 21:07:35 +0100345 /* module bss can sometimes be missed */
346 if (i != module->bss_index) {
Liam Girdwood05ef4342018-02-13 20:29:40 +0000347
Liam Girdwood7db25d82018-04-12 21:07:35 +0100348 /* only check valid sections */
349 if (!(section->sh_flags & valid))
350 continue;
Liam Girdwood05ef4342018-02-13 20:29:40 +0000351
Liam Girdwood7db25d82018-04-12 21:07:35 +0100352 if (section->sh_size == 0)
353 continue;
354
355 if (elf_is_rom(image, section))
356 continue;
357 }
Liam Girdwood05ef4342018-02-13 20:29:40 +0000358
359 fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t%d", i,
360 section->sh_addr, section->sh_addr + section->sh_size,
361 section->sh_size);
362
363 /* text or data section */
Liam Girdwood7db25d82018-04-12 21:07:35 +0100364 if (image->reloc)
365 elf_module_size_reloc(image, module, section, i);
366 else
367 elf_module_size(image, module, section, i);
Liam Girdwood05ef4342018-02-13 20:29:40 +0000368
Liam Girdwood0e26f152018-04-06 21:16:12 +0100369 /* section name */
370 fprintf(stdout, "%s\n", module->strings + section->sh_name);
Liam Girdwood05ef4342018-02-13 20:29:40 +0000371 }
372
373 fprintf(stdout, "\n");
374}
375
376/* make sure no section overlap from any modules */
377int elf_validate_section(struct image *image, struct module *module,
Liam Girdwood9d5c4662018-02-22 15:40:25 +0000378 Elf32_Shdr *section, int index)
Liam Girdwood05ef4342018-02-13 20:29:40 +0000379{
380 struct module *m;
381 Elf32_Shdr *s;
382 uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR);
383 int i, j;
384
385 /* for each module */
386 for (i = 0; i < image->num_modules; i++) {
387 m = &image->module[i];
388
Liam Girdwood05ef4342018-02-13 20:29:40 +0000389 /* for each section */
390 for (j = 0; j < m->hdr.e_shnum; j++) {
391 s = &m->section[j];
392
393 if (s == section)
394 continue;
395
396 /* only check valid sections */
Liam Girdwood9d5c4662018-02-22 15:40:25 +0000397 if (!(s->sh_flags & valid))
Liam Girdwood05ef4342018-02-13 20:29:40 +0000398 continue;
399
Liam Girdwood9d5c4662018-02-22 15:40:25 +0000400 if (s->sh_size == 0)
Liam Girdwood05ef4342018-02-13 20:29:40 +0000401 continue;
402
Liam Girdwood9d5c4662018-02-22 15:40:25 +0000403 /* is section start non overlapping ? */
Liam Girdwood05ef4342018-02-13 20:29:40 +0000404 if (section->sh_addr >= s->sh_addr &&
Liam Girdwood9d5c4662018-02-22 15:40:25 +0000405 section->sh_addr <
406 s->sh_addr + s->sh_size) {
407 goto err;
408 }
409
410 /* is section end non overlapping ? */
411 if (section->sh_addr + section->sh_size > s->sh_addr &&
Liam Girdwood05ef4342018-02-13 20:29:40 +0000412 section->sh_addr + section->sh_size <=
413 s->sh_addr + s->sh_size) {
414 goto err;
415 }
416 }
417 }
418
419 return 0;
420
421err:
Liam Girdwood9d5c4662018-02-22 15:40:25 +0000422 fprintf(stderr, "error: section overlap between %s:%d and %s:%d\n",
423 module->elf_file, index, m->elf_file, j);
Liam Girdwood05ef4342018-02-13 20:29:40 +0000424 fprintf(stderr, " [0x%x : 0x%x] overlaps with [0x%x :0x%x]\n",
425 section->sh_addr, section->sh_addr + section->sh_size,
426 s->sh_addr, s->sh_addr + s->sh_size);
427 return -EINVAL;
428}
429
430/* make sure no section overlaps from any modules */
431int elf_validate_modules(struct image *image)
432{
433 struct module *module;
434 Elf32_Shdr *section;
435 uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR);
436 int i, j, ret;
437
Liam Girdwood7db25d82018-04-12 21:07:35 +0100438 /* relocatable modules have no physical addresses until runtime */
439 if (image->reloc)
440 return 0;
441
Liam Girdwood05ef4342018-02-13 20:29:40 +0000442 /* for each module */
443 for (i = 0; i < image->num_modules; i++) {
444 module = &image->module[i];
445
446 /* for each section */
447 for (j = 0; j < module->hdr.e_shnum; j++) {
448 section = &module->section[j];
449
450 /* only check valid sections */
451 if (!(section->sh_flags & valid))
452 continue;
453
454 if (section->sh_size == 0)
455 continue;
456
457 /* is section non overlapping ? */
Liam Girdwood9d5c4662018-02-22 15:40:25 +0000458 ret = elf_validate_section(image, module, section, j);
Liam Girdwood05ef4342018-02-13 20:29:40 +0000459 if (ret < 0)
460 return ret;
461 }
462 }
463
464 return 0;
465}
466
467int elf_find_section(struct image *image, struct module *module,
468 const char *name)
469{
470 Elf32_Ehdr *hdr = &module->hdr;
471 Elf32_Shdr *section, *s;
472 char *buffer;
473 size_t count;
474 int ret, i;
475
476 section = &module->section[hdr->e_shstrndx];
477
478 /* alloc data data */
479 buffer = calloc(1, section->sh_size);
480 if (buffer == NULL)
481 return -ENOMEM;
482
483 /* read in section string data */
484 ret = fseek(module->fd, section->sh_offset, SEEK_SET);
485 if (ret < 0) {
486 fprintf(stderr, "error: cant seek to string section %d\n", ret);
487 goto out;
488 }
489
490 count = fread(buffer, 1, section->sh_size, module->fd);
491 if (count != section->sh_size) {
492 fprintf(stderr, "error: can't read string section %d\n", -errno);
493 ret = -errno;
494 goto out;
495 }
496
497 /* find section with name */
498 for (i = 0; i < hdr->e_shnum; i++) {
499 s = &module->section[i];
500 if (!strcmp(name, buffer + s->sh_name)) {
501 ret = i;
502 goto out;
503 }
504 }
505
506 fprintf(stderr, "error: can't find section %s in module %s\n", name,
507 module->elf_file);
508 ret = -EINVAL;
509
510out:
511 free(buffer);
512 return ret;
513}
514
515int elf_parse_module(struct image *image, int module_index, const char *name)
516{
517 struct module *module;
518 uint32_t rem;
519 int ret = 0;
520
521 /* validate module index */
522 if (module_index >= MAX_MODULES) {
523 fprintf(stderr, "error: too any modules\n");
524 return -EINVAL;
525 }
526
527 module = &image->module[module_index];
528
529 /* open the elf input file */
530 module->fd = fopen(name, "r");
531 if (module->fd == NULL) {
532 fprintf(stderr, "error: unable to open %s for reading %d\n",
533 name, errno);
534 return -EINVAL;
535 }
536 module->elf_file = name;
537
Liam Girdwood7db25d82018-04-12 21:07:35 +0100538 /* get file size */
539 ret = fseek(module->fd, 0, SEEK_END);
540 if (ret < 0)
541 goto hdr_err;
542 module->file_size = ftell(module->fd);
543 ret = fseek(module->fd, 0, SEEK_SET);
544 if (ret < 0)
545 goto hdr_err;
546
Liam Girdwood05ef4342018-02-13 20:29:40 +0000547 /* read in elf header */
548 ret = elf_read_hdr(image, module);
549 if (ret < 0)
550 goto hdr_err;
551
552 /* read in programs */
553 ret = elf_read_programs(image, module);
554 if (ret < 0) {
555 fprintf(stderr, "error: failed to read program sections %d\n",
556 ret);
557 goto hdr_err;
558 }
559
560 /* read sections */
561 ret = elf_read_sections(image, module);
562 if (ret < 0) {
563 fprintf(stderr, "error: failed to read base sections %d\n",
564 ret);
565 goto sec_err;
566 }
567
568 /* check limits */
569 elf_module_limits(image, module);
570
571 elf_find_section(image, module, "");
572
573 fprintf(stdout, " module: input size %d (0x%x) bytes %d sections\n",
574 module->fw_size, module->fw_size, module->num_sections);
575 fprintf(stdout, " module: text %d (0x%x) bytes\n"
576 " data %d (0x%x) bytes\n"
577 " bss %d (0x%x) bytes\n\n",
578 module->text_size, module->text_size,
579 module->data_size, module->data_size,
580 module->bss_size, module->bss_size);
581
582 /* file sizes round up to nearest page */
583 module->text_file_size = module->text_end - module->text_start;
584 rem = module->text_file_size % MAN_PAGE_SIZE;
585 if (rem)
586 module->text_file_size += MAN_PAGE_SIZE - rem;
587
Liam Girdwood05ef4342018-02-13 20:29:40 +0000588 /* data section */
589 module->data_file_size = module->data_end - module->data_start;
590 rem = module->data_file_size % MAN_PAGE_SIZE;
591 if (rem)
592 module->data_file_size += MAN_PAGE_SIZE - rem;
593
594 /* bss section */
595 module->bss_file_size = module->bss_end - module->bss_start;
596 rem = module->bss_file_size % MAN_PAGE_SIZE;
597 if (rem)
598 module->bss_file_size += MAN_PAGE_SIZE - rem;
599
600 return 0;
601
602sec_err:
603 free(module->prg);
604hdr_err:
605 fclose(module->fd);
606
607 return ret;
608}
609
610void elf_free_module(struct image *image, int module_index)
611{
612 struct module *module = &image->module[module_index];
613
614 free(module->prg);
615 free(module->section);
Liam Girdwood0e26f152018-04-06 21:16:12 +0100616 free(module->strings);
Liam Girdwood05ef4342018-02-13 20:29:40 +0000617 fclose(module->fd);
618}