00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <elf.h>
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <malloc.h>
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <unistd.h>
00028
00029 #include <sys/mman.h>
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032
00033 #include "elf_loader.h"
00034 #include "spebase.h"
00035
00036 #ifdef DEBUG
00037 static void display_debug_output(Elf32_Ehdr *elf_start, Elf32_Shdr *sh);
00038 #endif
00039
00040 #define __PRINTF(fmt, args...) { fprintf(stderr,fmt , ## args); }
00041 #ifdef DEBUG
00042 #define DEBUG_PRINTF(fmt, args...) __PRINTF(fmt , ## args)
00043 #define TAG DEBUG_PRINTF("TAG: %d@%s\n", __LINE__, __FILE__);
00044 #else
00045 #define DEBUG_PRINTF(fmt, args...)
00046 #define TAG
00047 #endif
00048
00049 static const unsigned char expected[EI_PAD] = {
00050 [EI_MAG0] = ELFMAG0,
00051 [EI_MAG1] = ELFMAG1,
00052 [EI_MAG2] = ELFMAG2,
00053 [EI_MAG3] = ELFMAG3,
00054 [EI_CLASS] = ELFCLASS32,
00055 [EI_DATA] = ELFDATA2MSB,
00056 [EI_VERSION] = EV_CURRENT,
00057 [EI_OSABI] = ELFOSABI_SYSV,
00058 [EI_ABIVERSION] = 0
00059 };
00060
00061 static int
00062 check_spe_elf(Elf32_Ehdr *ehdr)
00063 {
00064
00065 if (memcmp (ehdr->e_ident, expected, EI_PAD) != 0)
00066 {
00067 DEBUG_PRINTF ("invalid ELF header.\n");
00068 DEBUG_PRINTF ("expected 0x%016llX != 0x%016llX\n",
00069 *(long long *) expected, *(long long *) (ehdr->e_ident));
00070 errno = EINVAL;
00071 return -errno;
00072 }
00073
00074
00075 if (ehdr->e_machine != 0x17)
00076 {
00077 DEBUG_PRINTF ("not an SPE ELF object");
00078 errno = EINVAL;
00079 return -errno;
00080 }
00081
00082
00083 if (ehdr->e_type != ET_EXEC)
00084 {
00085 DEBUG_PRINTF ("invalid SPE ELF type.\n");
00086 DEBUG_PRINTF ("SPE type %d != %d\n", ehdr->e_type, ET_EXEC);
00087 errno = EINVAL;
00088 DEBUG_PRINTF ("parse_spu_elf(): errno=%d.\n", errno);
00089 return -errno;
00090 }
00091
00092 return 0;
00093
00094 }
00098 int
00099 _base_spe_verify_spe_elf_image(spe_program_handle_t *handle)
00100 {
00101 Elf32_Ehdr *ehdr;
00102 void *elf_start;
00103
00104 elf_start = handle->elf_image;
00105 ehdr = (Elf32_Ehdr *)(handle->elf_image);
00106
00107 return check_spe_elf(ehdr);
00108 }
00109
00110 int
00111 _base_spe_parse_isolated_elf(spe_program_handle_t *handle,
00112 uint64_t *addr, uint32_t *size)
00113 {
00114 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)handle->elf_image;
00115 Elf32_Phdr *phdr;
00116
00117 if (!ehdr) {
00118 DEBUG_PRINTF("No ELF image has been loaded\n");
00119 errno = EINVAL;
00120 return -errno;
00121 }
00122
00123 if (ehdr->e_phentsize != sizeof(*phdr)) {
00124 DEBUG_PRINTF("Invalid program header format (phdr size=%d)\n",
00125 ehdr->e_phentsize);
00126 errno = EINVAL;
00127 return -errno;
00128 }
00129
00130 if (ehdr->e_phnum != 1) {
00131 DEBUG_PRINTF("Invalid program header count (%d), expected 1\n",
00132 ehdr->e_phnum);
00133 errno = EINVAL;
00134 return -errno;
00135 }
00136
00137 phdr = (Elf32_Phdr *)(handle->elf_image + ehdr->e_phoff);
00138
00139 if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0) {
00140 DEBUG_PRINTF("SPE program segment is not loadable (type=%x)\n",
00141 phdr->p_type);
00142 errno = EINVAL;
00143 return -errno;
00144 }
00145
00146 if (addr)
00147 *addr = (uint64_t)(unsigned long)
00148 (handle->elf_image + phdr->p_offset);
00149
00150 if (size)
00151 *size = phdr->p_memsz;
00152
00153 return 0;
00154 }
00155
00156 static int
00157 overlay(Elf32_Phdr *ph, Elf32_Phdr *prev_ph)
00158 {
00159
00160
00161
00162
00163 if (prev_ph && (ph->p_vaddr >= prev_ph->p_vaddr) &&
00164 (ph->p_vaddr < (prev_ph->p_vaddr + prev_ph->p_memsz)))
00165 return 1;
00166 else
00167 return 0;
00168 }
00169
00170 static void
00171 copy_to_ld_buffer(spe_program_handle_t *handle, void *buffer, Elf32_Phdr
00172 *ph, Elf32_Off toe_addr, long toe_size)
00173 {
00174 void *start = handle->elf_image;
00175
00176 DEBUG_PRINTF("SPE_LOAD %p (0x%x) -> %p (0x%x) (%i bytes)\n",
00177 buffer + ph->p_vaddr, ph->p_vaddr, start + ph->p_offset,
00178 ph->p_offset, ph->p_filesz);
00179
00180
00181 if (ph->p_vaddr == toe_addr) {
00182
00183
00184 if (toe_size != ph->p_filesz && ph->p_filesz) {
00185 DEBUG_PRINTF("loading base copy\n");
00186 memcpy(buffer + ph->p_vaddr, start + ph->p_offset,
00187 ph->p_filesz);
00188 }
00189
00190
00191 DEBUG_PRINTF("loading toe %X %X\n", ph->p_offset, toe_addr);
00192 memcpy(buffer + ph->p_vaddr, handle->toe_shadow, toe_size);
00193 } else if (ph->p_filesz) {
00194 memcpy(buffer + ph->p_vaddr, start + ph->p_offset,
00195 ph->p_filesz);
00196 }
00197 DEBUG_PRINTF("done ...\n");
00198 }
00199
00200 int
00201 _base_spe_load_spe_elf (spe_program_handle_t *handle, void *ld_buffer, struct spe_ld_info *ld_info)
00202 {
00203 Elf32_Ehdr *ehdr;
00204 Elf32_Phdr *phdr;
00205 Elf32_Phdr *ph, *prev_ph;
00206
00207 Elf32_Shdr *shdr;
00208 Elf32_Shdr *sh;
00209
00210 Elf32_Off toe_addr = 0;
00211 long toe_size = 0;
00212
00213 char* str_table = 0;
00214
00215 int num_load_seg = 0;
00216 void *elf_start;
00217 int ret;
00218
00219 DEBUG_PRINTF ("load_spe_elf(%p, %p)\n", handle, ld_buffer);
00220
00221 elf_start = handle->elf_image;
00222
00223 DEBUG_PRINTF ("load_spe_elf(%p, %p)\n", handle->elf_image, ld_buffer);
00224 ehdr = (Elf32_Ehdr *)(handle->elf_image);
00225
00226
00227 if ((ret=check_spe_elf(ehdr)))
00228 return ret;
00229
00230
00231 phdr = (Elf32_Phdr *) ((char *) ehdr + ehdr->e_phoff);
00232 shdr = (Elf32_Shdr *) ((char *) ehdr + ehdr->e_shoff);
00233 str_table = (char*)ehdr + shdr[ehdr->e_shstrndx].sh_offset;
00234
00235
00236
00237 for (sh = shdr; sh < &shdr[ehdr->e_shnum]; ++sh)
00238 {
00239 DEBUG_PRINTF("section name: %s ( start: 0x%04x, size: 0x%04x)\n", str_table+sh->sh_name, sh->sh_offset, sh->sh_size );
00240 if (strcmp(".toe", str_table+sh->sh_name) == 0) {
00241 DEBUG_PRINTF("section offset: %d\n", sh->sh_offset);
00242 toe_size += sh->sh_size;
00243 if ((toe_addr == 0) || (toe_addr > sh->sh_addr))
00244 toe_addr = sh->sh_addr;
00245 }
00246
00247
00248
00249
00250
00251
00252
00253
00254 #ifdef DEBUG
00255 if (strcmp(".note.spu_name", str_table+sh->sh_name) == 0)
00256 display_debug_output(elf_start, sh);
00257 #endif
00258 }
00259
00260
00261
00262
00263 DEBUG_PRINTF("Segments: 0x%x\n", ehdr->e_phnum);
00264 for (ph = phdr, prev_ph = NULL; ph < &phdr[ehdr->e_phnum]; ++ph) {
00265 switch (ph->p_type) {
00266 case PT_LOAD:
00267 if (!overlay(ph, prev_ph)) {
00268 if (ph->p_filesz < ph->p_memsz) {
00269 DEBUG_PRINTF("padding loaded image with zeros:\n");
00270 DEBUG_PRINTF("start: 0x%04x\n", ph->p_vaddr + ph->p_filesz);
00271 DEBUG_PRINTF("length: 0x%04x\n", ph->p_memsz - ph->p_filesz);
00272 memset(ld_buffer + ph->p_vaddr + ph->p_filesz, 0, ph->p_memsz - ph->p_filesz);
00273 }
00274 copy_to_ld_buffer(handle, ld_buffer, ph,
00275 toe_addr, toe_size);
00276 num_load_seg++;
00277 }
00278 break;
00279 case PT_NOTE:
00280 DEBUG_PRINTF("SPE_LOAD found PT_NOTE\n");
00281 break;
00282 }
00283 }
00284 if (num_load_seg == 0)
00285 {
00286 DEBUG_PRINTF ("no segments to load");
00287 errno = EINVAL;
00288 return -errno;
00289 }
00290
00291
00292 ld_info->entry = ehdr->e_entry;
00293 DEBUG_PRINTF ("entry = 0x%x\n", ehdr->e_entry);
00294
00295 return 0;
00296
00297 }
00298
00299 #ifdef DEBUG
00300 static void
00301 display_debug_output(Elf32_Ehdr *elf_start, Elf32_Shdr *sh)
00302 {
00303 typedef struct
00304 {
00305 unsigned long namesz;
00306 unsigned long descsz;
00307 unsigned long type;
00308 char name[8];
00309 char lookupname[32];
00310 } ELF_NOTE;
00311
00312 ELF_NOTE *note = (ELF_NOTE *)((void *)elf_start+sh->sh_offset);
00313 printf ("Loading SPE program : %s\n", note->lookupname);
00314 printf ("SPU LS Entry Addr : 0x%05x\n", elf_start->e_entry);
00315 }
00316 #endif
00317
00318 static int
00319 toe_check_syms(Elf32_Ehdr *ehdr, Elf32_Shdr *sh)
00320 {
00321 Elf32_Sym *sym, *sym_hdr, *sym_end;
00322 Elf32_Shdr *shdr;
00323 char *str_table;
00324 char *sym_name;
00325 int ret;
00326
00327 shdr = (Elf32_Shdr*) ((char*) ehdr + ehdr->e_shoff);
00328 sym_hdr = (Elf32_Sym*) ((char*) ehdr + sh->sh_offset);
00329 sym_end = (Elf32_Sym*) ((char*) ehdr + sh->sh_offset + sh->sh_size);
00330 str_table = (char*)ehdr + shdr[sh->sh_link].sh_offset;
00331
00332 ret = 0;
00333 for (sym = sym_hdr; sym < sym_end; sym++)
00334 if (sym->st_name) {
00335 sym_name = str_table + sym->st_name;
00336 if ((strncmp(sym_name, "_EAR_", 5) == 0) &&
00337 (strcmp(sym_name, "_EAR_") != 0)) {
00338
00339
00340
00341
00342
00343
00344
00345 fprintf(stderr, "Invalid _EAR_ symbol '%s'\n",
00346 sym_name);
00347 errno = EINVAL;
00348 ret = 1;
00349 }
00350 }
00351 return ret;
00352 }
00353
00354 int _base_spe_toe_ear (spe_program_handle_t *speh)
00355 {
00356 Elf32_Ehdr *ehdr;
00357 Elf32_Shdr *shdr, *sh;
00358 char *str_table;
00359 char **ch;
00360 int ret;
00361 long toe_size;
00362
00363 ehdr = (Elf32_Ehdr*) (speh->elf_image);
00364 shdr = (Elf32_Shdr*) ((char*) ehdr + ehdr->e_shoff);
00365 str_table = (char*)ehdr + shdr[ehdr->e_shstrndx].sh_offset;
00366
00367 toe_size = 0;
00368 for (sh = shdr; sh < &shdr[ehdr->e_shnum]; ++sh)
00369 if (strcmp(".toe", str_table + sh->sh_name) == 0)
00370 toe_size += sh->sh_size;
00371
00372 ret = 0;
00373 if (toe_size > 0) {
00374 for (sh = shdr; sh < &shdr[ehdr->e_shnum]; ++sh)
00375 if (sh->sh_type == SHT_SYMTAB || sh->sh_type ==
00376 SHT_DYNSYM)
00377 ret = toe_check_syms(ehdr, sh);
00378 if (!ret && toe_size != 16) {
00379
00380 fprintf(stderr, "Unexpected toe size of %ld\n",
00381 toe_size);
00382 errno = EINVAL;
00383 ret = 1;
00384 }
00385 }
00386 if (!ret && toe_size) {
00387
00388
00389
00390 speh->toe_shadow = malloc(toe_size);
00391 if (speh->toe_shadow) {
00392 ch = (char**) speh->toe_shadow;
00393 if (sizeof(char*) == 8) {
00394 ch[0] = (char*) speh->elf_image;
00395 ch[1] = 0;
00396 } else {
00397 ch[0] = 0;
00398 ch[1] = (char*) speh->elf_image;
00399 ch[2] = 0;
00400 ch[3] = 0;
00401 }
00402 } else {
00403 errno = ENOMEM;
00404 ret = 1;
00405 }
00406 }
00407 return ret;
00408 }
00409