1 /*
2 * Copyright (c) 2014, Mentor Graphics Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. Neither the name of Mentor Graphics Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from this
15 * software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
30 #include "openamp/elf_loader.h"
32 /* Local functions. */
34 static int elf_loader_get_needed_sections(struct elf_decode_info *elf_info);
35 static int elf_loader_relocs_specific(struct elf_decode_info *elf_info,
36 Elf32_Shdr * section);
37 static void *elf_loader_get_entry_point_address(struct elf_decode_info
38 *elf_info);
39 static int elf_loader_relocate_link(struct elf_decode_info *elf_info);
40 static int elf_loader_seek_and_read(void *firmware, void *destination,
41 Elf32_Off offset, Elf32_Word size);
42 static int elf_loader_read_headers(void *firmware,
43 struct elf_decode_info *elf_info);
44 static int elf_loader_load_sections(void *firmware,
45 struct elf_decode_info *elf_info);
46 static int elf_loader_get_decode_info(void *firmware,
47 struct elf_decode_info *elf_info);
48 static int elf_loader_reloc_entry(struct elf_decode_info *elf_info,
49 Elf32_Rel * rel_entry);
50 static Elf32_Addr elf_loader_get_dynamic_symbol_addr(struct elf_decode_info
51 *elf_info, int index);
53 /**
54 * elf_loader_init
55 *
56 * Initializes ELF loader.
57 *
58 * @param loader - pointer to remoteproc loader
59 *
60 * @return - 0 if success, error otherwise
61 */
62 int elf_loader_init(struct remoteproc_loader *loader)
63 {
65 /* Initialize loader function table */
66 loader->load_firmware = elf_loader_load_remote_firmware;
67 loader->retrieve_entry = elf_loader_retrieve_entry_point;
68 loader->retrieve_rsc = elf_loader_retrieve_resource_section;
69 loader->attach_firmware = elf_loader_attach_firmware;
70 loader->detach_firmware = elf_loader_detach_firmware;
71 loader->retrieve_load_addr = elf_get_load_address;
73 return RPROC_SUCCESS;
74 }
76 /**
77 * elf_loader_attach_firmware
78 *
79 * Attaches an ELF firmware to the loader
80 *
81 * @param loader - pointer to remoteproc loader
82 * @param firmware - pointer to the firmware start location
83 *
84 * @return - 0 if success, error otherwise
85 */
86 int elf_loader_attach_firmware(struct remoteproc_loader *loader, void *firmware)
87 {
89 struct elf_decode_info *elf_info;
90 int status;
92 /* Allocate memory for decode info structure. */
93 elf_info = env_allocate_memory(sizeof(struct elf_decode_info));
95 if (!elf_info) {
96 return RPROC_ERR_NO_MEM;
97 }
99 /* Clear the ELF decode struct. */
100 env_memset(elf_info, 0, sizeof(struct elf_decode_info));
102 /* Get the essential information to decode the ELF. */
103 status = elf_loader_get_decode_info(firmware, elf_info);
105 if (status) {
106 /* Free memory. */
107 env_free_memory(elf_info);
108 return status;
109 }
111 elf_info->firmware = firmware;
112 loader->fw_decode_info = elf_info;
114 return status;
115 }
117 /**
118 * elf_loader_detach_firmware
119 *
120 * Detaches ELF firmware from the loader
121 *
122 * @param loader - pointer to remoteproc loader
123 *
124 * @return - 0 if success, error otherwise
125 */
126 int elf_loader_detach_firmware(struct remoteproc_loader *loader)
127 {
129 struct elf_decode_info *elf_info =
130 (struct elf_decode_info *)loader->fw_decode_info;
131 if (elf_info) {
132 /* Free memory. */
133 env_free_memory(elf_info->shstrtab);
134 env_free_memory(elf_info->section_headers_start);
135 env_free_memory(elf_info);
136 }
138 return RPROC_SUCCESS;
139 }
141 /**
142 * elf_loader_retrieve_entry_point
143 *
144 * Retrieves the ELF entrypoint.
145 *
146 * @param loader - pointer to remoteproc loader
147 *
148 * @return - entrypoint
149 */
150 void *elf_loader_retrieve_entry_point(struct remoteproc_loader *loader)
151 {
153 return elf_loader_get_entry_point_address((struct elf_decode_info *)
154 loader->fw_decode_info);
155 }
157 /**
158 * elf_loader_retrieve_resource_section
159 *
160 * Retrieves the resource section.
161 *
162 * @param loader - pointer to remoteproc loader
163 * @param size - pointer to contain the size of the section
164 *
165 * @return - pointer to resource section
166 */
167 void *elf_loader_retrieve_resource_section(struct remoteproc_loader *loader,
168 unsigned int *size)
169 {
171 Elf32_Shdr *rsc_header;
172 void *resource_section = NULL;
173 struct elf_decode_info *elf_info =
174 (struct elf_decode_info *)loader->fw_decode_info;
176 if (elf_info->rsc) {
177 /* Retrieve resource section header. */
178 rsc_header = elf_info->rsc;
179 /* Retrieve resource section size. */
180 *size = rsc_header->sh_size;
182 /* Locate the start of resource section. */
183 resource_section = (void *)((unsigned int)elf_info->firmware
184 + rsc_header->sh_offset);
185 }
187 /* Return the address of resource section. */
188 return resource_section;
189 }
191 /**
192 * elf_loader_load_remote_firmware
193 *
194 * Loads the ELF firmware.
195 *
196 * @param loader - pointer to remoteproc loader
197 *
198 * @return - 0 if success, error otherwise
199 */
200 int elf_loader_load_remote_firmware(struct remoteproc_loader *loader)
201 {
203 struct elf_decode_info *elf_info =
204 (struct elf_decode_info *)loader->fw_decode_info;
205 int status;
207 /* Load ELF sections. */
208 status = elf_loader_load_sections(elf_info->firmware, elf_info);
210 if (!status) {
212 /* Perform dynamic relocations if needed. */
213 status = elf_loader_relocate_link(elf_info);
214 }
216 return status;
217 }
219 /**
220 * elf_get_load_address
221 *
222 * Provides firmware load address.
223 *
224 * @param loader - pointer to remoteproc loader
225 *
226 * @return - load address pointer
227 */
228 void *elf_get_load_address(struct remoteproc_loader *loader)
229 {
231 struct elf_decode_info *elf_info =
232 (struct elf_decode_info *)loader->fw_decode_info;
233 int status = 0;
234 Elf32_Shdr *current = (Elf32_Shdr *) (elf_info->section_headers_start);
236 /* Traverse all sections except the reserved null section. */
237 int section_count = elf_info->elf_header.e_shnum - 1;
238 while ((section_count > 0) && (status == 0)) {
239 /* Compute the pointer to section header. */
240 current = (Elf32_Shdr *) (((unsigned char *)current)
241 + elf_info->elf_header.e_shentsize);
242 /* Get the name of current section. */
243 char *current_name = elf_info->shstrtab + current->sh_name;
244 if (!env_strcmp(current_name, ".text")) {
245 return ((void *)(current->sh_addr));
246 }
247 /* Move to the next section. */
248 section_count--;
249 }
251 return (RPROC_ERR_PTR);
252 }
254 /**
255 * elf_loader_get_needed_sections
256 *
257 * Retrieves the sections we need during the load and link from the
258 * section headers list.
259 *
260 * @param elf_info - ELF object decode info container.
261 *
262 * @return- Pointer to the ELF section header.
263 */
265 static int elf_loader_get_needed_sections(struct elf_decode_info *elf_info)
266 {
267 Elf32_Shdr *current = (Elf32_Shdr *) (elf_info->section_headers_start);
269 /* We are interested in the following sections:
270 .dynsym
271 .dynstr
272 .rel.plt
273 .rel.dyn
274 */
275 int sections_to_find = 5;
277 /* Search for sections but skip the reserved null section. */
279 int section_count = elf_info->elf_header.e_shnum - 1;
280 while ((section_count > 0) && (sections_to_find > 0)) {
281 /* Compute the section header pointer. */
282 current = (Elf32_Shdr *) (((unsigned char *)current)
283 + elf_info->elf_header.e_shentsize);
285 /* Get the name of current section. */
286 char *current_name = elf_info->shstrtab + current->sh_name;
288 /* Proceed if the section is allocatable and is not executable. */
289 if ((current->sh_flags & SHF_ALLOC)
290 && !(current->sh_flags & SHF_EXECINSTR)) {
291 /* Check for '.dynsym' or '.dynstr' or '.rel.plt' or '.rel.dyn'. */
292 if (*current_name == '.') {
293 current_name++;
295 /* Check for '.dynsym' or 'dynstr'. */
296 if (*current_name == 'd') {
297 current_name++;
299 /* Check for '.dynsym'. */
300 if (env_strncmp
301 (current_name, "ynsym", 5) == 0) {
302 elf_info->dynsym = current;
303 sections_to_find--;
304 }
306 /* Check for '.dynstr'. */
307 else if (env_strncmp
308 (current_name, "ynstr",
309 5) == 0) {
310 elf_info->dynstr = current;
311 sections_to_find--;
312 }
313 }
315 /* Check for '.rel.plt' or '.rel.dyn'. */
316 else if (*current_name == 'r') {
317 current_name++;
319 /* Check for '.rel.plt'. */
320 if (env_strncmp
321 (current_name, "el.plt", 6) == 0) {
322 elf_info->rel_plt = current;
323 sections_to_find--;
324 }
326 /* Check for '.rel.dyn'. */
327 else if (env_strncmp
328 (current_name, "el.dyn",
329 6) == 0) {
330 elf_info->rel_dyn = current;
331 sections_to_find--;
332 }
334 /* Check for '.resource_table'. */
335 else if (env_strncmp
336 (current_name, "esource_table",
337 13)
338 == 0) {
339 elf_info->rsc = current;
340 sections_to_find--;
341 }
342 }
343 }
344 }
346 /* Move to the next section. */
347 section_count--;
348 }
350 /* Return remaining sections section. */
351 return (sections_to_find);
352 }
354 /**
355 * elf_loader_relocs_specific
356 *
357 * Processes the relocations contained in the specified section.
358 *
359 * @param elf_info - elf decoding information.
360 * @param section - header of the specified relocation section.
361 *
362 * @return - 0 if success, error otherwise
363 */
364 static int elf_loader_relocs_specific(struct elf_decode_info *elf_info,
365 Elf32_Shdr * section)
366 {
368 unsigned char *section_load_addr = (unsigned char *)section->sh_addr;
369 int status = 0;
370 unsigned int i;
372 /* Check the section type. */
373 if (section->sh_type == SHT_REL) {
374 /* Traverse the list of relocation entries contained in the section. */
375 for (i = 0; (i < section->sh_size) && (status == 0);
376 i += section->sh_entsize) {
377 /* Compute the relocation entry address. */
378 Elf32_Rel *rel_entry =
379 (Elf32_Rel *) (section_load_addr + i);
381 /* Process the relocation entry. */
382 status = elf_loader_reloc_entry(elf_info, rel_entry);
383 }
384 }
386 /* Return status to caller. */
387 return (status);
388 }
390 /**
391 * elf_loader_get_entry_point_address
392 *
393 * Retrieves the entry point address from the specified ELF object.
394 *
395 * @param elf_info - elf object decode info container.
396 * @param runtime_buffer - buffer containing ELF sections which are
397 * part of runtime.
398 *
399 * @return - entry point address of the specified ELF object.
400 */
401 static void *elf_loader_get_entry_point_address(struct elf_decode_info
402 *elf_info)
403 {
404 return ((void *)elf_info->elf_header.e_entry);
405 }
407 /**
408 * elf_loader_relocate_link
409 *
410 * Relocates and links the given ELF object.
411 *
412 * @param elf_info - elf object decode info container.
414 *
415 * @return - 0 if success, error otherwise
416 */
418 static int elf_loader_relocate_link(struct elf_decode_info *elf_info)
419 {
420 int status = 0;
422 /* Check of .rel.dyn section exists in the ELF. */
423 if (elf_info->rel_dyn) {
424 /* Relocate and link .rel.dyn section. */
425 status =
426 elf_loader_relocs_specific(elf_info, elf_info->rel_dyn);
427 }
429 /* Proceed to check if .rel.plt section exists, if no error encountered yet. */
430 if (status == 0 && elf_info->rel_plt) {
431 /* Relocate and link .rel.plt section. */
432 status =
433 elf_loader_relocs_specific(elf_info, elf_info->rel_plt);
434 }
436 /* Return status to caller */
437 return (status);
438 }
440 /**
441 * elf_loader_seek_and_read
442 *
443 * Seeks to the specified offset in the given file and reads the data
444 * into the specified destination location.
445 *
446 * @param firmware - firmware to read from.
447 * @param destination - Location into which the data should be read.
448 * @param offset - Offset to seek in the file.
449 * @param size - Size of the data to read.
451 *
452 * @return - 0 if success, error otherwise
453 */
455 static int elf_loader_seek_and_read(void *firmware, void *destination,
456 Elf32_Off offset, Elf32_Word size)
457 {
458 char *src = (char *)firmware;
460 /* Seek to the specified offset. */
461 src = src + offset;
463 /* Read the data. */
464 env_memcpy((char *)destination, src, size);
466 /* Return status to caller. */
467 return (0);
468 }
470 /**
471 * elf_loader_read_headers
472 *
473 * Reads the ELF headers (ELF header, section headers and the section
474 * headers string table) essential to access further information from
475 * the file containing the ELF object.
476 *
477 * @param firmware - firmware to read from.
478 * @param elf_info - ELF object decode info container.
479 *
480 * @return - 0 if success, error otherwise
481 */
482 static int elf_loader_read_headers(void *firmware,
483 struct elf_decode_info *elf_info)
484 {
485 int status = 0;
486 unsigned int section_count;
488 /* Read the ELF header. */
489 status = elf_loader_seek_and_read(firmware, &(elf_info->elf_header), 0,
490 sizeof(Elf32_Ehdr));
492 /* Ensure the read was successful. */
493 if (!status) {
494 /* Get section count from the ELF header. */
495 section_count = elf_info->elf_header.e_shnum;
497 /* Allocate memory to read in the section headers. */
498 elf_info->section_headers_start =
499 env_allocate_memory(section_count *
500 elf_info->elf_header.e_shentsize);
502 /* Check if the allocation was successful. */
503 if (elf_info->section_headers_start) {
504 /* Read the section headers list. */
505 status = elf_loader_seek_and_read(firmware,
506 elf_info->
507 section_headers_start,
508 elf_info->elf_header.
509 e_shoff,
510 section_count *
511 elf_info->elf_header.
512 e_shentsize);
514 /* Ensure the read was successful. */
515 if (!status) {
516 /* Compute the pointer to section header string table section. */
517 Elf32_Shdr *section_header_string_table =
518 (Elf32_Shdr *) (elf_info->
519 section_headers_start +
520 elf_info->elf_header.
521 e_shstrndx *
522 elf_info->elf_header.
523 e_shentsize);
525 /* Allocate the memory for section header string table. */
526 elf_info->shstrtab =
527 env_allocate_memory
528 (section_header_string_table->sh_size);
530 /* Ensure the allocation was successful. */
531 if (elf_info->shstrtab) {
532 /* Read the section headers string table. */
533 status =
534 elf_loader_seek_and_read(firmware,
535 elf_info->
536 shstrtab,
537 section_header_string_table->
538 sh_offset,
539 section_header_string_table->
540 sh_size);
541 }
542 }
543 }
544 }
546 /* Return status to caller. */
547 return (status);
548 }
550 /**
551 * elf_loader_file_read_sections
552 *
553 * Reads the ELF section contents from the specified file containing
554 * the ELF object.
555 *
556 * @param firmware - firmware to read from.
557 * @param elf_info - ELF object decode info container.
558 *
559 * @return - 0 if success, error otherwise
560 */
561 static int elf_loader_load_sections(void *firmware,
562 struct elf_decode_info *elf_info)
563 {
564 int status = 0;
565 Elf32_Shdr *current = (Elf32_Shdr *) (elf_info->section_headers_start);
567 /* Traverse all sections except the reserved null section. */
568 int section_count = elf_info->elf_header.e_shnum - 1;
569 while ((section_count > 0) && (status == 0)) {
570 /* Compute the pointer to section header. */
571 current = (Elf32_Shdr *) (((unsigned char *)current)
572 + elf_info->elf_header.e_shentsize);
574 /* Make sure the section can be allocated and is not empty. */
575 if ((current->sh_flags & SHF_ALLOC) && (current->sh_size)) {
576 char *destination = NULL;
578 /* Check if the section is part of runtime and is not section with
579 * no-load attributes such as BSS or heap. */
580 if ((current->sh_type & SHT_NOBITS) == 0) {
581 /* Compute the destination address where the section should
582 * be copied. */
583 destination = (char *)(current->sh_addr);
584 status =
585 elf_loader_seek_and_read(firmware,
586 destination,
587 current->sh_offset,
588 current->sh_size);
589 }
590 }
592 /* Move to the next section. */
593 section_count--;
594 }
596 /* Return status to caller. */
597 return (status);
598 }
600 /**
601 * elf_loader_get_decode_info
602 *
603 * Retrieves the information necessary to decode the ELF object for
604 * loading, relocating and linking.
605 *
606 * @param firmware - firmware to read from.
607 * @param elf_info - ELF object decode info container.
608 *
609 * @return - 0 if success, error otherwise
610 */
611 static int elf_loader_get_decode_info(void *firmware,
612 struct elf_decode_info *elf_info)
613 {
614 int status;
616 /* Read the ELF headers (ELF header and section headers including
617 * the section header string table). */
618 status = elf_loader_read_headers(firmware, elf_info);
620 /* Ensure that ELF headers were read successfully. */
621 if (!status) {
622 /* Retrieve the sections required for load. */
623 elf_loader_get_needed_sections(elf_info);
625 }
627 /* Return status to caller. */
628 return (status);
629 }
631 /**
632 * elf_loader_get_dynamic_symbol_addr
633 *
634 * Retrieves the (relocatable) address of the symbol specified as
635 * index from the given ELF object.
636 *
637 * @param elf_info - ELF object decode info container.
638 * @param index - Index of the desired symbol in the dynamic symbol table.
639 *
640 * @return - Address of the specified symbol.
641 */
642 static Elf32_Addr elf_loader_get_dynamic_symbol_addr(struct elf_decode_info
643 *elf_info, int index)
644 {
645 Elf32_Sym *symbol_entry = (Elf32_Sym *) (elf_info->dynsym_addr
646 +
647 index *
648 elf_info->dynsym->sh_entsize);
650 /* Return the symbol address. */
651 return (symbol_entry->st_value);
652 }
654 /**
655 * elf_loader_reloc_entry
656 *
657 * Processes the specified relocation entry. It handles the relocation
658 * and linking both cases.
659 *
660 *
661 * @param elf_info - ELF object decode info container.
662 *
663 * @return - 0 if success, error otherwise
664 */
665 static int elf_loader_reloc_entry(struct elf_decode_info *elf_info,
666 Elf32_Rel * rel_entry)
667 {
668 unsigned char rel_type = ELF32_R_TYPE(rel_entry->r_info);
669 int status = 0;
671 switch (rel_type) {
672 case R_ARM_ABS32: /* 0x02 */
673 {
674 Elf32_Addr sym_addr =
675 elf_loader_get_dynamic_symbol_addr(elf_info,
676 ELF32_R_SYM
677 (rel_entry->
678 r_info));
680 if (sym_addr) {
681 *((unsigned int *)(rel_entry->r_offset)) =
682 (unsigned int)sym_addr;
683 break;
684 }
685 }
687 break;
689 default:
690 break;
691 }
693 return status;
694 }