pcsx2/fps2bios/kernel/iopload/iopelf.c

429 lines
9.2 KiB
C

#include "romdir.h"
#include "iopelf.h"
typedef struct {
u32 st_name;
u32 st_value;
u32 st_size;
u8 st_info;
u8 st_other;
u16 st_shndx;
} Elf32_Sym;
char *sections_names;
ELF_HEADER *elfHeader;
ELF_PHR *elfProgH;
ELF_SHR *elfSectH;
u8 *elfdata;
int elfsize;
u32 elfbase;
static int debug=1;
#define _dprintf(fmt, args...) \
if (debug > 0) __printf("iopelf: " fmt, ## args)
static void __memcpy(void *dest, const void *src, int n) {
const u8 *s = (u8*)src;
u8 *d = (u8*)dest;
while (n) {
*d++ = *s++; n--;
}
}
int loadHeaders() {
elfHeader = (ELF_HEADER*)elfdata;
if ((elfHeader->e_shentsize != sizeof(ELF_SHR)) && (elfHeader->e_shnum > 0)) {
return -1;
}
#ifdef ELF_LOG
ELF_LOG( "type: " );
#endif
switch( elfHeader->e_type )
{
default:
#ifdef ELF_LOG
ELF_LOG( "unknown %x", elfHeader->e_type );
#endif
break;
case 0x0:
#ifdef ELF_LOG
ELF_LOG( "no file type" );
#endif
break;
case 0x1:
#ifdef ELF_LOG
ELF_LOG( "relocatable" );
#endif
break;
case 0x2:
#ifdef ELF_LOG
ELF_LOG( "executable" );
#endif
break;
}
#ifdef ELF_LOG
ELF_LOG( "\n" );
ELF_LOG( "machine: " );
#endif
switch ( elfHeader->e_machine )
{
default:
#ifdef ELF_LOG
ELF_LOG( "unknown" );
#endif
break;
case 0x8:
#ifdef ELF_LOG
ELF_LOG( "mips_rs3000" );
#endif
break;
}
#ifdef ELF_LOG
ELF_LOG("\n");
ELF_LOG("version: %d\n",elfHeader->e_version);
ELF_LOG("entry: %08x\n",elfHeader->e_entry);
ELF_LOG("flags: %08x\n",elfHeader->e_flags);
ELF_LOG("eh size: %08x\n",elfHeader->e_ehsize);
ELF_LOG("ph off: %08x\n",elfHeader->e_phoff);
ELF_LOG("ph entsiz: %08x\n",elfHeader->e_phentsize);
ELF_LOG("ph num: %08x\n",elfHeader->e_phnum);
ELF_LOG("sh off: %08x\n",elfHeader->e_shoff);
ELF_LOG("sh entsiz: %08x\n",elfHeader->e_shentsize);
ELF_LOG("sh num: %08x\n",elfHeader->e_shnum);
ELF_LOG("sh strndx: %08x\n",elfHeader->e_shstrndx);
ELF_LOG("\n");
#endif
return 0;
}
int loadProgramHeaders() {
int i;
if (elfHeader->e_phnum == 0) {
return 0;
}
if (elfHeader->e_phentsize != sizeof(ELF_PHR)) {
return -1;
}
elfProgH = (ELF_PHR*)&elfdata[elfHeader->e_phoff];
for ( i = 0 ; i < elfHeader->e_phnum ; i++ )
{
#ifdef ELF_LOG
ELF_LOG( "Elf32 Program Header\n" );
ELF_LOG( "type: " );
#endif
switch ( elfProgH[ i ].p_type )
{
default:
#ifdef ELF_LOG
ELF_LOG( "unknown %x", (int)elfProgH[ i ].p_type );
#endif
break;
case 0x1:
#ifdef ELF_LOG
ELF_LOG("load");
#endif
/* if ( elfHeader->e_shnum == 0 ) {*/
if (elfProgH[ i ].p_offset < elfsize) {
int size;
if ((elfProgH[ i ].p_filesz + elfProgH[ i ].p_offset) > elfsize) {
size = elfsize - elfProgH[ i ].p_offset;
} else {
size = elfProgH[ i ].p_filesz;
}
_dprintf("loading program at %x, size=%x\n", elfProgH[ i ].p_paddr + elfbase, size);
__memcpy((void*)(elfProgH[ i ].p_paddr + elfbase),
&elfdata[elfProgH[ i ].p_offset],
size);
}
#ifdef ELF_LOG
ELF_LOG("\t*LOADED*");
#endif
// }
break;
}
#ifdef ELF_LOG
ELF_LOG("\n");
ELF_LOG("offset: %08x\n",(int)elfProgH[i].p_offset);
ELF_LOG("vaddr: %08x\n",(int)elfProgH[i].p_vaddr);
ELF_LOG("paddr: %08x\n",elfProgH[i].p_paddr);
ELF_LOG("file size: %08x\n",elfProgH[i].p_filesz);
ELF_LOG("mem size: %08x\n",elfProgH[i].p_memsz);
ELF_LOG("flags: %08x\n",elfProgH[i].p_flags);
ELF_LOG("palign: %08x\n",elfProgH[i].p_align);
ELF_LOG("\n");
#endif
}
return 0;
}
void _relocateElfSection(int i) {
ELF_REL *rel;
int size = elfSectH[i].sh_size / 4;
int r = 0;
u32 *ptr, *tmp;
ELF_SHR *rsec = &elfSectH[elfSectH[i].sh_info];
u8 *mem = (u8*)(elfSectH[i].sh_addr + elfbase);
u32 imm;
int j;
ptr = (u32*)(elfdata+elfSectH[i].sh_offset);
// _dprintf("relocating section %s\n", &sections_names[rsec->sh_name]);
// __printf("sh_addr %x\n", elfSectH[i].sh_addr);
while (size > 0) {
rel = (ELF_REL*)&ptr[r];
// __printf("rel size=%x: offset=%x, info=%x\n", size, rel->r_offset, rel->r_info);
tmp = (u32*)&mem[rel->r_offset];
switch ((u8)rel->r_info) {
case 2: // R_MIPS_32
*tmp+= elfbase; break;
case 4: // R_MIPS_26
*tmp = (*tmp & 0xfc000000) |
(((*tmp & 0x03ffffff) + (elfbase >> 2)) & 0x03ffffff);
break;
case 5: // R_MIPS_HI16
imm = (((*tmp & 0xffff) + (elfbase >> 16)) & 0xffff);
for (j=(r+2)/2; j<elfSectH[i].sh_size / 4; j++) {
if (j*2 == r) continue;
if ((u8)((ELF_REL*)&ptr[j*2])->r_info == 6)
break;
// if ((rel->r_info >> 8) == (((ELF_REL*)&ptr[j*2])->r_info >> 8))
// break;
}
/* if (j != elfSectH[i].sh_size / 4)*/ {
u32 *p;
rel = (ELF_REL*)&ptr[j*2];
// __printf("HI16: found match: %x\n", rel->r_offset);
p = (u32*)&mem[rel->r_offset];
// __printf("%x + %x = %x\n", *p, elfbase, (*p & 0xffff) + (elfbase & 0xffff));
if (((*p & 0xffff) + (elfbase & 0xffff)) & 0x8000) {
// __printf("found\n");
imm++;
}
}
*tmp = (*tmp & 0xffff0000) | imm;
break;
case 6: // R_MIPS_LO16
*tmp = (*tmp & 0xffff0000) |
(((*tmp & 0xffff) + (elfbase & 0xffff)) & 0xffff);
break;
default:
__printf("UNKNOWN R_MIPS REL!!\n");
break;
}
size-= 2; r+= 2;
}
}
int loadSectionHeaders() {
int i;
int i_st = -1;
int i_dt = -1;
if (elfHeader->e_shnum == 0) {
return -1;
}
elfSectH = (ELF_SHR*)&elfdata[elfHeader->e_shoff];
if ( elfHeader->e_shstrndx < elfHeader->e_shnum ) {
sections_names = (char *)&elfdata[elfSectH[ elfHeader->e_shstrndx ].sh_offset];
}
for ( i = 0 ; i < elfHeader->e_shnum ; i++ )
{
#ifdef ELF_LOG
ELF_LOG( "Elf32 Section Header [%x] %s", i, &sections_names[ elfSectH[ i ].sh_name ] );
#endif
/* if ( elfSectH[i].sh_flags & 0x2 ) {
if (elfSectH[i].sh_offset < elfsize) {
int size;
if ((elfSectH[i].sh_size + elfSectH[i].sh_offset) > elfsize) {
size = elfsize - elfSectH[i].sh_offset;
} else {
size = elfSectH[i].sh_size;
}
memcpy(&psM[ elfSectH[ i ].sh_addr &0x1ffffff ],
&elfdata[elfSectH[i].sh_offset],
size);
}
#ifdef ELF_LOG
ELF_LOG( "\t*LOADED*" );
#endif
}*/
#ifdef ELF_LOG
ELF_LOG("\n");
ELF_LOG("type: ");
#endif
switch ( elfSectH[ i ].sh_type )
{
default:
#ifdef ELF_LOG
ELF_LOG("unknown %08x",elfSectH[i].sh_type);
#endif
break;
case 0x0:
#ifdef ELF_LOG
ELF_LOG("null");
#endif
break;
case 0x1:
#ifdef ELF_LOG
ELF_LOG("progbits");
#endif
break;
case 0x2:
#ifdef ELF_LOG
ELF_LOG("symtab");
#endif
break;
case 0x3:
#ifdef ELF_LOG
ELF_LOG("strtab");
#endif
break;
case 0x4:
#ifdef ELF_LOG
ELF_LOG("rela");
#endif
break;
case 0x8:
#ifdef ELF_LOG
ELF_LOG("no bits");
#endif
break;
case 0x9:
#ifdef ELF_LOG
ELF_LOG("rel");
#endif
break;
}
#ifdef ELF_LOG
ELF_LOG("\n");
ELF_LOG("flags: %08x\n", elfSectH[i].sh_flags);
ELF_LOG("addr: %08x\n", elfSectH[i].sh_addr);
ELF_LOG("offset: %08x\n", elfSectH[i].sh_offset);
ELF_LOG("size: %08x\n", elfSectH[i].sh_size);
ELF_LOG("link: %08x\n", elfSectH[i].sh_link);
ELF_LOG("info: %08x\n", elfSectH[i].sh_info);
ELF_LOG("addralign: %08x\n", elfSectH[i].sh_addralign);
ELF_LOG("entsize: %08x\n", elfSectH[i].sh_entsize);
#endif
// dump symbol table
if (elfSectH[i].sh_type == 0x02) {
i_st = i; i_dt = elfSectH[i].sh_link;
}
}
// now that we have all the stuff loaded, relocate it
for (i = 0 ; i < elfHeader->e_shnum ; i++) {
if (elfSectH[i].sh_type == 0x09) { // relocations
_relocateElfSection(i);
}
}
return 0;
}
void* loadElfFile(ROMFILE_INFO* ri, u32 offset)
{
imageInfo* ii;
ELF_PHR* ph;
ELF_IOPMOD* im;
__printf("loadElfFile: base=%x, size=%x\n", ri->fileData, ri->entry->fileSize);
elfdata = (u8*)(ri->fileData);
elfsize = ri->entry->fileSize;
elfbase = offset+0x30;
loadHeaders();
// fill the image info header
ph= (ELF_PHR*)((char*)elfHeader +elfHeader->e_phoff);
im= (ELF_IOPMOD*)((char*)elfHeader + ph[0].p_offset);
ii = (imageInfo*)offset;
if( *(u16*)(elfHeader->e_ident+4) != 0x101 )
return NULL;
if (elfHeader->e_machine != EM_MIPS)
return NULL;
if (elfHeader->e_phentsize != sizeof(ELF_PHR))
return NULL;
if (elfHeader->e_phnum != 2)
return NULL;
if (ph[0].p_type != PT_SCE_IOPMOD)
return NULL;
if (elfHeader->e_type != ET_SCE_IOPRELEXEC){
if (elfHeader->e_type != elfHeader->e_phnum )//ET_EXEC)
return NULL;
//result->type=3;
}
//else result->type=4;
ii->next =0;
ii->name =NULL;
ii->version =0;
ii->flags =0;
ii->modid =0;
if ((int)im->moduleinfo != -1) {
moduleInfo* minfo = (moduleInfo*)(im->moduleinfo+ph[1].p_vaddr); // probably wrong
ii->name = minfo->name;
ii->version = minfo->version;
}
else {
ii->name = NULL;
ii->version = 0;
}
ii->entry = im->entry;
ii->gp_value = im->gp_value;
ii->p1_vaddr = ph[1].p_vaddr;
ii->text_size = im->text_size;
ii->data_size = im->data_size;
ii->bss_size = im->bss_size;
loadProgramHeaders();
loadSectionHeaders();
_dprintf("loadElfFile: e_entry=%x, hdr=%x\n", elfHeader->e_entry, elfHeader);
return (void*)(elfbase+elfHeader->e_entry);
}