00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <errno.h>
00032 #include <elf.h>
00033 #include <gpxe/uaccess.h>
00034 #include <gpxe/segment.h>
00035 #include <gpxe/image.h>
00036 #include <gpxe/elf.h>
00037
00038 typedef Elf32_Ehdr Elf_Ehdr;
00039 typedef Elf32_Phdr Elf_Phdr;
00040 typedef Elf32_Off Elf_Off;
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
00051 Elf_Ehdr *ehdr ) {
00052 physaddr_t dest;
00053 userptr_t buffer;
00054 unsigned long e_offset;
00055 int rc;
00056
00057
00058 if ( phdr->p_type != PT_LOAD )
00059 return 0;
00060
00061
00062 if ( ( phdr->p_offset + phdr->p_filesz ) > image->len ) {
00063 DBGC ( image, "ELF %p segment outside image\n", image );
00064 return -ENOEXEC;
00065 }
00066
00067
00068
00069
00070
00071 dest = phdr->p_paddr;
00072 if ( ! dest )
00073 dest = phdr->p_vaddr;
00074 if ( ! dest ) {
00075 DBGC ( image, "ELF %p segment loads to physical address 0\n",
00076 image );
00077 return -ENOEXEC;
00078 }
00079 buffer = phys_to_user ( dest );
00080
00081 DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image,
00082 phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ),
00083 phdr->p_paddr, ( phdr->p_paddr + phdr->p_filesz ),
00084 ( phdr->p_paddr + phdr->p_memsz ) );
00085
00086
00087 if ( ( rc = prep_segment ( buffer, phdr->p_filesz,
00088 phdr->p_memsz ) ) != 0 ) {
00089 DBGC ( image, "ELF %p could not prepare segment: %s\n",
00090 image, strerror ( rc ) );
00091 return rc;
00092 }
00093
00094
00095 memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz );
00096
00097
00098 if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
00099 image->priv.phys = ehdr->e_entry;
00100 DBGC ( image, "ELF %p found physical entry point at %lx\n",
00101 image, image->priv.phys );
00102 } else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) )
00103 < phdr->p_filesz ) {
00104 if ( ! image->priv.phys ) {
00105 image->priv.phys = ( dest + e_offset );
00106 DBGC ( image, "ELF %p found virtual entry point at %lx"
00107 " (virt %lx)\n", image, image->priv.phys,
00108 ( ( unsigned long ) ehdr->e_entry ) );
00109 }
00110 }
00111
00112 return 0;
00113 }
00114
00115
00116
00117
00118
00119
00120
00121 int elf_load ( struct image *image ) {
00122 Elf_Ehdr ehdr;
00123 Elf_Phdr phdr;
00124 Elf_Off phoff;
00125 unsigned int phnum;
00126 int rc;
00127
00128
00129 assert ( image->type != NULL );
00130
00131
00132 copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
00133 if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) {
00134 DBGC ( image, "ELF %p has invalid signature\n", image );
00135 return -ENOEXEC;
00136 }
00137
00138
00139 image->priv.phys = 0;
00140
00141
00142 for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
00143 phoff += ehdr.e_phentsize, phnum-- ) {
00144 if ( phoff > image->len ) {
00145 DBGC ( image, "ELF %p program header %d outside "
00146 "image\n", image, phnum );
00147 return -ENOEXEC;
00148 }
00149 copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
00150 if ( ( rc = elf_load_segment ( image, &phdr, &ehdr ) ) != 0 )
00151 return rc;
00152 }
00153
00154
00155 if ( ! image->priv.phys ) {
00156 DBGC ( image, "ELF %p entry point %lx outside image\n",
00157 image, ( ( unsigned long ) ehdr.e_entry ) );
00158 return -ENOEXEC;
00159 }
00160
00161 return 0;
00162 }