diff --git a/ee/Makefile b/ee/Makefile index c9e6d93e973..e26e9a957ec 100644 --- a/ee/Makefile +++ b/ee/Makefile @@ -11,7 +11,7 @@ SUBDIRS = startup erl kernel libcglue libpthreadglue libprofglue rpc debug \ packet packet2 draw libgs \ libvux font input inputx network iopreboot \ mpeg \ - elf-loader elf-loader-nocolour \ + elf-loader elf-loader-nocolour elf-loader2 \ include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/Rules.make diff --git a/ee/elf-loader2/Makefile b/ee/elf-loader2/Makefile new file mode 100644 index 00000000000..b6d0e8cdebc --- /dev/null +++ b/ee/elf-loader2/Makefile @@ -0,0 +1,39 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. + +EE_OBJS = \ + elf.o \ + elf_loader_compat.o \ + elf_loader_reader.o \ + elf_loader_stdio.o \ + ldrsrc.o + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/ee/Rules.lib.make +include $(PS2SDKSRC)/ee/Rules.make +include $(PS2SDKSRC)/ee/Rules.release + +$(PS2SDKSRC)/tools/bin2c/bin/bin2c: $(PS2SDKSRC)/tools/bin2c + $(MAKEREC) $< + +src/ldrsrc/bin/ldrsrc.bin: + $(MAKEREC) src/ldrsrc + +$(EE_OBJS_DIR)ldrsrc.c: src/ldrsrc/bin/ldrsrc.bin $(PS2SDKSRC)/tools/bin2c/bin/bin2c + $(PS2SDKSRC)/tools/bin2c/bin/bin2c $< $@ ldrsrc + +$(EE_OBJS_DIR)ldrsrc.o: $(EE_OBJS_DIR)ldrsrc.c + $(DIR_GUARD) + $(EE_C_COMPILE) $< -c -o $@ + +clean:: + $(MAKEREC) src/ldrsrc clean + +.NOTPARALLEL:: \ + $(PS2SDKSRC)/tools/bin2c/bin/bin2c \ + src/ldrsrc/bin/ldrsrc.bin diff --git a/ee/elf-loader2/include/elf-loader.h b/ee/elf-loader2/include/elf-loader.h new file mode 100644 index 00000000000..f3fea4ea340 --- /dev/null +++ b/ee/elf-loader2/include/elf-loader.h @@ -0,0 +1,57 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# (c) 2020 Francisco Javier Trujillo Mata +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +/** + * @file + * ELF Loader functions. + */ + +#ifndef __ELFLOADER_H__ +#define __ELFLOADER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +// Before call this method be sure that you have previously called sbv_patch_disable_prefix_check(); +extern int LoadELFFromFile(const char *filename, int argc, char *argv[]); + +/** Modify argv[0] when partition info should be kept + * + * @param filename path to the file itself + * @param partition block device + partition name + * @param argc Number of arguments. + * @param argv Pointer to array of arguments. + * @returns positive on success, zero value on failure + * + * You should prepare filename and partition before parsing in function + * + * filename should be changed to :/path_to_file_without_mountpoint + * for example `pfs3:/TEST.ELF` (where `pfs3` is mountpoint name) will become + * `pfs:/TEST.ELF` (where `pfs` - filesystem type) + * + * partition should be in form : + * for example `hdd0:__common:` + * block_device - can be `hdd0:`, `hdd1:` , `dvr_hdd0:` + * - name of APA partition on particular block device + * dont forget about leading ":" + * + * It is not necessary that filename should be on that partition + * filename - mass:/TEST.ELF + * partition - pfs:/__common + * will be valid usage + */ +extern int LoadELFFromFileWithPartition(const char *filename, const char *partition, int argc, char *argv[]); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELFLOADER_H__ */ diff --git a/ee/elf-loader2/src/elf.c b/ee/elf-loader2/src/elf.c new file mode 100644 index 00000000000..12d361160d6 --- /dev/null +++ b/ee/elf-loader2/src/elf.c @@ -0,0 +1,356 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "elf_loader_common.h" + +#include +#include + +// Loader ELF variables +extern u8 ldrsrc[]; +extern int size_ldrsrc; + +int elf_loader_is_elf_ehdr_valid(const elf_loader_elf32_ehdr_t *ehdr) +{ + int ret; + + ret = 0; + + if ( memcmp( + ehdr->e_ident, + "\x7F" + "ELF", + 4) ) + { + ret = -9; + } + else if ( ehdr->e_entry < 0x80000 || ehdr->e_entry > (32 * 1024 * 1024) ) + { + ret = -10; + } + else if ( ehdr->e_ident[4] != 1 ) + { + ret = -1; + } + else if ( ehdr->e_ident[5] != 1 ) + { + ret = -2; + } + else if ( ehdr->e_type != 2 ) + { + ret = -3; + } + else if ( ehdr->e_machine != 8 ) + { + ret = -4; + } + else if ( ehdr->e_ehsize != sizeof(elf_loader_elf32_ehdr_t) ) + { + ret = -5; + } + else if ( ehdr->e_phentsize != sizeof(elf_loader_elf32_phdr_t) ) + { + ret = -6; + } + else if ( ehdr->e_phnum > ELF_LOADER_MAX_PROGRAM_HEADERS ) + { + ret = -7; + } + else if ( ehdr->e_shnum && ehdr->e_shentsize != 40 ) + { + ret = -8; + } + return ret; +} + +int elf_loader_is_elf_valid_for_loading(const void *buf, size_t buf_size) +{ + int i; + int ret; + int ph_count; + int entrypoint_in_ph; + u32 highest_vaddr; + u32 highest_offset; + const elf_loader_elf32_ehdr_t *ehdr; + const elf_loader_elf32_phdr_t *phdr; + + if ( buf_size < sizeof(elf_loader_elf32_ehdr_t) ) + return -30; + ehdr = (const elf_loader_elf32_ehdr_t *)buf; + ret = elf_loader_is_elf_ehdr_valid(ehdr); + if ( ret ) + return ret; + if ( buf_size < (ehdr->e_phoff + sizeof(elf_loader_elf32_ehdr_t)) ) + return -31; + phdr = (const elf_loader_elf32_phdr_t *)(((const u8 *)buf) + ehdr->e_phoff); + ph_count = 0; + entrypoint_in_ph = 0; + highest_vaddr = 0x80000; + highest_offset = 0; + for ( i = 0; i < ehdr->e_phnum; i += 1 ) + { + if ( phdr[i].p_type == 1 && phdr[i].p_filesz != 0 ) + { + // Program headers need to be pre-sorted + if ( phdr[i].p_vaddr < highest_vaddr || phdr[i].p_offset < highest_offset ) + { + return -20; + } + highest_vaddr = phdr[i].p_vaddr; + highest_offset = phdr[i].p_offset; + if ( ehdr->e_entry >= phdr[i].p_vaddr && (phdr[i].p_vaddr + phdr[i].p_filesz) > ehdr->e_entry ) + { + entrypoint_in_ph = 1; + } + ph_count += 1; + } + } + if ( !ph_count || ph_count > ELF_LOADER_MAX_PROGRAM_HEADERS ) + { + return -21; + } + if ( !entrypoint_in_ph ) + { + return -22; + } + if ( buf_size < highest_offset ) + return -32; + return 0; +} + +int elf_loader_exec_elf_prepare_loadinfo(elf_loader_execinfo_t *execinfo, const void *buf, size_t buf_size) +{ + int ret; + const elf_loader_elf32_ehdr_t *ehdr; + const elf_loader_elf32_phdr_t *phdr; + int i; + u32 min_load_addr; + u32 max_load_addr; + u32 info_count; + u32 memsize; + + ret = elf_loader_is_elf_valid_for_loading(buf, buf_size); + if ( ret ) + return ret; + ehdr = (const elf_loader_elf32_ehdr_t *)buf; + phdr = (const elf_loader_elf32_phdr_t *)(((const u8 *)buf) + ehdr->e_phoff); + memsize = GetMemorySize(); + + min_load_addr = 0xFFFFFFFF; + max_load_addr = 0x00100000; + + info_count = 0; + for ( i = 0; i < ehdr->e_phnum; i += 1 ) + { + if ( phdr[i].p_type == 1 && phdr[i].p_filesz != 0 ) + { + // Item: move memory down + execinfo->loaderinfo.items[info_count].dest_addr = (void *)(phdr[i].p_vaddr); + execinfo->loaderinfo.items[info_count].src_addr = (void *)(((u8 *)buf) + phdr[i].p_offset); + execinfo->loaderinfo.items[info_count].size = phdr[i].p_filesz; + { + u32 load_address; + u32 end_load_address; + load_address = phdr[i].p_vaddr; + end_load_address = load_address + phdr[i].p_filesz; + if ( load_address < min_load_addr ) + { + min_load_addr = load_address; + } + if ( end_load_address > max_load_addr ) + { + max_load_addr = end_load_address; + } + } + if ( + (u8 *)(execinfo->loaderinfo.items[info_count].dest_addr) + >= ((u8 *)execinfo->loaderinfo.items[info_count].src_addr) ) + break; + info_count += 1; + } + } + for ( i = ehdr->e_phnum - 1; i >= 0; i -= 1 ) + { + if ( phdr[i].p_type == 1 && phdr[i].p_filesz != 0 ) + { + // Item: move memory up + execinfo->loaderinfo.items[info_count].dest_addr = (void *)(phdr[i].p_vaddr); + execinfo->loaderinfo.items[info_count].src_addr = (void *)(((u8 *)buf) + phdr[i].p_offset); + execinfo->loaderinfo.items[info_count].size = phdr[i].p_filesz; + { + u32 load_address; + u32 end_load_address; + load_address = phdr[i].p_vaddr; + end_load_address = load_address + phdr[i].p_filesz; + if ( load_address < min_load_addr ) + { + min_load_addr = load_address; + } + if ( end_load_address > max_load_addr ) + { + max_load_addr = end_load_address; + } + } + if ( + (u8 *)(execinfo->loaderinfo.items[info_count].dest_addr) + <= ((u8 *)execinfo->loaderinfo.items[info_count].src_addr) ) + break; + info_count += 1; + } + } + if ( min_load_addr != 0xFFFFFFFF ) + { + u32 wanted_size; + wanted_size = min_load_addr - 0x00100000; + if ( wanted_size != 0 ) + { + // Item: clear memory + execinfo->loaderinfo.items[info_count].dest_addr = (void *)0x00100000; + execinfo->loaderinfo.items[info_count].src_addr = (void *)NULL; + execinfo->loaderinfo.items[info_count].size = wanted_size; + info_count += 1; + } + } + if ( max_load_addr != 0x00100000 ) + { + u32 wanted_size; + wanted_size = memsize - (uiptr)max_load_addr; + // Item: clear memory + if ( wanted_size != 0 ) + { + execinfo->loaderinfo.items[info_count].dest_addr = (void *)max_load_addr; + execinfo->loaderinfo.items[info_count].src_addr = (void *)NULL; + execinfo->loaderinfo.items[info_count].size = wanted_size; + info_count += 1; + } + } + // Item: execute entry point + execinfo->loaderinfo.items[info_count].dest_addr = (void *)(ehdr->e_entry); + execinfo->loaderinfo.items[info_count].src_addr = (void *)NULL; // GP returned is always NULL + execinfo->loaderinfo.items[info_count].size = 0; + + return 0; +} + +int elf_loader_exec_elf_prepare_arginfo( + elf_loader_execinfo_t *execinfo, const char *filename, const char *partition, int argc, char *argv[]) +{ + char *ptr; + int len, i; + + ptr = execinfo->arginfo.payload; + argc = (argc > 15) ? 15 : argc; + execinfo->arginfo.argc = argc + 1; + // Make pointer relative to payload, so that it can be relocated later + execinfo->arginfo.argv[0] = (char *)((uiptr)ptr - (uiptr)(execinfo->arginfo.payload)); + if ( partition != NULL ) + { + len = strlen(partition); // Not including NULL terminator + if ( ((ptr - execinfo->arginfo.payload) + len) > sizeof(execinfo->arginfo.payload) ) + return -40; + memcpy(ptr, partition, len); + ptr += len; + } + len = strlen(filename) + 1; + if ( ((ptr - execinfo->arginfo.payload) + len) > sizeof(execinfo->arginfo.payload) ) + return -40; + memcpy(ptr, filename, len); + ptr += len; + for ( i = 0; i < argc; i += 1 ) + { + execinfo->arginfo.argv[i + 1] = (char *)((uiptr)ptr - (uiptr)(execinfo->arginfo.payload)); + len = strlen(argv[i]) + 1; + if ( ((ptr - execinfo->arginfo.payload) + len) > sizeof(execinfo->arginfo.payload) ) + return -40; + memcpy(ptr, argv[i], len); + ptr += len; + } + return 0; +} + +static void elf_loader_ldr_entrypoint_stack(); + +static char args_storage[1024]; +static elf_loader_loaderinfo_t sg_loaderinfo; + +// Modified crt0 +// bss zero is skipped, and argument handling removed +static void elf_loader_ldr_entrypoint(void) +{ + // clang-format off + __asm__ __volatile__( + // SetupThread + // Arg0: gp value (NULL since not using small data) + "move $4, $0" "\n" + // Arg1: Stack address (at EE scratchpad) + "move $5, $0" "\n" + "lui $5, 0x7000" "\n" + // Arg2: Stack size (16 KB) + "move $6, $0" "\n" + "ori $6, $6, 0x4000" "\n" + // Arg3: args buffer (needs to not be NULL since kernel unconditionally writes argc to it) + "la $7, %0 \n" + // Arg4: root function + "la $8, ExitThread \n" + "move $gp, $4 \n" + "addiu $3, $0, 60 \n" + "syscall \n" + "move $sp, $2 \n" + // Jump to entrypoint that can use stack + "j %1 \n" + : // No output registers + : "R"(args_storage), "Csy"(elf_loader_ldr_entrypoint_stack)); + // clang-format on +} + +typedef void *(*ldr_getinternalinfo_callback)(void); +#define LDR_ENTRYPOINT_ADDR 0x00084000 + +static void elf_loader_ldr_entrypoint_stack() +{ + ldr_getinternalinfo_callback cb; + + // Use VU1 data memory as heap + SetupHeap((void *)0x1100C000, 0x4000); + + FlushCache(0); + + memcpy((void *)LDR_ENTRYPOINT_ADDR, ldrsrc, size_ldrsrc); + // Use VU0 data memory as storage for loader information + memcpy((void *)0x11004000, &sg_loaderinfo, sizeof(elf_loader_loaderinfo_t)); + + FlushCache(0); + FlushCache(2); + + cb = (void *)LDR_ENTRYPOINT_ADDR; + cb(); + // Should be unreachable here + __builtin_trap(); +} + +int elf_loader_exec_elf(elf_loader_execinfo_t *execinfo) +{ + elf_loader_arginfo_t *low_arginfo; + int i; + + if ( execinfo->arginfo.argc == 0 ) + return -1; + memcpy(&sg_loaderinfo, &(execinfo->loaderinfo), sizeof(elf_loader_loaderinfo_t)); + // Copy argument info to low EE memory (because EE wipes VU0, VU1, or SPR memory before reading it) + low_arginfo = (void *)0x00088000; + memcpy((void *)low_arginfo, &(execinfo->arginfo), sizeof(elf_loader_execinfo_t)); + // Relocate the arguments to the new address + for ( i = 0; i < low_arginfo->argc; i += 1 ) + { + low_arginfo->argv[i] = (char *)((uiptr)(low_arginfo->argv[i]) + (uiptr)(low_arginfo->payload)); + } + ExecPS2(&elf_loader_ldr_entrypoint, NULL, 0, NULL); + return -1; +} diff --git a/ee/elf-loader2/src/elf_loader_compat.c b/ee/elf-loader2/src/elf_loader_compat.c new file mode 100644 index 00000000000..d55c2e82a82 --- /dev/null +++ b/ee/elf-loader2/src/elf_loader_compat.c @@ -0,0 +1,62 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "elf_loader_common.h" + +#include +#include +#include +#include + +int LoadELFFromFileWithPartition(const char *filename, const char *partition, int argc, char *argv[]) +{ + int ret; + elf_loader_reader_info_stdio_resultbuf_t resultbuf; + elf_loader_execinfo_t execinfo; + + ret = elf_loader_reader_read_elf_file_stdio(&resultbuf, filename, "rb"); + if ( ret < 0 ) + { + return ret; + } + ret = elf_loader_exec_elf_prepare_loadinfo(&execinfo, resultbuf.m_buf, resultbuf.m_bufsize); + if ( ret < 0 ) + { + free(resultbuf.m_buf); + return ret; + } + ret = elf_loader_exec_elf_prepare_arginfo(&execinfo, filename, partition, argc, argv); + if ( ret < 0 ) + { + free(resultbuf.m_buf); + return ret; + } + + // No turning back here. + while ( !SifIopReset(NULL, 0) ) + ; + while ( !SifIopSync() ) + ; + + sceSifInitRpc(0); + SifLoadFileInit(); + SifLoadModule("rom0:SIO2MAN", 0, NULL); + SifLoadModule("rom0:MCMAN", 0, NULL); + SifLoadModule("rom0:MCSERV", 0, NULL); + SifLoadFileExit(); + sceSifExitRpc(); + + return elf_loader_exec_elf(&execinfo); +} + +int LoadELFFromFile(const char *filename, int argc, char *argv[]) +{ + return LoadELFFromFileWithPartition(filename, NULL, argc, argv); +} diff --git a/ee/elf-loader2/src/elf_loader_reader.c b/ee/elf-loader2/src/elf_loader_reader.c new file mode 100644 index 00000000000..b56a100c95f --- /dev/null +++ b/ee/elf-loader2/src/elf_loader_reader.c @@ -0,0 +1,163 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "elf_loader_common.h" + +#include + +void elf_loader_reader_read_elf_file(elf_loader_reader_info_t *info) +{ + void *ptr; + int ret; + ptrdiff_t cur_alloc_block_size; + + ret = -10; + cur_alloc_block_size = 0; + ptr = info->m_alloc_callback( + info->m_userdata, + NULL, + 0, + sizeof(elf_loader_elf32_ehdr_t) + (sizeof(elf_loader_elf32_phdr_t) * ELF_LOADER_MAX_PROGRAM_HEADERS)); + if ( ptr ) + { + elf_loader_reader_segment_info_t elf_segment_info[1]; + + ret = -11; + cur_alloc_block_size = + sizeof(elf_loader_elf32_phdr_t) + (sizeof(elf_loader_elf32_phdr_t) * ELF_LOADER_MAX_PROGRAM_HEADERS); + elf_segment_info[0].m_segment_addr = ptr; + elf_segment_info[0].m_segment_offset = 0; + elf_segment_info[0].m_segment_size = cur_alloc_block_size; + + if ( !info->m_read_callback( + info->m_userdata, + ELF_LOADER_READER_STAGE_ELF_HEADER, + &elf_segment_info[0], + sizeof(elf_segment_info) / sizeof(elf_segment_info[0])) ) + ptr = info->m_alloc_callback(info->m_userdata, ptr, cur_alloc_block_size, 0); + } + if ( ptr ) + { + int ret; + + ret = elf_loader_is_elf_ehdr_valid(ptr); + if ( ret ) + ptr = info->m_alloc_callback(info->m_userdata, ptr, cur_alloc_block_size, 0); + } + if ( ptr ) + { + elf_loader_elf32_ehdr_t *elf_header; + elf_loader_reader_segment_info_t elf_segment_info[1]; + u32 phoff; + + ret = -12; + elf_header = (void *)ptr; + elf_header->e_shoff = 0; + elf_header->e_shentsize = 0; + elf_header->e_shnum = 0; + elf_header->e_shstrndx = 0; + phoff = elf_header->e_phoff; + elf_header->e_phoff = sizeof(elf_loader_elf32_ehdr_t); + + elf_segment_info[0].m_segment_addr = ((u8 *)ptr) + elf_header->e_phoff; + elf_segment_info[0].m_segment_offset = phoff; + elf_segment_info[0].m_segment_size = sizeof(elf_loader_elf32_phdr_t) * elf_header->e_phnum; + + if ( !info->m_read_callback( + info->m_userdata, + ELF_LOADER_READER_STAGE_PROGRAM_HEADERS, + &elf_segment_info[0], + sizeof(elf_segment_info) / sizeof(elf_segment_info[0])) ) + ptr = info->m_alloc_callback(info->m_userdata, ptr, cur_alloc_block_size, 0); + } + if ( ptr ) + { + elf_loader_elf32_ehdr_t *elf_header; + elf_loader_elf32_phdr_t *elf_pheader; + int i; + u32 offs_sum; + + ret = -13; + elf_header = (void *)ptr; + elf_pheader = (void *)(((u8 *)ptr) + elf_header->e_phoff); + offs_sum = 0; + // Remove any unused program headers + for ( i = 0; i < elf_header->e_phnum; i += 1 ) + { + while ( i < elf_header->e_phnum && (elf_pheader[i].p_type != 1 || elf_pheader[i].p_filesz == 0) ) + { + elf_header->e_phnum -= 1; + memmove(&elf_pheader[i], &elf_pheader[i + 1], sizeof(elf_loader_elf32_phdr_t) * (elf_header->e_phnum - i)); + } + } + // Sort program headers by address + for ( i = 1; i < elf_header->e_phnum; i += 1 ) + { + int j; + elf_loader_elf32_phdr_t phdr_tmp; + + memcpy(&phdr_tmp, &elf_pheader[i], sizeof(elf_loader_elf32_phdr_t)); + for ( j = i - 1; j >= 0 && phdr_tmp.p_vaddr < elf_pheader[j].p_vaddr; j -= 1 ) + { + memcpy(&elf_pheader[j + 1], &elf_pheader[j], sizeof(elf_loader_elf32_phdr_t)); + } + memcpy(&elf_pheader[j + 1], &phdr_tmp, sizeof(elf_loader_elf32_phdr_t)); + } + offs_sum = sizeof(elf_loader_elf32_ehdr_t) + (sizeof(elf_loader_elf32_phdr_t) * elf_header->e_phnum); + for ( i = 0; i < elf_header->e_phnum; i += 1 ) + { + offs_sum += elf_pheader[i].p_filesz; + } + ptr = info->m_alloc_callback(info->m_userdata, ptr, cur_alloc_block_size, offs_sum); + cur_alloc_block_size = offs_sum; + } + if ( ptr ) + { + elf_loader_elf32_ehdr_t *elf_header; + elf_loader_elf32_phdr_t *elf_pheader; + elf_loader_reader_segment_info_t elf_segment_info[ELF_LOADER_MAX_PROGRAM_HEADERS]; + int i; + u32 offs_sum; + + ret = -14; + elf_header = (void *)ptr; + elf_pheader = (void *)(((u8 *)ptr) + elf_header->e_phoff); + offs_sum = sizeof(elf_loader_elf32_ehdr_t) + (sizeof(elf_loader_elf32_phdr_t) * elf_header->e_phnum); + for ( i = 0; i < elf_header->e_phnum; i += 1 ) + { + elf_segment_info[i].m_segment_addr = ((u8 *)ptr) + offs_sum; + elf_segment_info[i].m_segment_offset = elf_pheader[i].p_offset; + elf_segment_info[i].m_segment_size = elf_pheader[i].p_filesz; + elf_pheader[i].p_offset = offs_sum; + offs_sum += elf_segment_info[i].m_segment_size; + } + // Sort segment info by offset in file + for ( i = 1; i < elf_header->e_phnum; i += 1 ) + { + int j; + elf_loader_reader_segment_info_t segment_info_tmp; + + memcpy(&segment_info_tmp, &elf_segment_info[i], sizeof(elf_loader_reader_segment_info_t)); + for ( j = i - 1; j >= 0 && segment_info_tmp.m_segment_offset < elf_segment_info[j].m_segment_offset; j -= 1 ) + { + memcpy(&elf_segment_info[j + 1], &elf_segment_info[j], sizeof(elf_loader_reader_segment_info_t)); + } + memcpy(&elf_segment_info[j + 1], &segment_info_tmp, sizeof(elf_loader_reader_segment_info_t)); + } + if ( !info->m_read_callback( + info->m_userdata, ELF_LOADER_READER_STAGE_SEGMENTS, &elf_segment_info[0], elf_header->e_phnum) ) + ptr = info->m_alloc_callback(info->m_userdata, ptr, cur_alloc_block_size, 0); + } + if ( ptr ) + { + ret = 0; + } + info->m_result_callback(info->m_userdata, ptr, cur_alloc_block_size, ret); +} diff --git a/ee/elf-loader2/src/elf_loader_stdio.c b/ee/elf-loader2/src/elf_loader_stdio.c new file mode 100644 index 00000000000..a6d4558c670 --- /dev/null +++ b/ee/elf-loader2/src/elf_loader_stdio.c @@ -0,0 +1,103 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "elf_loader_common.h" + +#include +#include +#include + +typedef struct elf_loader_reader_info_stdio_ +{ + FILE *m_fp; + elf_loader_reader_info_t m_reader_info; + elf_loader_reader_info_stdio_resultbuf_t m_resultbuf; +} elf_loader_reader_info_stdio_t; + +static void *elf_loader_reader_read_elf_file_stdlib_allocation_callback( + void *userdata, void *pointer, ptrdiff_t old_size, ptrdiff_t new_size) +{ + void *new_ptr; + (void)userdata; + (void)old_size; + + if ( !new_size ) + { + free(pointer); + return NULL; + } + new_ptr = realloc(pointer, new_size); + if ( !new_ptr ) + { + free(pointer); + } + return new_ptr; +} + +static int elf_loader_reader_read_elf_file_stdio_read_callback( + void *userdata, elf_loader_reader_stage_t stage, const elf_loader_reader_segment_info_t *segm_info, size_t segm_count) +{ + elf_loader_reader_info_stdio_t *procinfo; + size_t i; + + procinfo = (elf_loader_reader_info_stdio_t *)userdata; + if ( !procinfo->m_fp ) + return 0; + for ( i = 0; i < segm_count; i += 1 ) + { + if ( fseek(procinfo->m_fp, segm_info[i].m_segment_offset, SEEK_SET) ) + { + return 0; + } + if ( ftell(procinfo->m_fp) != segm_info[i].m_segment_offset ) + { + return 0; + } + if ( fread(segm_info[i].m_segment_addr, segm_info[i].m_segment_size, 1, procinfo->m_fp) != 1 ) + { + return 0; + } + } + return 1; +} + +static void +elf_loader_reader_read_elf_file_stdio_result_callback(void *userdata, void *pointer, ptrdiff_t pointer_size, int errval) +{ + elf_loader_reader_info_stdio_t *procinfo; + + procinfo = (elf_loader_reader_info_stdio_t *)userdata; + procinfo->m_resultbuf.m_buf = pointer; + procinfo->m_resultbuf.m_bufsize = pointer_size; + procinfo->m_resultbuf.m_result = errval; +} + +int elf_loader_reader_read_elf_file_stdio( + elf_loader_reader_info_stdio_resultbuf_t *resultbuf, const char *filename, const char *flags) +{ + elf_loader_reader_info_stdio_t procinfo; + + procinfo.m_reader_info.m_userdata = &procinfo; + procinfo.m_reader_info.m_alloc_callback = elf_loader_reader_read_elf_file_stdlib_allocation_callback; + procinfo.m_reader_info.m_read_callback = elf_loader_reader_read_elf_file_stdio_read_callback; + procinfo.m_reader_info.m_result_callback = elf_loader_reader_read_elf_file_stdio_result_callback; + procinfo.m_fp = fopen(filename, flags); + if ( !procinfo.m_fp ) + return -30; + elf_loader_reader_read_elf_file(&procinfo.m_reader_info); + if ( procinfo.m_fp ) + { + fclose(procinfo.m_fp); + procinfo.m_fp = NULL; + } + if ( resultbuf ) + memcpy(resultbuf, &procinfo.m_resultbuf, sizeof(elf_loader_reader_info_stdio_resultbuf_t)); + return procinfo.m_resultbuf.m_result; +} diff --git a/ee/elf-loader2/src/include/elf_loader_common.h b/ee/elf-loader2/src/include/elf_loader_common.h new file mode 100644 index 00000000000..a92ea871863 --- /dev/null +++ b/ee/elf-loader2/src/include/elf_loader_common.h @@ -0,0 +1,143 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#ifndef __ELF_LOADER_COMMON_H__ +#define __ELF_LOADER_COMMON_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define ELF_LOADER_MAX_PROGRAM_HEADERS 32 + + typedef struct elf_loader_elf32_ehdr_ + { + u8 e_ident[16]; + u16 e_type; + u16 e_machine; + u32 e_version; + u32 e_entry; + u32 e_phoff; + u32 e_shoff; + u32 e_flags; + u16 e_ehsize; + u16 e_phentsize; + u16 e_phnum; + u16 e_shentsize; + u16 e_shnum; + u16 e_shstrndx; + } elf_loader_elf32_ehdr_t; + + typedef struct elf_loader_elf32_phdr_ + { + u32 p_type; + u32 p_offset; + u32 p_vaddr; + u32 p_paddr; + u32 p_filesz; + u32 p_memsz; + u32 p_flags; + u32 p_align; + } elf_loader_elf32_phdr_t; + + // dest_addr != 0, src_addr != 0, size != 0: move + // dest_addr != 0, src_addr == 0, size != 0: zero + // dest_addr != 0, size == 0: exec + typedef struct elf_loader_loaderinfo_item_ + { + void *dest_addr; + void *src_addr; + u32 size; + } elf_loader_loaderinfo_item_t; + +#define ELF_LOADER_MAX_LOADERINFO_ITEMS (ELF_LOADER_MAX_PROGRAM_HEADERS + 3) + + typedef struct elf_loader_loaderinfo_ + { + elf_loader_loaderinfo_item_t items[ELF_LOADER_MAX_LOADERINFO_ITEMS]; + } elf_loader_loaderinfo_t; + + typedef struct elf_loader_arginfo_ + { + int argc; + char *argv[16]; + char payload[256]; + } elf_loader_arginfo_t; + + typedef struct elf_loader_execinfo_ + { + elf_loader_arginfo_t arginfo; + elf_loader_loaderinfo_t loaderinfo; + } elf_loader_execinfo_t; + + typedef struct elf_loader_reader_segment_info_ + { + void *m_segment_addr; + int m_segment_offset; + size_t m_segment_size; + } elf_loader_reader_segment_info_t; + + typedef enum elf_loader_reader_stage_ + { + ELF_LOADER_READER_STAGE_ELF_HEADER, + ELF_LOADER_READER_STAGE_PROGRAM_HEADERS, + ELF_LOADER_READER_STAGE_SEGMENTS, + ELF_LOADER_READER_STAGE_END, + } elf_loader_reader_stage_t; + + typedef void *(*elf_loader_reader_allocation_callback_t)( + void *userdata, void *pointer, ptrdiff_t old_size, ptrdiff_t new_size); + typedef int (*elf_loader_reader_read_callback_t)( + void *userdata, + elf_loader_reader_stage_t stage, + const elf_loader_reader_segment_info_t *segm_info, + size_t segm_count); + typedef void (*elf_loader_reader_result_callback_t)( + void *userdata, void *pointer, ptrdiff_t pointer_size, int errval); + typedef struct elf_loader_reader_info_ + { + void *m_userdata; + elf_loader_reader_allocation_callback_t m_alloc_callback; + elf_loader_reader_read_callback_t m_read_callback; + elf_loader_reader_result_callback_t m_result_callback; + } elf_loader_reader_info_t; + + typedef struct elf_loader_reader_info_stdio_resultbuf_ + { + void *m_buf; + ptrdiff_t m_bufsize; + int m_result; + } elf_loader_reader_info_stdio_resultbuf_t; + + // Defined in elf.c + extern int elf_loader_is_elf_ehdr_valid(const elf_loader_elf32_ehdr_t *ehdr); + extern int elf_loader_is_elf_valid_for_loading(const void *buf, size_t buf_size); + extern int elf_loader_exec_elf_prepare_loadinfo(elf_loader_execinfo_t *execinfo, const void *buf, size_t buf_size); + extern int elf_loader_exec_elf_prepare_arginfo( + elf_loader_execinfo_t *execinfo, const char *filename, const char *partition, int argc, char *argv[]); + extern int elf_loader_exec_elf(elf_loader_execinfo_t *execinfo); + + // Defined in elf_loader_reader.c + extern void elf_loader_reader_read_elf_file(elf_loader_reader_info_t *info); + + // Defined in elf_loader_stdio.c + extern int elf_loader_reader_read_elf_file_stdio( + elf_loader_reader_info_stdio_resultbuf_t *resultbuf, const char *filename, const char *flags); + +#ifdef __cplusplus +} +#endif + +#endif /* __ELF_LOADER_COMMON_H__ */ diff --git a/ee/elf-loader2/src/ldrsrc/Makefile b/ee/elf-loader2/src/ldrsrc/Makefile new file mode 100644 index 00000000000..cd806674f12 --- /dev/null +++ b/ee/elf-loader2/src/ldrsrc/Makefile @@ -0,0 +1,48 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. + +EE_BIN_DIR = bin/ +EE_OBJS_DIR = obj/ + +EE_LDRSRC_BIN = ldrsrc.bin +EE_LDRSRC_BIN := $(EE_LDRSRC_BIN:%=$(EE_BIN_DIR)%) +EE_LDRSRC_ELF = ldrsrc.elf +EE_LDRSRC_ELF := $(EE_LDRSRC_ELF:%=$(EE_BIN_DIR)%) +EE_OBJS = ldrsrc.o + +# Enable debug colors? +LOADER_ENABLE_DEBUG_COLORS ?= 0 + +EE_LIBS += -lc_nano +EE_INCS += -I$(PS2SDKSRC)/ee/elf-loader2/include -I$(PS2SDKSRC)/ee/elf-loader2/src/include +EE_CFLAGS += -mno-gpopt + +EE_LINKFILE ?= $(PS2SDKSRC)/ee/elf-loader2/src/ldrsrc/linkfile + +ifneq (x$(LOADER_ENABLE_DEBUG_COLORS), x0) +EE_CFLAGS += -DLOADER_ENABLE_DEBUG_COLORS +endif + +EE_LIB_ARCHIVES ?= $(PS2SDKSRC)/ee/kernel/lib/libkernel.a + +$(EE_LDRSRC_BIN): $(EE_LDRSRC_ELF) + $(DIR_GUARD) + $(EE_OBJCOPY) -Obinary $< $@ + +clean: + rm -f -r $(EE_OBJS_DIR) $(EE_BIN_DIR) + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/ee/Rules.make + +$(EE_LDRSRC_ELF): $(EE_OBJS) $(EE_LIB_ARCHIVES) + $(DIR_GUARD) + $(EE_CC) $(EE_CFLAGS) -o $@ $^ -nostdlib -nostartfiles -T$(EE_LINKFILE) -s $(EE_LIBS) $(EE_LIB_ARCHIVES) + +$(PS2SDKSRC)/ee/kernel/lib/libkernel.a: + $(MAKEREC) $(PS2SDKSRC)/ee/kernel diff --git a/ee/elf-loader2/src/ldrsrc/linkfile b/ee/elf-loader2/src/ldrsrc/linkfile new file mode 100644 index 00000000000..653632763a1 --- /dev/null +++ b/ee/elf-loader2/src/ldrsrc/linkfile @@ -0,0 +1,90 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +ENTRY(ldr_proc); + +MEMORY { + bram : ORIGIN = 0x00084000, LENGTH = 0x00004000 /* 0x11008000 - 0x1100C000: VU1 code memory */ +} + +REGION_ALIAS("MAIN_REGION", bram); + +PHDRS { + text PT_LOAD; +} + +SECTIONS { + .text : { + _ftext = . ; + *(.start) + *(.text) + *(.text.*) + *(.gnu.linkonce.t*) + QUAD(0) + } >MAIN_REGION :text + + PROVIDE(_etext = .); + PROVIDE(etext = .); + + .reginfo : { *(.reginfo) } >MAIN_REGION + + /* Static data. */ + .rodata ALIGN(128): { + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r*) + } >MAIN_REGION + + .data ALIGN(128): { + _fdata = . ; + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + SORT(CONSTRUCTORS) + } >MAIN_REGION + + _gp = ALIGN(128) + 0x7ff0; + .lit4 ALIGN(128): { *(.lit4) } >MAIN_REGION + .lit8 ALIGN(128): { *(.lit8) } >MAIN_REGION + + .sdata ALIGN(128): { + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s*) + } >MAIN_REGION + + _edata = .; + PROVIDE(edata = .); + + /* Uninitialized data. */ + .sbss ALIGN(128) : { + _fbss = . ; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb*) + *(.scommon) + } >MAIN_REGION + + .bss ALIGN(128) : { + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b*) + *(COMMON) + } >MAIN_REGION + _end_bss = .; + + _end = .; + PROVIDE(end = .); + + /* Unwanted stuff */ + /DISCARD/ : { + * ( .MIPS.abiflags ) + } +} diff --git a/ee/elf-loader2/src/ldrsrc/src/ldrsrc.c b/ee/elf-loader2/src/ldrsrc/src/ldrsrc.c new file mode 100644 index 00000000000..133c5dc180a --- /dev/null +++ b/ee/elf-loader2/src/ldrsrc/src/ldrsrc.c @@ -0,0 +1,98 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include +#include +#include +#include +#include +#include + +#ifdef LOADER_ENABLE_DEBUG_COLORS +#define SET_GS_BGCOLOUR(colour) \ + do \ + { \ + *((volatile unsigned long int *)0x120000E0) = colour; \ + } while ( 0 ) +#else +#define SET_GS_BGCOLOUR(colour) \ + do \ + { \ + } while ( 0 ) +#endif + +// Color status helper in BGR format +#define WHITE_BG 0xFFFFFF // start main +#define CYAN_BG 0xFFFF00 // move memory +#define GREEN_BG 0x00FF00 // set memory to 0 +#define RED_BG 0x0000FF // never encountered execution command +#define MAGENTA_BG 0xFF00FF // malformed loader info +#define BROWN_BG 0x2A2AA5 // before FlushCache +#define PURPLE_BG 0x800080 // before ExecPS2 + +//-------------------------------------------------------------- +// Redefinition of init/deinit libc: +//-------------------------------------------------------------- +// DON'T REMOVE, as it is for reducing binary size. +// These functions are defined as weak in /libc/src/init.c +//-------------------------------------------------------------- +void _libcglue_init() {} +void _libcglue_deinit() {} +void _libcglue_args_parse(int argc, char **argv) {} + +DISABLE_PATCHED_FUNCTIONS(); +DISABLE_EXTRA_TIMERS_FUNCTIONS(); +PS2_DISABLE_AUTOSTART_PTHREAD(); + +void __attribute__((section(".start"))) ldr_proc(void); +void ldr_proc(void) +{ + elf_loader_loaderinfo_t *ldrinfo; + elf_loader_arginfo_t *arginfo; + + SET_GS_BGCOLOUR(WHITE_BG); + ldrinfo = (void *)0x11004000; + arginfo = (void *)0x00088000; + + { + int i; + for ( i = 0; i < (sizeof(ldrinfo->items) / sizeof(ldrinfo->items[0])); i += 1 ) + { + elf_loader_loaderinfo_item_t *item; + + item = &(ldrinfo->items[i]); + if ( item->dest_addr != NULL && item->src_addr != NULL && item->size != 0 ) + { + SET_GS_BGCOLOUR(CYAN_BG); + memmove(item->dest_addr, item->src_addr, item->size); + } + else if ( item->dest_addr != NULL && item->src_addr == NULL && item->size != 0 ) + { + SET_GS_BGCOLOUR(GREEN_BG); + memset(item->dest_addr, 0, item->size); + } + else if ( item->dest_addr != NULL && item->size == 0 ) + { + SET_GS_BGCOLOUR(BROWN_BG); + FlushCache(0); + FlushCache(2); + SET_GS_BGCOLOUR(PURPLE_BG); + ExecPS2(item->dest_addr, item->src_addr, arginfo->argc, arginfo->argv); + } + else + { + SET_GS_BGCOLOUR(MAGENTA_BG); + break; + } + } + } + SET_GS_BGCOLOUR(RED_BG); + __builtin_trap(); +}