]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/open-amp.git/blob - lib/remoteproc/elf_loader.c
rm compilation warnings, clean comments, file rename
[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 "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;
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)
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;
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)
153         return elf_loader_get_entry_point_address((struct elf_decode_info *)
154                                                   loader->fw_decode_info);
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)
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;
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)
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;
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)
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);
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)
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);
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)
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);
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)
404         return ((void *)elf_info->elf_header.e_entry);
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)
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);
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)
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);
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)
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);
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)
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);
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)
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);
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)
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);
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)
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;