apps: machine: zynqmp_r5: correct IPI setting.
[processor-sdk/open-amp.git] / lib / remoteproc / elf_loader.c
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 <string.h>
31 #include "metal/alloc.h"
32 #include "openamp/elf_loader.h"
34 /* Local functions. */
36 static int elf_loader_get_needed_sections(struct elf_decode_info *elf_info);
37 static int elf_loader_relocs_specific(struct elf_decode_info *elf_info,
38                                       Elf32_Shdr * section);
39 static void *elf_loader_get_entry_point_address(struct elf_decode_info
40                                                 *elf_info);
41 static int elf_loader_relocate_link(struct elf_decode_info *elf_info);
42 static int elf_loader_seek_and_read(void *firmware, void *destination,
43                                     Elf32_Off offset, Elf32_Word size);
44 static int elf_loader_read_headers(void *firmware,
45                                    struct elf_decode_info *elf_info);
46 static int elf_loader_load_sections(void *firmware,
47                                     struct elf_decode_info *elf_info);
48 static int elf_loader_get_decode_info(void *firmware,
49                                       struct elf_decode_info *elf_info);
50 static int elf_loader_reloc_entry(struct elf_decode_info *elf_info,
51                                   Elf32_Rel * rel_entry);
52 static Elf32_Addr elf_loader_get_dynamic_symbol_addr(struct elf_decode_info
53                                                      *elf_info, int index);
55 /**
56  * elf_loader_init
57  *
58  * Initializes ELF loader.
59  *
60  * @param loader    - pointer to remoteproc loader
61  *
62  * @return  - 0 if success, error otherwise
63  */
64 int elf_loader_init(struct remoteproc_loader *loader)
65 {
67         /* Initialize loader function table */
68         loader->load_firmware = elf_loader_load_remote_firmware;
69         loader->retrieve_entry = elf_loader_retrieve_entry_point;
70         loader->retrieve_rsc = elf_loader_retrieve_resource_section;
71         loader->attach_firmware = elf_loader_attach_firmware;
72         loader->detach_firmware = elf_loader_detach_firmware;
73         loader->retrieve_load_addr = elf_get_load_address;
75         return RPROC_SUCCESS;
76 }
78 /**
79  * elf_loader_attach_firmware
80  *
81  * Attaches an ELF firmware to the loader
82  *
83  * @param loader    - pointer to remoteproc loader
84  * @param firmware -  pointer to the firmware start location
85  *
86  * @return  - 0 if success, error otherwise
87  */
88 int elf_loader_attach_firmware(struct remoteproc_loader *loader, void *firmware)
89 {
91         struct elf_decode_info *elf_info;
92         int status;
94         /* Allocate memory for decode info structure. */
95         elf_info = metal_allocate_memory(sizeof(struct elf_decode_info));
97         if (!elf_info) {
98                 return RPROC_ERR_NO_MEM;
99         }
101         /* Clear the ELF decode struct. */
102         memset(elf_info, 0, sizeof(struct elf_decode_info));
104         /* Get the essential information to decode the ELF. */
105         status = elf_loader_get_decode_info(firmware, elf_info);
107         if (status) {
108                 /* Free memory. */
109                 metal_free_memory(elf_info);
110                 return status;
111         }
113         elf_info->firmware = firmware;
114         loader->fw_decode_info = elf_info;
116         return status;
119 /**
120  * elf_loader_detach_firmware
121  *
122  * Detaches ELF firmware from the loader
123  *
124  * @param loader - pointer to remoteproc loader
125  *
126  * @return  - 0 if success, error otherwise
127  */
128 int elf_loader_detach_firmware(struct remoteproc_loader *loader)
131         struct elf_decode_info *elf_info =
132             (struct elf_decode_info *)loader->fw_decode_info;
133         if (elf_info) {
134                 /* Free memory. */
135                 metal_free_memory(elf_info->shstrtab);
136                 metal_free_memory(elf_info->section_headers_start);
137                 metal_free_memory(elf_info);
138         }
140         return RPROC_SUCCESS;
143 /**
144  * elf_loader_retrieve_entry_point
145  *
146  * Retrieves the ELF entrypoint.
147  *
148  * @param loader - pointer to remoteproc loader
149  *
150  * @return  - entrypoint
151  */
152 void *elf_loader_retrieve_entry_point(struct remoteproc_loader *loader)
155         return elf_loader_get_entry_point_address((struct elf_decode_info *)
156                                                   loader->fw_decode_info);
159 /**
160  * elf_loader_retrieve_resource_section
161  *
162  * Retrieves the resource section.
163  *
164  * @param loader - pointer to remoteproc loader
165  * @param size   - pointer to contain the size of the section
166  *
167  * @return  - pointer to resource section
168  */
169 void *elf_loader_retrieve_resource_section(struct remoteproc_loader *loader,
170                                            unsigned int *size)
173         Elf32_Shdr *rsc_header;
174         void *resource_section = NULL;
175         struct elf_decode_info *elf_info =
176             (struct elf_decode_info *)loader->fw_decode_info;
178         if (elf_info->rsc) {
179                 /* Retrieve resource section header. */
180                 rsc_header = elf_info->rsc;
181                 /* Retrieve resource section size. */
182                 *size = rsc_header->sh_size;
184                 /* Locate the start of resource section. */
185                 resource_section = (void *)((uintptr_t)elf_info->firmware
186                                             + rsc_header->sh_offset);
187         }
189         /* Return the address of resource section. */
190         return resource_section;
193 /**
194  * elf_loader_load_remote_firmware
195  *
196  * Loads the ELF firmware.
197  *
198  * @param loader - pointer to remoteproc loader
199  *
200  * @return  - 0 if success, error otherwise
201  */
202 int elf_loader_load_remote_firmware(struct remoteproc_loader *loader)
205         struct elf_decode_info *elf_info =
206             (struct elf_decode_info *)loader->fw_decode_info;
207         int status;
209         /* Load ELF sections. */
210         status = elf_loader_load_sections(elf_info->firmware, elf_info);
212         if (!status) {
214                 /* Perform dynamic relocations if needed. */
215                 status = elf_loader_relocate_link(elf_info);
216         }
218         return status;
221 /**
222  * elf_get_load_address
223  *
224  * Provides firmware load address.
225  *
226  * @param loader - pointer to remoteproc loader
227  *
228  * @return  - load address pointer
229  */
230 void *elf_get_load_address(struct remoteproc_loader *loader)
233         struct elf_decode_info *elf_info =
234             (struct elf_decode_info *)loader->fw_decode_info;
235         int status = 0;
236         Elf32_Shdr *current = (Elf32_Shdr *) (elf_info->section_headers_start);
238         /* Traverse all sections except the reserved null section. */
239         int section_count = elf_info->elf_header.e_shnum - 1;
240         while ((section_count > 0) && (status == 0)) {
241                 /* Compute the pointer to section header. */
242                 current = (Elf32_Shdr *) (((unsigned char *)current)
243                                           + elf_info->elf_header.e_shentsize);
244                 /* Get the name of current section. */
245                 char *current_name = elf_info->shstrtab + current->sh_name;
246                 if (!strcmp(current_name, ".text")) {
247                         return ((void *)(current->sh_addr));
248                 }
249                 /* Move to the next section. */
250                 section_count--;
251         }
253         return (RPROC_ERR_PTR);
256 /**
257  * elf_loader_get_needed_sections
258  *
259  * Retrieves the sections we need during the load and link from the
260  * section headers list.
261  *
262  * @param elf_info  - ELF object decode info container.
263  *
264  * @return- Pointer to the ELF section header.
265  */
267 static int elf_loader_get_needed_sections(struct elf_decode_info *elf_info)
269         Elf32_Shdr *current = (Elf32_Shdr *) (elf_info->section_headers_start);
271         /* We are interested in the following sections:
272            .dynsym
273            .dynstr
274            .rel.plt
275            .rel.dyn
276          */
277         int sections_to_find = 5;
279         /* Search for sections but skip the reserved null section. */
281         int section_count = elf_info->elf_header.e_shnum - 1;
282         while ((section_count > 0) && (sections_to_find > 0)) {
283                 /* Compute the section header pointer. */
284                 current = (Elf32_Shdr *) (((unsigned char *)current)
285                                           + elf_info->elf_header.e_shentsize);
287                 /* Get the name of current section. */
288                 char *current_name = elf_info->shstrtab + current->sh_name;
290                 /* Proceed if the section is allocatable and is not executable. */
291                 if ((current->sh_flags & SHF_ALLOC)
292                     && !(current->sh_flags & SHF_EXECINSTR)) {
293                         /* Check for '.dynsym' or '.dynstr' or '.rel.plt' or '.rel.dyn'. */
294                         if (*current_name == '.') {
295                                 current_name++;
297                                 /* Check for '.dynsym' or 'dynstr'. */
298                                 if (*current_name == 'd') {
299                                         current_name++;
301                                         /* Check for '.dynsym'. */
302                                         if (strncmp(current_name, "ynsym", 5) == 0) {
303                                                 elf_info->dynsym = current;
304                                                 sections_to_find--;
305                                         }
307                                         /* Check for '.dynstr'. */
308                                         else if (strncmp(current_name, "ynstr", 5) == 0) {
309                                                 elf_info->dynstr = current;
310                                                 sections_to_find--;
311                                         }
312                                 }
314                                 /* Check for '.rel.plt' or '.rel.dyn'. */
315                                 else if (*current_name == 'r') {
316                                         current_name++;
318                                         /* Check for '.rel.plt'. */
319                                         if (strncmp(current_name, "el.plt", 6) == 0) {
320                                                 elf_info->rel_plt = current;
321                                                 sections_to_find--;
322                                         }
324                                         /* Check for '.rel.dyn'. */
325                                         else if (strncmp(current_name, "el.dyn", 6) == 0) {
326                                                 elf_info->rel_dyn = current;
327                                                 sections_to_find--;
328                                         }
330                                         /* Check for '.resource_table'. */
331                                         else if (strncmp(current_name, "esource_table", 13)
332                                                  == 0) {
333                                                 elf_info->rsc = current;
334                                                 sections_to_find--;
335                                         }
336                                 }
337                         }
338                 }
340                 /* Move to the next section. */
341                 section_count--;
342         }
344         /* Return remaining sections section. */
345         return (sections_to_find);
348 /**
349  * elf_loader_relocs_specific
350  *
351  * Processes the relocations contained in the specified section.
352  *
353  * @param elf_info - elf decoding information.
354  * @param section  - header of the specified relocation section.
355  *
356  * @return  - 0 if success, error otherwise
357  */
358 static int elf_loader_relocs_specific(struct elf_decode_info *elf_info,
359                                       Elf32_Shdr * section)
362         unsigned char *section_load_addr = (unsigned char *)section->sh_addr;
363         int status = 0;
364         unsigned int i;
366         /* Check the section type. */
367         if (section->sh_type == SHT_REL) {
368                 /* Traverse the list of relocation entries contained in the section. */
369                 for (i = 0; (i < section->sh_size) && (status == 0);
370                      i += section->sh_entsize) {
371                         /* Compute the relocation entry address. */
372                         Elf32_Rel *rel_entry =
373                             (Elf32_Rel *) (section_load_addr + i);
375                         /* Process the relocation entry. */
376                         status = elf_loader_reloc_entry(elf_info, rel_entry);
377                 }
378         }
380         /* Return status to caller. */
381         return (status);
384 /**
385  * elf_loader_get_entry_point_address
386  *
387  * Retrieves the entry point address from the specified ELF object.
388  *
389  * @param elf_info       - elf object decode info container.
390  * @param runtime_buffer - buffer containing ELF sections which are
391  *                         part of runtime.
392  *
393  * @return - entry point address of the specified ELF object.
394  */
395 static void *elf_loader_get_entry_point_address(struct elf_decode_info
396                                                 *elf_info)
398         return ((void *)elf_info->elf_header.e_entry);
401 /**
402  * elf_loader_relocate_link
403  *
404  * Relocates and links the given ELF object.
405  *
406  * @param elf_info       - elf object decode info container.
408  *
409  * @return  - 0 if success, error otherwise
410  */
412 static int elf_loader_relocate_link(struct elf_decode_info *elf_info)
414         int status = 0;
416         /* Check of .rel.dyn section exists in the ELF. */
417         if (elf_info->rel_dyn) {
418                 /* Relocate and link .rel.dyn section. */
419                 status =
420                     elf_loader_relocs_specific(elf_info, elf_info->rel_dyn);
421         }
423         /* Proceed to check if .rel.plt section exists, if no error encountered yet. */
424         if (status == 0 && elf_info->rel_plt) {
425                 /* Relocate and link .rel.plt section. */
426                 status =
427                     elf_loader_relocs_specific(elf_info, elf_info->rel_plt);
428         }
430         /* Return status to caller */
431         return (status);
434 /**
435  * elf_loader_seek_and_read
436  *
437  * Seeks to the specified offset in the given file and reads the data
438  * into the specified destination location.
439  *
440  * @param firmware     - firmware to read from.
441  * @param destination - Location into which the data should be read.
442  * @param offset      - Offset to seek in the file.
443  * @param size        - Size of the data to read.
445  *
446  * @return  - 0 if success, error otherwise
447  */
449 static int elf_loader_seek_and_read(void *firmware, void *destination,
450                                     Elf32_Off offset, Elf32_Word size)
452         char *src = (char *)firmware;
454         /* Seek to the specified offset. */
455         src = src + offset;
457         /* Read the data. */
458         memcpy((char *)destination, src, size);
460         /* Return status to caller. */
461         return (0);
464 /**
465  * elf_loader_read_headers
466  *
467  * Reads the ELF headers (ELF header, section headers and the section
468  * headers string table) essential to access further information from
469  * the file containing the ELF object.
470  *
471  * @param firmware    - firmware to read from.
472  * @param elf_info - ELF object decode info container.
473  *
474  * @return  - 0 if success, error otherwise
475  */
476 static int elf_loader_read_headers(void *firmware,
477                                    struct elf_decode_info *elf_info)
479         int status = 0;
480         unsigned int section_count;
482         /* Read the ELF header. */
483         status = elf_loader_seek_and_read(firmware, &(elf_info->elf_header), 0,
484                                           sizeof(Elf32_Ehdr));
486         /* Ensure the read was successful. */
487         if (!status) {
488                 /* Get section count from the ELF header. */
489                 section_count = elf_info->elf_header.e_shnum;
491                 /* Allocate memory to read in the section headers. */
492                 elf_info->section_headers_start = metal_allocate_memory(section_count * elf_info->elf_header.e_shentsize);
494                 /* Check if the allocation was successful. */
495                 if (elf_info->section_headers_start) {
496                         /* Read the section headers list. */
497                         status = elf_loader_seek_and_read(firmware,
498                                                           elf_info->
499                                                           section_headers_start,
500                                                           elf_info->elf_header.
501                                                           e_shoff,
502                                                           section_count *
503                                                           elf_info->elf_header.
504                                                           e_shentsize);
506                         /* Ensure the read was successful. */
507                         if (!status) {
508                                 /* Compute the pointer to section header string table section. */
509                                 Elf32_Shdr *section_header_string_table =
510                                     (Elf32_Shdr *) (elf_info->
511                                                     section_headers_start +
512                                                     elf_info->elf_header.
513                                                     e_shstrndx *
514                                                     elf_info->elf_header.
515                                                     e_shentsize);
517                                 /* Allocate the memory for section header string table. */
518                                 elf_info->shstrtab = metal_allocate_memory(section_header_string_table->sh_size);
520                                 /* Ensure the allocation was successful. */
521                                 if (elf_info->shstrtab) {
522                                         /* Read the section headers string table. */
523                                         status =
524                                             elf_loader_seek_and_read(firmware,
525                                                                      elf_info->
526                                                                      shstrtab,
527                                                                      section_header_string_table->
528                                                                      sh_offset,
529                                                                      section_header_string_table->
530                                                                      sh_size);
531                                 }
532                         }
533                 }
534         }
536         /* Return status to caller. */
537         return (status);
540 /**
541  * elf_loader_file_read_sections
542  *
543  * Reads the ELF section contents from the specified file containing
544  * the ELF object.
545  *
546  * @param firmware - firmware to read from.
547  * @param elf_info - ELF object decode info container.
548  *
549  * @return  - 0 if success, error otherwise
550  */
551 static int elf_loader_load_sections(void *firmware,
552                                     struct elf_decode_info *elf_info)
554         int status = 0;
555         Elf32_Shdr *current = (Elf32_Shdr *) (elf_info->section_headers_start);
557         /* Traverse all sections except the reserved null section. */
558         int section_count = elf_info->elf_header.e_shnum - 1;
559         while ((section_count > 0) && (status == 0)) {
560                 /* Compute the pointer to section header. */
561                 current = (Elf32_Shdr *) (((unsigned char *)current)
562                                           + elf_info->elf_header.e_shentsize);
564                 /* Make sure the section can be allocated and is not empty. */
565                 if ((current->sh_flags & SHF_ALLOC) && (current->sh_size)) {
566                         char *destination = NULL;
568                         /* Check if the section is part of runtime and is not section with
569                          * no-load attributes such as BSS or heap. */
570                         if ((current->sh_type & SHT_NOBITS) == 0) {
571                                 /* Compute the destination address where the section should
572                                  * be copied. */
573                                 destination = (char *)(current->sh_addr);
574                                 status =
575                                     elf_loader_seek_and_read(firmware,
576                                                              destination,
577                                                              current->sh_offset,
578                                                              current->sh_size);
579                         }
580                 }
582                 /* Move to the next section. */
583                 section_count--;
584         }
586         /* Return status to caller. */
587         return (status);
590 /**
591  * elf_loader_get_decode_info
592  *
593  * Retrieves the information necessary to decode the ELF object for
594  * loading, relocating and linking.
595  *
596  * @param firmware - firmware to read from.
597  * @param elf_info - ELF object decode info container.
598  *
599  * @return  - 0 if success, error otherwise
600  */
601 static int elf_loader_get_decode_info(void *firmware,
602                                       struct elf_decode_info *elf_info)
604         int status;
606         /* Read the ELF headers (ELF header and section headers including
607          * the section header string table). */
608         status = elf_loader_read_headers(firmware, elf_info);
610         /* Ensure that ELF headers were read successfully. */
611         if (!status) {
612                 /* Retrieve the sections required for load. */
613                 elf_loader_get_needed_sections(elf_info);
615         }
617         /* Return status to caller. */
618         return (status);
621 /**
622  * elf_loader_get_dynamic_symbol_addr
623  *
624  * Retrieves the (relocatable) address of the symbol specified as
625  * index from the given ELF object.
626  *
627  * @param elf_info - ELF object decode info container.
628  * @param index    - Index of the desired symbol in the dynamic symbol table.
629  *
630  * @return - Address of the specified symbol.
631  */
632 static Elf32_Addr elf_loader_get_dynamic_symbol_addr(struct elf_decode_info
633                                                      *elf_info, int index)
635         Elf32_Sym *symbol_entry = (Elf32_Sym *) (elf_info->dynsym_addr
636                                                  +
637                                                  index *
638                                                  elf_info->dynsym->sh_entsize);
640         /* Return the symbol address. */
641         return (symbol_entry->st_value);
644 /**
645  * elf_loader_reloc_entry
646  *
647  * Processes the specified relocation entry. It handles the relocation
648  * and linking both cases.
649  *
650  *
651  * @param elf_info - ELF object decode info container.
652  *
653  * @return  - 0 if success, error otherwise
654  */
655 static int elf_loader_reloc_entry(struct elf_decode_info *elf_info,
656                                   Elf32_Rel * rel_entry)
658         unsigned char rel_type = ELF32_R_TYPE(rel_entry->r_info);
659         int status = 0;
661         switch (rel_type) {
662         case R_ARM_ABS32:       /* 0x02 */
663                 {
664                         Elf32_Addr sym_addr =
665                             elf_loader_get_dynamic_symbol_addr(elf_info,
666                                                                ELF32_R_SYM
667                                                                (rel_entry->
668                                                                 r_info));
670                         if (sym_addr) {
671                                 *((unsigned int *)(rel_entry->r_offset)) =
672                                     (unsigned int)sym_addr;
673                                 break;
674                         }
675                 }
677                 break;
679         default:
680                 break;
681         }
683         return status;