libspe2 0.9a
|
00001 /* 00002 * libspe2 - A wrapper to allow direct execution of SPE binaries 00003 * Copyright (C) 2005 IBM Corp. 00004 * 00005 * This library is free software; you can redistribute it and/or modify it 00006 * under the terms of the GNU Lesser General Public License as published by 00007 * the Free Software Foundation; either version 2.1 of the License, 00008 * or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, but 00011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 00012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 00013 * License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this library; if not, write to the Free Software Foundation, 00017 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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 /*DEBUG*/ 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 /* Validate ELF */ 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 /* Validate the machine type */ 00075 if (ehdr->e_machine != 0x17) 00076 { 00077 DEBUG_PRINTF ("not an SPE ELF object"); 00078 errno = EINVAL; 00079 return -errno; 00080 } 00081 00082 /* Validate ELF object type. */ 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 * If our ph segment virtual address fits within that of the 00161 * previous ph, this is an overlay. 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 /* toe segment comes from the shadow */ 00181 if (ph->p_vaddr == toe_addr) { 00182 /* still makes a copy if toe is buried with other 00183 * sections */ 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 /* overlay only the total toe section size */ 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 /* Check for a Valid SPE ELF Image (again) */ 00227 if ((ret=check_spe_elf(ehdr))) 00228 return ret; 00229 00230 /* Start processing headers */ 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 /* traverse the sections to locate the toe segment */ 00236 /* by specification, the toe sections are grouped together in a segment */ 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 /* Disabled : Actually not needed, only good for testing 00247 if (strcmp(".bss", str_table+sh->sh_name) == 0) { 00248 DEBUG_PRINTF("zeroing .bss section:\n"); 00249 DEBUG_PRINTF("section offset: 0x%04x\n", sh->sh_offset); 00250 DEBUG_PRINTF("section size: 0x%04x\n", sh->sh_size); 00251 memset(ld_buffer + sh->sh_offset, 0, sh->sh_size); 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 /*DEBUG*/ 00258 } 00259 00260 /* 00261 * Load all PT_LOAD segments onto the SPE local store buffer. 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 /* Remember where the code wants to be started */ 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 /*DEBUG*/ 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 * We have a prefix of _EAR_ followed by 00340 * something else. This is not currently 00341 * (and might not ever be) supported: for 00342 * a _EAR_foo, it requires a lookup of foo 00343 * in the ppu ELF file. 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 /* Paranoia */ 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 * Allocate toe_shadow, and fill it with elf_image. 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