Created
June 17, 2018 13:31
-
-
Save psxdev/3a2e77c8176d4b72432a40b146528c56 to your computer and use it in GitHub Desktop.
main.c for eboot.bin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//dont wait an app from me, here source perhaps it can help to get all pieces togeher, now all is up to you | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <kernel.h> | |
#include <system_service.h> | |
#include <orbis2d.h> | |
#include <orbisPad.h> | |
#include <orbisAudio.h> | |
#include <modplayer.h> | |
#include <ps4link.h> | |
#include <debugnet.h> | |
#include <orbissys.h> | |
#include <string.h> | |
#include <elfloader.h> | |
#include <ps4/error.h> | |
typedef struct OrbisGlobalConf | |
{ | |
Orbis2dConfig *conf; | |
OrbisPadConfig *confPad; | |
OrbisAudioConfig *confAudio; | |
ps4LinkConfiguration *confLink; | |
int orbisLinkFlag; | |
}OrbisGlobalConf; | |
OrbisGlobalConf globalConf; | |
//IV0002-NPXS29040_00-ORBISLINK0000000 | |
size_t sceLibcHeapSize = 256 * 1024 * 1024; | |
typedef struct Ps4MemoryProtected | |
{ | |
void *writable; | |
void *executable; | |
size_t size; | |
}Ps4MemoryProtected; | |
int ps4MemoryProtectedCreate(Ps4MemoryProtected **memory, size_t size) | |
{ | |
int executableHandle, writableHandle; | |
Ps4MemoryProtected *m; | |
long pageSize = 0x4000;//sysconf(_SC_PAGESIZE); | |
if(memory == NULL) | |
return PS4_ERROR_ARGUMENT_PRIMARY_MISSING; | |
if(size == 0) | |
return PS4_ERROR_ARGUMENT_SIZE_NULL; | |
m = (Ps4MemoryProtected *)malloc(sizeof(Ps4MemoryProtected)); | |
if(m == NULL) | |
return PS4_ERROR_OUT_OF_MEMORY; | |
m->size = (size / pageSize + 1) * pageSize; // align to pageSize | |
m->executable = mmap(NULL, m->size, 7, 0x1000, -1, 0); | |
if(m->executable == MAP_FAILED) | |
goto e1; | |
m->writable = m->executable; | |
if(m->writable == MAP_FAILED) | |
goto e1; | |
*memory = m; | |
return PS4_OK; | |
e1: | |
free(m); | |
return PS4_ERROR_OUT_OF_MEMORY; // make error codes proper errnos ... everywhere ... meh | |
} | |
int ps4MemoryProtectedDestroy(Ps4MemoryProtected *memory) | |
{ | |
int r = 0; | |
if(memory == NULL) | |
return -1; | |
r |= munmap(memory->writable, memory->size); | |
r |= munmap(memory->executable, memory->size); | |
free(memory); | |
return r; | |
} | |
int ps4MemoryProtectedGetWritableAddress(Ps4MemoryProtected *memory, void **address) | |
{ | |
if(memory == NULL) | |
return PS4_ERROR_ARGUMENT_PRIMARY_MISSING; | |
if(address == NULL) | |
return PS4_ERROR_ARGUMENT_OUT_MISSING; | |
*address = memory->writable; | |
return PS4_OK; | |
} | |
int ps4MemoryProtectedGetExecutableAddress(Ps4MemoryProtected *memory, void **address) | |
{ | |
if(memory == NULL) | |
return PS4_ERROR_ARGUMENT_PRIMARY_MISSING; | |
if(address == NULL) | |
return PS4_ERROR_ARGUMENT_OUT_MISSING; | |
*address = memory->executable; | |
return PS4_OK; | |
} | |
int ps4MemoryProtectedGetSize(Ps4MemoryProtected *memory, size_t *size) | |
{ | |
if(memory == NULL) | |
return PS4_ERROR_ARGUMENT_PRIMARY_MISSING; | |
if(size == NULL) | |
return PS4_ERROR_ARGUMENT_OUT_MISSING; | |
*size = memory->size; | |
return PS4_OK; | |
} | |
void orbisMemorySet(void *p,unsigned char value,int size) | |
{ | |
unsigned char *buf=(unsigned char *)p; | |
//for(i=0;i<size;i++) | |
//{ | |
// buf[i]=value; | |
//} | |
debugNetPrintf(3,"[ORBISLINK] orbisMemorySet before memset\n"); | |
memset(buf,value,size); | |
debugNetPrintf(3,"[ORBISLINK] orbisMemorySet after memset\n"); | |
} | |
void orbisMemoryCopy(void *to,void *from,size_t size) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisMemoryCopy before memcpy\n"); | |
memcpy(to,from,size); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisMemoryCopy after memcpy\n"); | |
} | |
/* Defines */ | |
#define elfRelocationSymbol __ELFN(R_SYM) | |
#define elfRelocationType __ELFN(R_TYPE) | |
#define elfRelocationInfo __ELFN(R_INFO) | |
#define elfSymbolBind __ELFN(ST_BIND) | |
#define elfSymbolType __ELFN(ST_TYPE) | |
#define elfSymbolInfo __ELFN(ST_INFO) | |
#define elfIsElf(e) IS_ELF(*elfHeader(e)) // FIXME: Null deref | |
#define elfClass(e) (e == NULL ? 0 : e->data[4]) | |
#define elfEncoding(e) (e == NULL ? 0 : e->data[5]) | |
#define elfVersion(e) (e == NULL ? 0 : e->data[6]) | |
#define elfABI(e) (e == NULL ? 0 : e->data[7]) | |
/* Constants */ | |
enum{ ELF_MAXIMAL_STRING_LENGTH = 4096 }; | |
/* Type */ | |
typedef struct Elf // FIXME: We could cache a lot of offsets here to inc. performance | |
{ | |
uint8_t *data; | |
size_t size; // FIXME: Do more checks on size | |
} | |
Elf; | |
size_t elfGetSize(Elf *elf) | |
{ | |
return elf->size; | |
} | |
uint8_t *elfGetData(Elf *elf) | |
{ | |
return elf->data; | |
} | |
/* --- elf header --- */ | |
ElfHeader *elfHeader(Elf *elf) | |
{ | |
if(!elf) | |
return NULL; | |
return (ElfHeader *)elf->data; | |
} | |
uint64_t elfEntry(Elf *elf) | |
{ | |
if(!elf) | |
return 0; | |
ElfHeader *h = elfHeader(elf); | |
if(!h) | |
return 0; | |
return h->e_entry; | |
} | |
uint64_t elfLargestAlignment(Elf *elf) //ignore ... | |
{ | |
uint16_t index = 0; | |
uint64_t alignment = 0; | |
while(1) | |
{ | |
ElfSegment *h = elfSegment(elf, &index, ELF_SEGMENT_ATTRIBUTE_TYPE, PT_LOAD); | |
if(!h) | |
break; | |
// FIXME: Tired of bogus 2MB alignment -> ignore | |
if(alignment < h->p_align && h->p_align < 0x200000) | |
alignment = h->p_align; | |
++index; | |
} | |
return alignment; | |
} | |
size_t elfMemorySize(Elf *elf) | |
{ | |
ElfSection *sections; | |
ElfSegment *segments; | |
uint16_t size; | |
uint16_t length; | |
uint16_t index; | |
size_t memorySize = 0; | |
if(!elf) | |
return 0; | |
segments = elfSegments(elf, &size, &length); | |
if(segments) | |
{ | |
for(index = 0; index < length; ++index) | |
{ | |
ElfSegment *s = (ElfSegment *)((uint8_t *)segments + index * size); | |
if(memorySize < s->p_paddr + s->p_memsz) | |
memorySize = s->p_paddr + s->p_memsz; | |
} | |
} | |
else | |
{ | |
length = 0; | |
sections = elfSections(elf, &size, &length); | |
if(!sections) | |
return 0; | |
for(index = 0; index < length; ++index) | |
{ | |
ElfSection *s = (ElfSection *)((uint8_t *)sections + index * size); | |
if(memorySize < s->sh_addr + s->sh_size) | |
memorySize = s->sh_addr + s->sh_size; | |
} | |
} | |
return memorySize; | |
} | |
/* --- elf section header --- */ | |
char *elfSectionStrings(Elf *elf, uint64_t *size) | |
{ | |
ElfHeader *h; | |
uint16_t i; | |
ElfSection *s; | |
h = elfHeader(elf); | |
i = h->e_shstrndx; | |
s = elfSection(elf, &i, ELF_SECTION_ATTRIBUTE_NONE, 0); | |
if(size) | |
*size = s->sh_size; | |
return (char *)elf->data + s->sh_offset; | |
} | |
uint64_t elfSectionAttribute(ElfSection *elfSection, ElfSectionAttribute attribute) | |
{ | |
switch(attribute) | |
{ | |
case ELF_SECTION_ATTRIBUTE_NAME: | |
return elfSection->sh_name; | |
case ELF_SECTION_ATTRIBUTE_TYPE: | |
return elfSection->sh_type; | |
case ELF_SECTION_ATTRIBUTE_FLAGS: | |
return elfSection->sh_flags; | |
case ELF_SECTION_ATTRIBUTE_ADDRESS: | |
return elfSection->sh_addr; | |
case ELF_SECTION_ATTRIBUTE_OFFSET: | |
return elfSection->sh_offset; | |
case ELF_SECTION_ATTRIBUTE_SIZE: | |
return elfSection->sh_size; | |
case ELF_SECTION_ATTRIBUTE_LINK: | |
return elfSection->sh_link; | |
case ELF_SECTION_ATTRIBUTE_INFO: | |
return elfSection->sh_info; | |
case ELF_SECTION_ATTRIBUTE_MEMORY_ALIGNMENT: | |
return elfSection->sh_addralign; | |
case ELF_SECTION_ATTRIBUTE_ENTRY_SIZE: | |
return elfSection->sh_entsize; | |
default: | |
break; | |
} | |
return 0; | |
} | |
ElfSection *elfSections(Elf *elf, uint16_t *size, uint16_t *length) | |
{ | |
ElfHeader *h; | |
if(!elf) | |
return NULL; | |
h = elfHeader(elf); | |
if(h->e_shoff == 0) | |
return NULL; | |
if(size != NULL) | |
*size = h->e_shentsize; | |
if(length != NULL) | |
*length = h->e_shnum; | |
return (ElfSection *)(elf->data + h->e_shoff); | |
} | |
ElfSection *elfSection(Elf *elf, uint16_t *index, ElfSectionAttribute attribute, uint64_t value) | |
{ | |
uint16_t size; | |
uint16_t length; | |
ElfSection *h, *t; | |
uint16_t i = 0; | |
if(!index) | |
index = &i; | |
h = elfSections(elf, &size, &length); | |
if(!h) | |
return NULL; | |
for(; *index < length; ++(*index)) | |
{ | |
t = (ElfSection *)((uint8_t *)h + *index * size); | |
if(attribute == ELF_SECTION_ATTRIBUTE_NONE || elfSectionAttribute(t, attribute) == value) | |
return t; | |
} | |
return NULL; | |
} | |
ElfSection *elfSectionByName(Elf *elf, char *name) | |
{ | |
uint64_t size; | |
char *mem = elfSectionStrings(elf, &size); | |
uint32_t offset = elfStringToOffset(mem, size, name); | |
ElfSection *sh = elfSection(elf, NULL, ELF_SECTION_ATTRIBUTE_NAME, offset); | |
return sh; | |
} | |
/* --- elf segment header --- */ | |
uint64_t elfSegmentAttribute(ElfSegment *elfSegment, ElfSegmentAttribute attribute) | |
{ | |
switch(attribute) | |
{ | |
case ELF_SEGMENT_ATTRIBUTE_TYPE: | |
return elfSegment->p_type; | |
case ELF_SEGMENT_ATTRIBUTE_FLAGS: | |
return elfSegment->p_flags; | |
case ELF_SEGMENT_ATTRIBUTE_OFFSET: | |
return elfSegment->p_offset; | |
case ELF_SEGMENT_ATTRIBUTE_VIRTUAL_ADDRESS: | |
return elfSegment->p_vaddr; | |
case ELF_SEGMENT_ATTRIBUTE_PHYSICAL_ADDRESS: | |
return elfSegment->p_paddr; | |
case ELF_SEGMENT_ATTRIBUTE_FILE_SIZE: | |
return elfSegment->p_filesz; | |
case ELF_SEGMENT_ATTRIBUTE_MEMORY_SIZE: | |
return elfSegment->p_memsz; | |
case ELF_SEGMENT_ATTRIBUTE_ALIGNMENT: | |
return elfSegment->p_align; | |
default: | |
break; | |
} | |
return 0; | |
} | |
ElfSegment *elfSegments(Elf *elf, uint16_t *size, uint16_t *length) | |
{ | |
ElfHeader *h; | |
if(!elf) | |
return NULL; | |
h = elfHeader(elf); | |
if(h->e_phoff == 0) | |
return NULL; | |
if(size != NULL) | |
*size = h->e_phentsize; | |
if(length != NULL) | |
*length = h->e_phnum; | |
return (ElfSegment *)(elf->data + h->e_phoff); | |
} | |
ElfSegment *elfSegment(Elf *elf, uint16_t *index, ElfSegmentAttribute attribute, uint64_t value) | |
{ | |
uint16_t size; | |
uint16_t length; | |
ElfSegment *h, *t; | |
uint16_t i = 0; | |
if(!index) | |
index = &i; | |
h = elfSegments(elf, &size, &length); | |
if(!h) | |
return NULL; | |
for(; *index < length; ++(*index)) | |
{ | |
t = (ElfSegment *)((uint8_t *)h + *index * size); | |
if(attribute == ELF_SEGMENT_ATTRIBUTE_NONE || elfSegmentAttribute(t, attribute) == value) | |
return t; | |
} | |
return NULL; | |
} | |
/* --- elf dynamic section --- */ | |
uint64_t elfDynamicAttribute(ElfDynamic *elfDynamic, ElfDynamicAttribute attribute) | |
{ | |
switch(attribute) | |
{ | |
case ELF_DYNAMIC_ATTRIBUTE_TAG: | |
return elfDynamic->d_tag; | |
case ELF_DYNAMIC_ATTRIBUTE_VALUE: | |
return elfDynamic->d_un.d_val; | |
case ELF_DYNAMIC_ATTRIBUTE_POINTER: | |
return elfDynamic->d_un.d_ptr; | |
default: | |
break; | |
} | |
return 0; | |
} | |
uint16_t elfDynamicsLength(ElfDynamic *dyn) | |
{ | |
uint16_t i = 0; | |
if(dyn != NULL) | |
for(;dyn->d_tag != DT_NULL; ++dyn) | |
++i; | |
return i; | |
} | |
ElfDynamic *elfDynamics(Elf *elf, uint16_t *size, uint16_t *length) | |
{ | |
ElfSection *h; | |
ElfSegment *h2; | |
if(!elf) | |
return NULL; | |
if((h = elfSection(elf, NULL, ELF_SECTION_ATTRIBUTE_TYPE, SHT_DYNAMIC))) | |
{ | |
if(size != NULL) | |
*size = h->sh_entsize; | |
if(length != NULL) | |
*length = h->sh_size / h->sh_entsize; | |
return (ElfDynamic *)(elf->data + h->sh_offset); | |
} | |
else if((h2 = elfSegment(elf, NULL, ELF_SEGMENT_ATTRIBUTE_TYPE, PT_DYNAMIC))) | |
{ | |
if(size != NULL) | |
*size = sizeof(ElfDynamic); | |
if(length != NULL) //h2->p_filesz / sizeof(ElfDynamic); | |
*length = elfDynamicsLength((ElfDynamic *)(elf->data + h2->p_offset)); | |
return (ElfDynamic *)(elf->data + h2->p_offset); | |
} | |
return NULL; | |
} | |
ElfDynamic *elfDynamic(Elf *elf, uint16_t *index, ElfDynamicAttribute attribute, uint64_t value) | |
{ | |
uint16_t size; | |
uint16_t length; | |
ElfDynamic *h, *t; | |
uint16_t i = 0; | |
if(!index) | |
index = &i; | |
h = elfDynamics(elf, &size, &length); | |
if(!h) | |
return NULL; | |
for(; *index < length; ++(*index)) | |
{ | |
t = (ElfDynamic *)((uint8_t *)h + *index * size); | |
if(attribute == ELF_DYNAMIC_ATTRIBUTE_NONE || elfDynamicAttribute(t, attribute) == value) | |
return t; | |
} | |
return NULL; | |
} | |
ElfDynamic *elfLoadedDynamics(Elf *elf, uint16_t *size, uint16_t *length) | |
{ | |
//ElfSection *h; | |
ElfSegment *h2; | |
if(!elf) | |
return NULL; | |
if((h2 = elfSegment(elf, NULL, ELF_SEGMENT_ATTRIBUTE_TYPE, PT_DYNAMIC))) | |
{ | |
if(size != NULL) | |
*size = sizeof(ElfDynamic); | |
if(length != NULL) | |
*length = elfDynamicsLength((ElfDynamic *)h2->p_vaddr); | |
return (ElfDynamic *)h2->p_vaddr; | |
} | |
return NULL; | |
} | |
ElfDynamic *elfLoadedDynamic(Elf *elf, uint16_t *index, ElfDynamicAttribute attribute, uint64_t value) | |
{ | |
uint16_t size; | |
uint16_t length; | |
ElfDynamic *h, *t; | |
uint16_t i = 0; | |
if(!index) | |
index = &i; | |
h = elfLoadedDynamics(elf, &size, &length); | |
if(!h) | |
return NULL; | |
for(; *index < length; ++(*index)) | |
{ | |
t = (ElfDynamic *)((uint8_t *)h + *index * size); | |
if(attribute == ELF_DYNAMIC_ATTRIBUTE_NONE || elfDynamicAttribute(t, attribute) == value) | |
return t; | |
} | |
return NULL; | |
} | |
/* --- elf string tables --- */ | |
char *elfStringFromIndex(char *mem, uint64_t size, uint32_t index) | |
{ | |
uint64_t i, j = 0; | |
if(!mem) | |
return NULL; | |
if(index == 0) | |
return mem; | |
for(i = 0; i < size - 1; ++i) | |
if(mem[i] == '\0' && ++j == index) | |
return mem + i + 1; | |
return NULL; | |
} | |
char *elfStringFromOffset(char *mem, uint64_t size, uint32_t offset) | |
{ | |
if(!mem || offset >= size) | |
return NULL; | |
return mem + offset; | |
} | |
uint32_t elfStringToOffset(char *mem, uint64_t size, char *str) | |
{ | |
uint64_t i, j; | |
if(!str) | |
return 0; | |
for(i = 0; i < size; ++i) | |
{ | |
for(j = 0; j < ELF_MAXIMAL_STRING_LENGTH && mem[i + j] == str[j]; ++j) | |
if(str[j] == '\0') | |
return i; | |
} | |
return 0; | |
} | |
uint32_t elfStringToIndex(char *mem, uint64_t size, char *str) | |
{ | |
uint64_t index, i, j; | |
if(!str) | |
return 0; | |
index = 0; | |
for(i = 0; i < size; ++i) | |
{ | |
for(j = 0; j < ELF_MAXIMAL_STRING_LENGTH && mem[i + j] == str[j]; ++j) | |
if(str[j] == '\0') | |
return index; | |
if(mem[i] == '\0') | |
index++; | |
} | |
return 0; | |
} | |
/* --- elf relocations --- */ | |
uint64_t elfAddendRelocationAttribute(ElfAddendRelocation *elfAddendRelocation, ElfAddendRelocationAttribute attribute) | |
{ | |
switch(attribute) | |
{ | |
case ELF_ADDEND_RELOCATION_ATTRIBUTE_INFO: | |
return elfAddendRelocation->r_info; | |
case ELF_ADDEND_RELOCATION_ATTRIBUTE_OFFSET: | |
return elfAddendRelocation->r_offset; | |
case ELF_ADDEND_RELOCATION_ATTRIBUTE_ADDEND: | |
return elfAddendRelocation->r_addend; | |
default: | |
break; | |
} | |
return 0; | |
} | |
ElfAddendRelocation *elfAddendRelocations(Elf *elf, char *name, uint16_t *size, uint16_t *length) | |
{ | |
ElfSection *h; | |
h = elfSectionByName(elf, name); | |
if(!h || h->sh_type != SHT_RELA) | |
return NULL; | |
if(size != NULL) | |
*size = h->sh_entsize; | |
if(length != NULL) | |
*length = h->sh_size / h->sh_entsize; | |
return (ElfAddendRelocation *)(elf->data + h->sh_offset); | |
} | |
// FIXME this is not performant, better to pass in the base ElfAddendRelocation *, size and length | |
/* | |
ElfAddendRelocation *elfAddendRelocation(Elf *elf, char *name, uint16_t *index, ElfAddendRelocationAttribute attribute, uint64_t value) | |
{ | |
uint16_t size; | |
uint16_t length; | |
ElfAddendRelocation *h, *t; | |
uint16_t i = 0; | |
if(!index) | |
index = &i; | |
h = elfAddendRelocations(elf, name, &size, &length); | |
if(!h) | |
return NULL; | |
for(; *index < length; ++(*index)) | |
{ | |
t = (ElfAddendRelocation *)((uint8_t *)h + *index * size); | |
if(attribute == ElfAddendRelocationAttributeNone || elfAddendRelocationAttribute(t, attribute) == value) | |
return t; | |
} | |
return NULL; | |
} | |
*/ | |
/* --- elf symbols --- */ | |
uint64_t elfSymbolAttribute(ElfSymbol *elfSymbol, ElfSymbolAttribute attribute) | |
{ | |
switch(attribute) | |
{ | |
case ELF_SYMBOL_ATTRIBUTE_NAME: | |
return elfSymbol->st_name; | |
case ELF_SYMBOL_ATTRIBUTE_INFO: | |
return elfSymbol->st_info; | |
case ELF_SYMBOL_ATTRIBUTE_UNUSED: | |
return elfSymbol->st_other; | |
case ELF_SYMBOL_ATTRIBUTE_SECTION_INDEX: | |
return elfSymbol->st_shndx; | |
case ELF_SYMBOL_ATTRIBUTE_VALUE: | |
return elfSymbol->st_value; | |
case ELF_SYMBOL_ATTRIBUTE_SIZE: | |
return elfSymbol->st_size; | |
default: | |
break; | |
} | |
return 0; | |
} | |
ElfSymbol *elfSymbols(Elf *elf, char *name, uint16_t *size, uint16_t *length) | |
{ | |
ElfSection *h; | |
h = elfSectionByName(elf, name); | |
if(!h || (h->sh_type != SHT_SYMTAB && h->sh_type != SHT_DYNSYM)) | |
return NULL; | |
if(size != NULL) | |
*size = h->sh_entsize; | |
if(length != NULL) | |
*length = h->sh_size / h->sh_entsize; | |
return (ElfSymbol *)(elf->data + h->sh_offset); | |
} | |
/* | |
ElfSymbol *elfSymbol(Elf *elf, char *name, uint16_t *index, ElfSymbolAttribute attribute, uint64_t value) | |
{ | |
uint16_t size; | |
uint16_t length; | |
ElfSymbol *h, *t; | |
uint16_t i = 0; | |
if(!index) | |
index = &i; | |
h = elfSymbols(elf, name, &size, &length); | |
if(!h) | |
return NULL; | |
for(; *index < length; ++(*index)) | |
{ | |
t = (ElfSymbol *)((uint8_t *)h + *index * size); | |
if(attribute == ElfSymbolAttributeNone || elfSymbolAttribute(t, attribute) == value) | |
return t; | |
} | |
return NULL; | |
}*/ | |
/* actions */ | |
Elf *elfCreate(void *data, size_t size) | |
{ | |
Elf *elf, t; | |
if(data == NULL) | |
return NULL; | |
t.data = data; | |
t.size = size; | |
if(!elfIsElf(&t)) | |
return NULL; | |
elf = malloc(sizeof(Elf)); | |
if(elf==NULL) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] elfCreate error malloc return null\n"); | |
return NULL; | |
} | |
elf->data = (uint8_t *)data; | |
elf->size = size; | |
return elf; | |
} | |
Elf *elfCreateLocal(void *elfl, void *data, size_t size) | |
{ | |
Elf *elf, t; | |
if(elfl == NULL || data == NULL) | |
return NULL; | |
t.data = data; | |
t.size = size; | |
if(!elfIsElf(&t)) | |
return NULL; | |
elf = (Elf *)elfl; | |
elf->data = (uint8_t *)data; | |
elf->size = size; | |
return elf; | |
} | |
Elf *elfCreateLocalUnchecked(void *elfl, void *data, size_t size) | |
{ | |
Elf *elf; | |
if(elfl == NULL || data == NULL) | |
return NULL; | |
elf = (Elf *)elfl; | |
elf->data = (uint8_t *)data; | |
elf->size = size; | |
return elf; | |
} | |
void *elfDestroy(Elf *elf) | |
{ | |
void *data; | |
if(elf == NULL) | |
return NULL; | |
if(elf->data!=NULL) | |
{ | |
//debugNetPrintf(3,"data %x\n",elf->data); | |
//data = elf->data; | |
munmap(elf->data,elf->size); | |
//free(elf->data); | |
} | |
return elf; | |
} | |
void elfDestroyAndFree(Elf *elf) | |
{ | |
void *d; | |
if(elf == NULL) | |
return; | |
//debugNetPrintf(3,"elf %x\n",elf); | |
d = elfDestroy(elf); | |
//debugNetPrintf(3,"d %x\n",d); | |
if(d) | |
free(d); | |
} | |
/* --- --- */ | |
int elfLoaderIsLoadable(Elf *elf) | |
{ | |
ElfHeader *h; | |
if(!elfIsElf(elf)) | |
return 0; | |
h = elfHeader(elf); | |
return elfClass(elf) == ELFCLASS64 && | |
elfEncoding(elf) == ELFDATA2LSB && | |
elfVersion(elf) == EV_CURRENT && | |
(elfABI(elf) == ELFOSABI_SYSV || elfABI(elf) == ELFOSABI_FREEBSD) && | |
h->e_type == ET_DYN && | |
h->e_phoff != 0 && | |
h->e_shoff != 0 && | |
h->e_machine == EM_X86_64 && | |
h->e_version == EV_CURRENT; | |
} | |
int elfLoaderInstantiate(Elf *elf, void *memory) | |
{ | |
ElfSection *sections; | |
ElfSegment *segments; | |
uint16_t size; | |
uint16_t length; | |
uint16_t index; | |
if(elf == NULL) | |
return ELF_LOADER_RETURN_ELF_NULL; | |
if(memory == NULL) | |
return ELF_LOADER_RETURN_NO_WRITABLE_MEMORY; | |
segments = elfSegments(elf, &size, &length); | |
if(segments) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] elfLoaderInstantiate in segments length=%d\n",length); | |
for(index = 0; index < length; ++index) | |
{ | |
ElfSegment *s = (ElfSegment *)((uint8_t *)segments + index * size); | |
if(s->p_filesz) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] elfLoaderInstantiate before elfLoaderInstantiate memcpy %p %p %d\n",(char *)memory + s->p_paddr,elf->data + s->p_offset,s->p_filesz); | |
orbisMemoryCopy((char *)memory + s->p_paddr, elf->data + s->p_offset, s->p_filesz); | |
debugNetPrintf(DEBUG,"[ORBISLINK] elfLoaderInstantiate after elfLoaderInstantiate memcpy\n"); | |
} | |
if(s->p_memsz - s->p_filesz) | |
{ //memset((char *)memory + s->p_paddr + s->p_filesz, 0, s->p_memsz - s->p_filesz); | |
debugNetPrintf(DEBUG,"[ORBISLINK] elfLoaderInstantiate before elfLoaderInstantiate orbisMemorySet\n"); | |
orbisMemorySet((char *)memory + s->p_paddr + s->p_filesz,0,s->p_memsz - s->p_filesz); | |
debugNetPrintf(DEBUG,"[ORBISLINK] elfLoaderInstantiate after elfLoaderInstantiate orbisMemorySet\n"); | |
} | |
} | |
} | |
else | |
{ | |
length = 0; | |
sections = elfSections(elf, &size, &length); | |
if(!sections) | |
return 0; | |
for(index = 0; index < length; ++index) | |
{ | |
ElfSection *s = (ElfSection *)((uint8_t *)sections + index * size); | |
if(!(s->sh_flags & SHF_ALLOC)) | |
continue; | |
if(s->sh_size) | |
{ | |
orbisMemoryCopy((char *)memory + s->sh_addr, elf->data + s->sh_offset, s->sh_size); | |
debugNetPrintf(DEBUG,"[ORBISLINK] elfLoaderInstantiate after elfLoaderInstantiate second memcpy\n"); | |
} | |
} | |
} | |
return ELF_LOADER_RETURN_OK; | |
} | |
int elfLoaderRelativeAddressIsExecutable(Elf *elf, int64_t address) | |
{ | |
ElfSection *sections; | |
ElfSegment *segments; | |
uint16_t size; | |
uint16_t length; | |
uint16_t index; | |
if(elf == NULL) | |
return 0; | |
segments = elfSegments(elf, &size, &length); | |
if(segments) | |
{ | |
for(index = 0; index < length; ++index) | |
{ | |
ElfSegment *s = (ElfSegment *)((uint8_t *)segments + index * size); | |
if(address >= s->p_paddr && address <= s->p_paddr + s->p_memsz) | |
return s->p_flags & PF_X; | |
} | |
} | |
else | |
{ | |
length = 0; | |
sections = elfSections(elf, &size, &length); | |
if(!sections) | |
return ELF_LOADER_RETURN_NO_SECTIONS_OR_SEGMENTS; | |
for(index = 0; index < length; ++index) | |
{ | |
ElfSection *s = (ElfSection *)((uint8_t *)sections + index * size); | |
if(address >= s->sh_addr && address <= s->sh_addr + s->sh_size) | |
return s->sh_flags & SHF_EXECINSTR; | |
} | |
} | |
return 1; // FIXME: Recheck | |
} | |
// FIXME: Implement ps4 aware relocation for functions using dlsym | |
int elfLoaderRelocate(Elf *elf, void *writable, void *executable) | |
{ | |
int i, j; | |
uint16_t relocationSize = 0; | |
uint16_t relocationsLength = 0; | |
ElfAddendRelocation *relocations; | |
uint16_t dynamicSymbolSize = 0; | |
uint16_t dynamicSymbolsLength = 0; | |
ElfSymbol *dynamicSymbols; | |
char *r1 = ".rela.dyn"; | |
char *r2 = ".rela.plt"; | |
char *rel[2] = {r1, r2}; | |
if(elf == NULL) | |
return ELF_LOADER_RETURN_ELF_NULL; | |
if(writable == NULL) | |
return ELF_LOADER_RETURN_NO_WRITABLE_MEMORY; | |
if(executable == NULL) | |
return ELF_LOADER_RETURN_NO_EXECUTABLE_MEMORY; | |
dynamicSymbols = elfSymbols(elf, ".dynsym", &dynamicSymbolSize, &dynamicSymbolsLength); | |
//symbols = elfSymbols(elf, ".symtab", &symbolSize, &symbolsLength); | |
for(j = 0; j < sizeof(rel) / sizeof(rel[0]); ++j) | |
{ | |
relocationsLength = 0; | |
relocations = elfAddendRelocations(elf, rel[j], &relocationSize, &relocationsLength); | |
for(i = 0; i < relocationsLength; ++i) | |
{ | |
ElfSymbol *symbol; | |
ElfAddendRelocation *relocation = (ElfAddendRelocation *)(((uint8_t *)relocations) + relocationSize * i); | |
uint16_t relocationType = (uint16_t)elfRelocationType(relocation->r_info); | |
uint16_t relocationSymbol = (uint16_t)elfRelocationSymbol(relocation->r_info); | |
uint8_t **offset = (uint8_t **)((uint8_t *)writable + relocation->r_offset); | |
int64_t value = 0; | |
switch(relocationType) | |
{ | |
case R_X86_64_RELATIVE: | |
value = relocation->r_addend; | |
break; | |
case R_X86_64_64: | |
symbol = (ElfSymbol *)(((uint8_t *)dynamicSymbols) + dynamicSymbolSize * relocationSymbol); | |
value = symbol->st_value + relocation->r_addend; | |
break; | |
case R_X86_64_JMP_SLOT: | |
case R_X86_64_GLOB_DAT: | |
symbol = (ElfSymbol *)(((uint8_t *)dynamicSymbols) + dynamicSymbolSize * relocationSymbol); | |
value = symbol->st_value; | |
break; | |
default: | |
return ELF_LOADER_RETURN_UNKNOWN_RELOCATION; | |
} | |
if(elfLoaderRelativeAddressIsExecutable(elf, value)) | |
*offset = (uint8_t *)executable + value; | |
else | |
*offset = (uint8_t *)writable + value; | |
} | |
} | |
return ELF_LOADER_RETURN_OK; | |
} | |
int elfLoaderLoad(Elf *elf, void *writable, void *executable) | |
{ | |
int r = ELF_LOADER_RETURN_OK; | |
if(elf == NULL) | |
return ELF_LOADER_RETURN_ELF_NULL; | |
if(writable == NULL) | |
return ELF_LOADER_RETURN_NO_WRITABLE_MEMORY; | |
if(executable == NULL) | |
return ELF_LOADER_RETURN_NO_EXECUTABLE_MEMORY; | |
if(!elfLoaderIsLoadable(elf)) | |
return ELF_LOADER_RETURN_IS_NOT_LOADABLE; | |
if((r = elfLoaderInstantiate(elf, writable)) != ELF_LOADER_RETURN_OK) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] elfLoaderLoad after elfLoaderInstantiate error return=%d\n",r); | |
return r; | |
} | |
debugNetPrintf(DEBUG,"[ORBISLINK] elfLoaderLoad after elfLoaderInstantiate return=%d\n",r); | |
r = elfLoaderRelocate(elf, writable, executable); | |
debugNetPrintf(DEBUG,"[ORBISLINK] elfLoaderLoad after elfLoaderRelocate return=%d\n",r); | |
return r; | |
} | |
extern ps4LinkConfiguration *configuration; | |
typedef int (*ElfMain)(int argc, char **argv); | |
typedef void (*ElfProcessMain)(void *arg); | |
typedef void (*ElfProcessExit)(int ret); | |
typedef void (*ElfProcessFree)(void *m, void *t); | |
typedef struct ElfRunUserArgument | |
{ | |
ElfMain main; | |
Ps4MemoryProtected *memory; | |
} | |
ElfRunUserArgument; | |
void *orbisUserMain(void *arg) | |
{ | |
ElfRunUserArgument *argument = (ElfRunUserArgument *)arg; | |
globalConf.confLink=configuration; | |
//ps4LinkConfiguration *shared_conf=configuration; | |
char pointer_conf[256]; | |
sprintf(pointer_conf,"%p",&globalConf); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserMain Configuration pointer %p, pointer_conf string %s\n",&globalConf,pointer_conf); | |
char *elfName = "elf"; | |
char *elfArgv[3] = { elfName, pointer_conf, NULL }; | |
int elfArgc = 2; | |
int r; | |
if(argument == NULL) | |
return NULL; | |
r = argument->main(elfArgc, elfArgv); | |
ps4MemoryProtectedDestroy(argument->memory); | |
//ps4MemoryDestroy(argument->memory); | |
free(argument); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserMain return (user): %i\n", r); | |
return NULL; | |
} | |
int orbisUserRun(Elf *elf) | |
{ | |
//pthread_t thread; | |
ScePthread thread; | |
int ret; | |
ElfRunUserArgument *argument; | |
void *writable, *executable; | |
int r; | |
if(elf == NULL) | |
return -1; | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserRun malloc for argument\n"); | |
argument = (ElfRunUserArgument *)malloc(sizeof(ElfRunUserArgument)); | |
if(argument == NULL) | |
{ | |
elfDestroyAndFree(elf); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserRun argument is NULL\n"); | |
return -1; | |
} | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserRun after malloc for argument\n"); | |
if(ps4MemoryProtectedCreate(&argument->memory, elfMemorySize(elf)) != 0) | |
//if(ps4MemoryCreate(&argument->memory, elfMemorySize(elf)) != PS4_OK) | |
{ | |
free(argument); | |
elfDestroyAndFree(elf); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserRun after elfDestroyAndFree\n"); | |
return -1; | |
} | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserRun after ps4MemoryProtectedCreate\n"); | |
argument->main = NULL; | |
ps4MemoryProtectedGetWritableAddress(argument->memory, &writable); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserRun after ps4MemoryProtectedGetWritableAddress writable=%p\n",writable); | |
ps4MemoryProtectedGetExecutableAddress(argument->memory, &executable); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserRun after ps4MemoryProtectedGetExecutableAddress executable=%p\n",executable); | |
r = elfLoaderLoad(elf, writable, executable); | |
//r = elfLoaderLoad(elf, ps4MemoryGetAddress(argument->memory), ps4MemoryGetAddress(argument->memory)); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserRun after elfLoaderLoad return r=%d readable=%p executable=%p\n",r,writable,executable); | |
if(r == ELF_LOADER_RETURN_OK) | |
{ | |
argument->main = (ElfMain)((uint8_t *)executable + elfEntry(elf)); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserRun after set argument->main %p \n",argument->main); | |
} | |
//elfDestroyAndFree(elf); // we don't need the "file" anymore but if i leave this line i got a memory crash | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisUserRun after elfDestroyAndFree \n"); | |
if(argument->main != NULL) | |
{ //pthread_create(&thread, NULL, elfLoaderUserMain, argument); | |
ret=scePthreadCreate(&thread, NULL, orbisUserMain, argument, "elf_user_thid"); | |
if(ret==0) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] New user elf thread UID: 0x%08X\n", thread); | |
} | |
else | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] New user elf thread could not create error: 0x%08X\n", ret); | |
scePthreadCancel(thread); | |
//ps4LinkFinish(); | |
return PS4_NOT_OK; | |
} | |
} | |
else | |
{ | |
ps4MemoryProtectedDestroy(argument->memory); | |
free(argument); | |
debugNetPrintf(DEBUG,"[ORBISLINK]orbisUserRun argument->main is released\n"); | |
return -1; | |
} | |
return PS4_OK; | |
} | |
Elf * orbisReadElfFromHost(char *path) | |
{ | |
int fd; //descriptor to manage file from host0 | |
int filesize;//variable to control file size | |
uint8_t *buf=NULL;//buffer for read from host0 file | |
Elf *elf;//elf to create from buf | |
//we open file in read only from host0 ps4sh include the full path with host0:/....... | |
fd=ps4LinkOpen(path,O_RDONLY,0); | |
//If we can't open file from host0 print the error and return | |
if(fd<0) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] ps4LinkOpen returned error opening file %d\n",fd); | |
return NULL; | |
} | |
//Seek to final to get file size | |
filesize=ps4LinkLseek(fd,0,SEEK_END); | |
//If we get an error print it and return | |
if(filesize<0) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] ps4LinkSeek returned error %d\n",fd); | |
ps4LinkClose(fd); | |
return NULL; | |
} | |
//Seek back to start | |
ps4LinkLseek(fd,0,SEEK_SET); | |
//Reserve memory for read buffer | |
//buf=malloc(filesize); | |
//char buf[filesize]; | |
debugNetPrintf(DEBUG,"[ORBISLINK] before orbisSysMmap\n"); | |
buf=mmap(NULL,filesize,0x01|0x02,0x1000|0x0002,-1,0); | |
if(buf==MAP_FAILED) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] mmap returned error tryng one more time\n"); | |
buf=mmap(NULL,filesize,0x01|0x02,0x1000|0x0002,-1,0); | |
if(buf==MAP_FAILED) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] mmap returned error again\n"); | |
ps4LinkClose(fd); | |
return NULL; | |
} | |
} | |
//Read filsesize bytes to buf | |
int numread=ps4LinkRead(fd,buf,filesize); | |
//if we don't get filesize bytes we are in trouble | |
if(numread!=filesize) | |
{ | |
sleep(1); | |
debugNetPrintf(DEBUG,"[ORBISLINK] ps4LinkRead returned error %d\n",numread); | |
sleep(1); | |
ps4LinkClose(fd); | |
return NULL; | |
} | |
//Close file | |
ps4LinkClose(fd); | |
//create elf from elfloader code from hitodama :P | |
elf = elfCreate((void*)buf, filesize); | |
//check is it is loadable | |
if(!elfLoaderIsLoadable(elf)) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] elf %s is not loadable\n",path); | |
//free(buf); | |
elfDestroy(elf); | |
elf = NULL; | |
} | |
return elf; | |
} | |
void orbisExecUserElf() | |
{ | |
Elf *elf=NULL; | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisExecUserElf called\n"); | |
elf=orbisReadElfFromHost("host0:homebrew.elf"); | |
if(elf==NULL) | |
{ | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisExecUserElf we can't create elf\n"); | |
return; | |
} | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisExecUserElf ready to run elf\n"); | |
orbisUserRun(elf); | |
return; | |
} | |
void finishOrbisLinkApp() | |
{ | |
orbisAudioFinish(); | |
orbisPadFinish(); | |
orbis2dFinish(); | |
ps4LinkFinish(); | |
} | |
void initOrbisLinkApp() | |
{ | |
int ret; | |
int jailbreak_out=-1; | |
//jailbreak_out=orbisSysJailBreak(); | |
globalConf.orbisLinkFlag=0; | |
ret=ps4LinkInit("192.168.1.3",0x4711,0x4712,0x4712,3); | |
if(!ret) | |
{ | |
ps4LinkFinish(); | |
return; | |
} | |
while(!ps4LinkRequestsIsConnected()) | |
{ | |
} | |
//debugNetPrintf(DEBUG,"[ORBISLINK] orbisSysJailBreak returned %d\n",jailbreak_out); | |
debugNetPrintf(DEBUG,"[ORBISLINK] Initialized and connected from pc/mac ready to receive commands\n"); | |
ret=orbisPadInit(); | |
if(ret==1) | |
{ | |
globalConf.confPad=orbisPadGetConf(); | |
ret=orbis2dInit(); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbis2dInit return %x \n",ret); | |
if(ret==1) | |
{ | |
globalConf.conf=orbis2dGetConf(); | |
ret=orbisAudioInit(); | |
if(ret==1) | |
{ | |
ret=orbisAudioInitChannel(ORBISAUDIO_CHANNEL_MAIN,1024,48000,ORBISAUDIO_FORMAT_S16_STEREO); | |
sleep(1); | |
debugNetPrintf(DEBUG,"[ORBISLINK] orbisAudioInitChannel return %x \n",ret); | |
sleep(1); | |
globalConf.confAudio=orbisAudioGetConf(); | |
} | |
} | |
} | |
//hide orbislink splash | |
//sceSystemServiceHideSplashScreen(); | |
} | |
int main() | |
{ | |
initOrbisLinkApp(); | |
debugNetPrintf(DEBUG,"[ORBISLINK]Loading homebrew.elf from host\n"); | |
orbisExecUserElf(); | |
while(!globalConf.orbisLinkFlag) | |
{ | |
} | |
finishOrbisLinkApp(); | |
exit(0); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment