All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
elf_loader.c
Go to the documentation of this file.
1 
2 /*
3  * OpenVirtualization:
4  * For additional details and support contact [email protected].
5  * Additional documentation can be found at www.openvirtualization.org
6  *
7  * Copyright (C) 2011 SierraWare
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * Elf loader implementation
24  *
25  */
26 #ifndef CONFIG_FILESYSTEM_SUPPORT
27 #error "Filesystem support required for Elf loader"
28 #endif
29 #include <elf.h>
30 #include <task.h>
31 #include <secure_api.h>
32 #include <sw_debug.h>
33 #include <otz_id.h>
34 #include <fat32.h>
35 #include <page_table.h>
36 #include <dispatcher_task.h>
37 #include <sw_string_functions.h>
38 #include <sw_mem_functions.h>
39 #include <mem_mng.h>
40 #include <sw_list.h>
41 #include <cpu_data.h>
42 #include <sw_types.h>
43 #include <task.h>
44 #include <elf_loader_app.h>
45 #include <elf_loader.h>
46 #include <sw_board.h>
47 
48 #define __KSYMTAB_ADDR ((va_t *)&_SW_KSYMTAB)
49 
50 static int init_map_loader(sa_config_t *);
51 
52 static int fix_process_func(Elf32_Shdr *sec_header , Elf32_Sym *sym , char
53  *entry_func, u32 symindex, const char *strtab,
54  sa_config_t *psa_config)
55 {
56  Elf32_Shdr *tmp_shdr=sec_header;
57  int index;
58  u32 n = ((tmp_shdr[symindex].sh_size) / (sizeof(Elf32_Sym))), i;
59 
60  for(i=1; i<n ; i++){
61  index = sym[i].st_name;
62  if(sw_strcmp((char *)(strtab + index), entry_func) == 0){
63 
64  /* BASE_LOAD_ADDRESS is where the .text section
65  * gets mapped..so
66  * all we need is an offset from BASE_LOAD_ADDRESS */
67  psa_config->process = BASE_LOAD_ADDRESS
68  + sym[i].st_value;
69  return 0;
70  }
71 
72  }
73  return -1;
74 }
75 
76 
85 {
86  int status = 0;
87  /* 0 indicates that the mapping is successful, so do the cleanup */
89  SECTION_SIZE);
90  if (status == -1){
91  sw_printf("Unable to unmap secure memory of elf loader\n");
92  return -1;
93  }
94 
95  return status;
96 
97 }
98 
107 static int load_into_memory(void *file_map , Elf32_Shdr * sec_header)
108 {
109  Elf32_Ehdr *elf_header = (Elf32_Ehdr *)file_map;
110  Elf32_Shdr *tmp_shdr = sec_header;
111  void *status = NULL;
112  int shnum = elf_header->e_shnum,i;
113  u32 prev_addr = BASE_LOAD_ADDRESS;
114 
115  for(i = 1; i < shnum ; i++){
116  if(tmp_shdr[i].sh_flags & SHF_ALLOC){
117  status = sw_memcpy((void *)prev_addr,
118  (void*)tmp_shdr[i].sh_addr,
119  tmp_shdr[i].sh_size);
120  if(status == NULL){
121  sw_printf("load failed\n");
122  return -1;
123  }
124  prev_addr += tmp_shdr[i].sh_size;
125  }
126 
127 
128 
129  }
130  return 0;
131 }
132 
133 
149 static u32 get_undefined_symbol_addr(struct kernel_symbol *sym_tab,
150  const char *symname, int n)
151 {
152 
153  int i, ret=-1;
154 
155  for(i=0; i<n ;i++){
156  if(sw_strcmp(symname, sym_tab->symbol) == 0){
157 
158  ret = (u32)sym_tab->addr;
159  break;
160  }
161  sym_tab+=1;
162  }
163  return ret;
164 
165 }
166 
167 
168 
187 static int fix_entry_point(Elf32_Shdr *sec_header , Elf32_Sym *sym , char
188  *entry_func, u32 symindex, const char *strtab,
189  sa_config_t *psa_config)
190 {
191  Elf32_Shdr *tmp_shdr=sec_header;
192  int index;
193  u32 n = ((tmp_shdr[symindex].sh_size) / (sizeof(Elf32_Sym))), i;
194 
195  for(i=1; i<n ; i++){
196  index = sym[i].st_name;
197  if(sw_strcmp((char *)(strtab + index), entry_func) == 0){
198 
199  /* BASE_LOAD_ADDRESS is where the .text section
200  * gets mapped..so
201  * all we need is an offset from BASE_LOAD_ADDRESS */
202  psa_config->entry_point = BASE_LOAD_ADDRESS
203  + sym[i].st_value;
204  return 0;
205  }
206 
207  }
208  return -1;
209 
210 
211 
212 }
213 
214 
236 static int apply_relocations(void *file_map , Elf32_Shdr *sec_header , const
237  char *str_tab, u32 symindex, u32 relindex, sa_config_t *conf,
238  int *fl)
239 {
240  Elf32_Shdr *sym_sec = sec_header + symindex;
241  Elf32_Shdr *rel_sec = sec_header + relindex;
242  Elf32_Rel *rel = (Elf32_Rel *)rel_sec->sh_addr;
243  Elf32_Sym *tmp_sym = NULL;
244  Elf32_Sym *sym = (Elf32_Sym *)sym_sec->sh_addr;
245  u32 i, status;
246  char *entry_func= conf->entry_func;
247  u32 symbol_addr,sym_index = symindex;
248  s32 offset,loc_to_rel;
249  Elf32_Shdr *dst_sec = sec_header + rel_sec->sh_info;
250  Elf32_Ehdr *elf_header = NULL;
251  const char *symname;
252  Elf32_Shdr *tmp_shdr = sec_header;
253 
254  va_t * sym_tab_start = (va_t *)&_SW_KSYMTAB;
255  va_t * sym_tab_end = (va_t *)&_SW_KSYMTAB_END;
256  u32 n = ((u32)sym_tab_end -
257  (u32)sym_tab_start) / sizeof(struct kernel_symbol);
258  struct kernel_symbol *sym_tab = NULL;
259 
260  sym_tab=(struct kernel_symbol *)sym_tab_start;
261 
262  tmp_sym = sym;
263  for(i=0; i < (rel_sec->sh_size)/(sizeof(Elf32_Rel)); i++){
264  /* Get the index inside the sym_tab */
265  offset = ELF32_R_SYM(rel[i].r_info);
266  if(offset < 0 || offset >
267  ((sym_sec->sh_size ) / (sizeof(Elf32_Sym)))){
268  sw_printf("Invalid offset inside the symbol table\n");
269  return -1;
270  }
271 
272  /* Index of the symbol in the symbol table */
273  sym = (Elf32_Sym *)sym + offset;
274 
275  /* Note that st_name is a index into the symbol string table */
276  symname = str_tab + sym->st_name;
277 
278 
279 
280  if( (rel[i].r_offset < 0 || rel[i].r_offset >
281  (dst_sec->sh_size - sizeof(u32)))){
282  sw_printf("Invalid offset of %s\n", symname);
283  return -1;
284  }
285 
286 
287  switch(ELF32_R_TYPE(rel[i].r_info))
288  {
289  case R_ARM_NONE:
290  /* ignore it..*/
291  break;
292  case R_ARM_ABS32:
293  /* Right now we are just exporting functions,
294  * add relocation support when we export global
295  * variable too */
296  *(u32 *)loc_to_rel += sym->st_value;
297  break;
298  case R_ARM_CALL:
299  case R_ARM_JUMP24:
300  case R_ARM_PC24:
301 /* Calculate relocations differently here, because there is a strong possibility
302  * that the reloc offset will exceed 32MB , so assuming that we load @ address
303  * closer to the kernel, use that address instead of dst_sec->sh_addr..Also we
304  * are taking advantage of the fact that the .text section will be the first to
305  * be mapped */
306  if(sym->st_shndx == SHN_UNDEF){
307 
308  symbol_addr = get_undefined_symbol_addr(
309  sym_tab,symname,n);
310  if(symbol_addr == -1){
311  sw_printf("Unable to find"
312  "symbol\n");
313  return -1;
314  }
315  loc_to_rel = (u32)(dst_sec->sh_addr +
316  rel[i].r_offset);
317  offset = (*(u32 *) loc_to_rel &
318  0x00ffffff) << 2;
319  if(offset & 0x02000000)
320  offset -= 0x04000000;
321 /* We know that the .text section will be the first section to be mapped.. so
322  * take advantage of it */
323  offset += symbol_addr -
325  rel[i].r_offset) ;
326 
327 
328  if (offset & 3 ||
329  offset <=
330  (s32)0xfe000000 ||
331  offset >=
332  (s32)0x02000000) {
333 
334  sw_printf("Invalid \
335  relocation\n");
336  return -1;
337  }
338  offset >>= 2;
339 
340  /* we need only the last 24 bits */
341  *(u32 *)loc_to_rel &= 0xff000000;
342  *(u32 *)loc_to_rel
343  |= offset & 0x00ffffff;
344 
345 
346  }
347  else{
348 
349  /* Get the offset to relocate */
350  loc_to_rel = (u32)(dst_sec->sh_addr
351  + rel[i].r_offset);
352  offset = (*(u32 *) loc_to_rel &
353  0x00ffffff) << 2;
354 
355  if(offset & 0x02000000)
356  offset -= 0x04000000;
357  offset +=
358  ((u32)tmp_shdr[sym->st_shndx].sh_addr
359  + sym->st_value) - loc_to_rel;
360  if (offset & 3 ||
361  offset <= 0xfe000000 ||
362  offset >= 0x02000000) {
363 
364  sw_printf("Invalid"
365  "relocation\n");
366  return -1;
367  }
368  offset >>= 2;
369 
370  /* we need only the last 24 bits */
371  *(u32 *)loc_to_rel &= 0xff000000;
372  *(u32 *)loc_to_rel |= offset &
373  0x00ffffff;
374  }
375  break;
376 
377  default:
378  break;
379 
380 
381  }
382  sym = tmp_sym;
383  }
384  /* We are calling the fix_entry_point() since all the params it requires
385  * are present in this function.. 'fl ' will
386  make sure that we call the function only once...*/
387  if(*fl == 0){
388 
389  status = fix_entry_point(sec_header, tmp_sym ,entry_func ,
390  sym_index, str_tab, conf);
391  if(status == -1){
392  sw_printf("Unable to fix entry_point\n");
393  return -1;
394  }
395 
396  status = fix_process_func(sec_header, tmp_sym
397  ,conf->process_name ,
398  sym_index, str_tab, conf);
399 
400  if(status == -1){
401  sw_printf("Unable to fix process_func\n");
402  return -1;
403  }
404  elf_header = file_map;
405  elf_header->e_entry = conf->entry_point;
406  *fl = 1;
407  }
408 
409  return 0;
410 
411 }
412 
413 
414 
430 static int relocate_elf_loader(int fp, Elf32_Ehdr *elf_header,
431  sa_config_t *conf)
432 {
433  void *file_map = NULL, *tmp = NULL;
434  u32 offset, len, num_bytes,sh_off,sh_num,i,symindex,strindex,relindex;
435  char *str_tab = NULL;
436  int status,ret = OTZ_OK,fl = 0;
437  Elf32_Shdr *sec_header , *tmp_shdr;
438 
439 
440  /* Get the number of bytes in the file */
441  offset = file_seek(fp,0x0,FILE_SEEK_END);
442  if(offset == -1){
443  sw_printf("file seek failed\n");
444  ret = -1;
445  goto out;
446  }
447 
448  len = offset;
449  offset = file_seek(fp,0x0,FILE_SEEK_SET);
450  file_map = (void *)sw_vir_page_alloc(len);
451  if(!file_map){
452  sw_printf("Insufficient memory\n");
453  ret = -1;
454  goto out;
455  }
456 
457  /* Map the file to memory */
458  tmp = file_map;
459 
460  do{
461  num_bytes = file_read(fp,(char *)tmp,len);
462  if(num_bytes == 0){
463  sw_printf("Read failed\n");
464  ret = -1;
465  goto out;
466  }
467  tmp = (char *)tmp + num_bytes;
468  len -= num_bytes;
469  }
470  while(len > 0);
471 
472  tmp = file_map;
473  sw_memcpy((char *)elf_header,(char *)tmp,sizeof(Elf32_Ehdr));
474  sh_off = elf_header->e_shoff;
475  sh_num = elf_header->e_shnum;
476 
477  sec_header = (Elf32_Shdr *)((char *)tmp + sh_off);
478  tmp_shdr = sec_header;
479 
480 /* Get the symtab index, strtab index and reloc index..
481  * and also fix sh_addr with file_map as the base address for easy referral */
482  for(i = 1; i < sh_num ; i++){
483  if(tmp_shdr[i].sh_type == SHT_SYMTAB){
484  symindex = i;
485  }
486  if(tmp_shdr[i].sh_type == SHT_STRTAB){
487  strindex = i;
488  }
489 
490  tmp_shdr[i].sh_addr = (Elf32_Addr)((char *)tmp +
491  tmp_shdr[i].sh_offset);
492 
493  }
494  /* Note that offset if from the beginning of the file */
495  str_tab = ((char *)tmp + tmp_shdr[strindex].sh_offset);
496 
497 /* Note that there will be multiple relocation sections..Apply for everything */
498  for(i = 1;i < sh_num ; i++){
499  if(tmp_shdr[i].sh_type == SHT_REL){
500  relindex = i;
501  status = apply_relocations(file_map, sec_header ,
502  str_tab, symindex, relindex, conf,&fl);
503  if(status == -1){
504  sw_printf("Relocation failed\n");
505  ret = -1;
506  goto out;
507  }
508  }
509  }
510 
511  status = load_into_memory(file_map,sec_header);
512  if(status == -1){
513  sw_printf("Unable to load into memory\n");
514  ret = -1;
515  goto out;
516  }
517 
518  /* Note that we have a separate cleanup label for both executable
519  * and relocatable files */
520 out:
521  if(file_map)
522  sw_vir_addr_free((u32) file_map,len);
523  if(fp != -1)
524  status = file_close(fp);
525  if(status == -1)
526  sw_printf("Unable to close file");
527  return ret;
528 }
529 
536 static int init_map_loader(sa_config_t *psa_config)
537 {
538 
541  != OTZ_OK){
542  sw_printf("Unable to map VA to PA\n");
543  return -1;
544  }
545  psa_config->elf_flag = ELF_FLAG_MAP;
546  return 0;
547 }
548 
549 
550 
560 static int validate_elf_header(int fp , Elf32_Ehdr *elf_header)
561 {
562  int num_bytes,rel = 0;
563  num_bytes = file_read(fp,(char *)elf_header,sizeof(Elf32_Ehdr));
564  if(num_bytes != sizeof(Elf32_Ehdr)){
565  sw_printf("Read failed\n");
566  return -1;
567 
568  }
569  if(!(elf_header->e_ident[EI_MAG0] == ELFMAG0 &&
570  elf_header->e_ident[EI_MAG1] == ELFMAG1 &&
571  elf_header->e_ident[EI_MAG2] == ELFMAG2 &&
572  elf_header->e_ident[EI_MAG3] == ELFMAG3)){
573  sw_printf("Invalid ELF file\n");
574  return -1;
575 
576  }
577  /* We support ARM specific ELF with 32 bit LSB support only */
578  if(elf_header->e_ident[EI_CLASS] != ELFCLASS32){
579  sw_printf("Not a 32-bit executable\n");
580  return -1;
581 
582  }
583  if(elf_header->e_ident[EI_DATA] != ELFDATA2LSB){
584  sw_printf("Not in Little Endian format\n");
585  return -1;
586 
587  }
588  /* Check if the version is current ie EV_CURRENT */
589  if(elf_header->e_ident[EI_VERSION] != EV_CURRENT){
590  sw_printf("Not using the current version of ELF\n");
591  return -1;
592 
593  }
594  /*Check if the ELF file is a executable file ie of type ET_EXEC */
595  if(elf_header->e_type != ET_EXEC){
596  /*sw_printf("Not a executable file \n");*/
597  if(elf_header->e_type == ET_REL)
598  {
599  rel = 1;
600  }
601 
602  }
603  /* Check if the architecture is ARM */
604  if(elf_header->e_machine != EM_ARM){
605  sw_printf("Unsupported process architecture\n");
606  return -1;
607 
608  }
609 /* Check if the version is current (Not sure if the check here is mandatory)*/
610  if(elf_header->e_version != EV_CURRENT){
611  sw_printf("Not using the current version of the ELF file\n");
612  return -1;
613 
614  }
615 
616 
617  return rel;
618 }
619 
630  Elf32_Phdr **phdr_tab)
631 {
632  int ph_num,num_bytes,num_of_segments,num_of_loadable_segments = 0;
633  Elf32_Phdr *phdr_table, *tmp_phdr;
634  ph_num = elf_header->e_phnum;
635 
636  phdr_table = (Elf32_Phdr *)sw_malloc(ph_num * sizeof( Elf32_Phdr));
637 
638  if(phdr_table == NULL){
639  sw_printf("No memory available\n");
640  return -1;
641  }
642  num_bytes = 0;
643  num_bytes = file_read(fp,(char *)phdr_table,
644  (ph_num * sizeof(Elf32_Phdr)));
645  if (num_bytes != (ph_num * sizeof( Elf32_Phdr))){
646  sw_printf("Reading Programheader table from ELF file failed\n");
647  return -1;
648  }
649  /* Get the number of PT_LOAD segments */
650  tmp_phdr = phdr_table;
651 
652  for(num_of_segments = 0;num_of_segments < elf_header->e_phnum;
653  num_of_segments++) {
654  if(tmp_phdr->p_type == PT_LOAD)
655  num_of_loadable_segments++;
656  tmp_phdr = ( Elf32_Phdr *)((char *)tmp_phdr +
657  elf_header->e_phentsize);
658 
659  }
660  *phdr_tab = phdr_table;
661  return num_of_loadable_segments;
662 
663 }
664 
665 
678 int elf_load( struct sa_config_t *conf)
679 {
680  Elf32_Ehdr elf_header;
681  Elf32_Ehdr *tmp_ehdr;
682  u32 rel = 0;
683  u32 num_bytes = 0,va_offset,status;
684  int num_of_segments,fp = -1,ret = OTZ_OK,mode = FILE_READ;
685  u32 *flag = NULL,*base_va = NULL;
686  u32 offset,leftover_size, num_of_loadable_segments = 0;
687  Elf32_Phdr *phdr_table = NULL, *tmp_phdr = NULL;
688  char *leftover_data = NULL;
689 
690  conf->elf_flag = -1;
691  ret = init_map_loader(conf);
692  if(ret != 0)
693  {
694  sw_printf("Mapping PA to VA failed\n");
695  ret = -1;
696  goto out;
697  }
698  fp = file_open(conf->file_path,mode);
699  if(fp == -1){
700  sw_printf("unable to open file\n");
701  ret =- 1;
702  goto out;
703  }
704 
705  rel = validate_elf_header(fp,&elf_header);
706  tmp_ehdr = &elf_header;
707  if(rel == 1){
708  status = relocate_elf_loader(fp,tmp_ehdr,conf);
709 /* We dont care about whatever be the status here, because we need to clean up
710 * the elf_loader task irrespective of the result */
711  ret = status;
712  if(status == -1 || status == 0)
713 
714  goto out;
715  }
716  if(rel == -1 ){
717  ret = -1;
718  goto out;
719  }
720  /* Here we are dealing with a executable...right now the executable
721  * support is not required.. */
722  goto out;
723  conf->entry_point = elf_header.e_entry;
724 
725  num_of_loadable_segments = get_number_of_loadable_segments(fp,
726  &elf_header,&phdr_table);
727  if(num_of_loadable_segments == -1){
728  ret =- 1;
729  goto out;
730  }
731  tmp_phdr = phdr_table;
732 /* array of u32 entries whose total number equals number_of_loadable_segments */
733  flag = sw_malloc(num_of_loadable_segments * sizeof(u32) );
734  if(flag == NULL){
735  sw_printf("No memory available\n");
736  ret =- 1;
737  goto out;
738  }
739  sw_memset(flag,0x0,num_of_loadable_segments * sizeof(u32));
740  for(num_of_segments = 0;num_of_segments < elf_header.e_phnum;
741  num_of_segments++){
742  if(tmp_phdr->p_type == PT_LOAD)
743  {
744 /* we need to check if the segment contains the .bss section
745  * in which p_filesz < p_memsz */
746  if(tmp_phdr->p_filesz == tmp_phdr->p_memsz)
747  {
748 
749 
750  va_offset = tmp_phdr->p_vaddr;
751 
752  offset = tmp_phdr->p_offset;
753  file_seek(fp,0,FILE_SEEK_SET);
754  file_seek(fp,offset,FILE_SEEK_SET);
755  num_bytes = 0;
756  num_bytes = file_read(fp,((char *)base_va
757  + va_offset ),
758  tmp_phdr->p_filesz);
759  if(num_bytes != tmp_phdr->p_filesz){
760  sw_printf("Reading segment failed\n");
761  ret = -1;
762  goto out;
763  }
764 
765 
766 
767  }
768  else if (tmp_phdr->p_filesz < tmp_phdr->p_memsz){
769 
770  va_offset = tmp_phdr->p_vaddr;
771  offset = tmp_phdr->p_offset;
772  file_seek(fp,0,FILE_SEEK_SET);
773  file_seek(fp,offset,FILE_SEEK_SET);
774  num_bytes = 0;
775  num_bytes = file_read(fp,((char *)base_va +
776  va_offset),
777  tmp_phdr->p_filesz);
778  if(num_bytes != tmp_phdr->p_filesz){
779  sw_printf("Reading segment failed\n");
780  ret = -1;
781  goto out;
782  }
783  leftover_size = (tmp_phdr->p_memsz -
784  tmp_phdr->p_filesz + 1);
785  leftover_data = (char *)sw_malloc(
786  tmp_phdr->p_memsz -
787  tmp_phdr->p_filesz+ 1);
788  sw_memset(leftover_data,0x0,(tmp_phdr->p_memsz -
789  tmp_phdr->p_filesz + 1));
790  sw_memcpy(base_va,leftover_data,leftover_size);
791  sw_malloc_free(leftover_data);
792 
793 
794 
795  }
796  }
797 
798  tmp_phdr = ( Elf32_Phdr *)((char *)tmp_phdr +
799  elf_header.e_phentsize);
800  }
801 
802 
803  /* TODO:
804  1) Also, Add support for dynamic linking (Not needed for now )
805  */
806 
807 
808 out:
809  /* Free the allocated memory and resources here */
810 
811  if(phdr_table){
812  tmp_phdr = phdr_table;
813  for(num_of_segments = 0,num_of_loadable_segments = 0;
814  num_of_segments < elf_header.e_phnum;
815  num_of_segments++){
816  if(tmp_phdr->p_type == PT_LOAD){
817  if(!flag[num_of_loadable_segments]){
818  sw_vir_addr_free(((u32)base_va +
819  tmp_phdr->p_vaddr),
820  tmp_phdr->p_memsz );
821 
822  }
823  num_of_loadable_segments++;
824  }
825  tmp_phdr = ( Elf32_Phdr *)((char *)tmp_phdr +
826  elf_header.e_phentsize);
827 
828  }
829 
830  sw_malloc_free(phdr_table);
831  }
832  if(fp != -1){
833 
834  file_close(fp);
835 
836  }
837 
838 
839  return ret;
840 }
841