diff --git a/ee/elf-loader-nocolour/Makefile b/ee/elf-loader-nocolour/Makefile index 3f46ac0c32e..49d4220b08d 100644 --- a/ee/elf-loader-nocolour/Makefile +++ b/ee/elf-loader-nocolour/Makefile @@ -2,7 +2,7 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Copyright ps2dev - http://www.ps2dev.org # Licenced under Academic Free License version 2.0 # Review ps2sdk README & LICENSE files for further details. diff --git a/ee/elf-loader-nocolour/src/loader/Makefile b/ee/elf-loader-nocolour/src/ldrsrc/Makefile similarity index 54% rename from ee/elf-loader-nocolour/src/loader/Makefile rename to ee/elf-loader-nocolour/src/ldrsrc/Makefile index 99222821df8..1143b15d356 100644 --- a/ee/elf-loader-nocolour/src/loader/Makefile +++ b/ee/elf-loader-nocolour/src/ldrsrc/Makefile @@ -2,17 +2,15 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# Copyright 2001-2004, ps2dev - http://www.ps2dev.org +# Copyright ps2dev - http://www.ps2dev.org # Licenced under Academic Free License version 2.0 # Review ps2sdk README & LICENSE files for further details. -EE_SRC_DIR = $(PS2SDKSRC)/ee/elf-loader/src/loader/src/ -EE_INC_DIR = $(PS2SDKSRC)/ee/elf-loader/src/loader/include/ +EE_SRC_DIR = $(PS2SDKSRC)/ee/elf-loader/src/ldrsrc/src/ +EE_INC_DIR = $(PS2SDKSRC)/ee/elf-loader/src/ldrsrc/include/ LOADER_ENABLE_DEBUG_COLORS ?= 0 -EE_LINKFILE ?= $(PS2SDKSRC)/ee/elf-loader/src/loader/linkfile +EE_LINKFILE ?= $(PS2SDKSRC)/ee/elf-loader/src/ldrsrc/linkfile -EE_BIN ?= loader.elf - -include $(PS2SDKSRC)/ee/elf-loader/src/loader/Makefile +include $(PS2SDKSRC)/ee/elf-loader/src/ldrsrc/Makefile diff --git a/ee/elf-loader/Makefile b/ee/elf-loader/Makefile index ddd75e180de..d0d62cc2b50 100644 --- a/ee/elf-loader/Makefile +++ b/ee/elf-loader/Makefile @@ -2,11 +2,11 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# (c) 2020 Francisco Javier Trujillo Mata +# 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 loader.o +EE_OBJS = elf.o ldrsrc.o include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/ee/Rules.lib.make @@ -16,15 +16,15 @@ include $(PS2SDKSRC)/ee/Rules.release $(PS2SDKSRC)/tools/bin2c/bin/bin2c: $(PS2SDKSRC)/tools/bin2c $(MAKEREC) $< -src/loader/bin/loader.elf: - $(MAKEREC) src/loader +src/ldrsrc/bin/ldrsrc.bin: + $(MAKEREC) src/ldrsrc -$(EE_OBJS_DIR)loader.c: src/loader/bin/loader.elf $(PS2SDKSRC)/tools/bin2c/bin/bin2c - $(PS2SDKSRC)/tools/bin2c/bin/bin2c $< $@ loader_elf +$(EE_OBJS_DIR)ldrsrc.c: src/ldrsrc/bin/ldrsrc.bin $(PS2SDKSRC)/tools/bin2c/bin/bin2c + $(PS2SDKSRC)/tools/bin2c/bin/bin2c $< $@ ldrsrc -$(EE_OBJS_DIR)loader.o: $(EE_OBJS_DIR)loader.c +$(EE_OBJS_DIR)ldrsrc.o: $(EE_OBJS_DIR)ldrsrc.c $(DIR_GUARD) $(EE_C_COMPILE) $< -c -o $@ clean:: - $(MAKEREC) src/loader clean + $(MAKEREC) src/ldrsrc clean diff --git a/ee/elf-loader/src/elf.c b/ee/elf-loader/src/elf.c index f709f3b7610..e231d9dca90 100644 --- a/ee/elf-loader/src/elf.c +++ b/ee/elf-loader/src/elf.c @@ -3,105 +3,492 @@ # ____| | ____| | | |____| # | ___| |____ ___| ____| | \ PS2DEV Open Source Project. #----------------------------------------------------------------------- -# (c) 2020 Francisco Javier Trujillo Mata +# 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 #include #include - -#include "elf.h" +#include +#include +#include +#include +#include // Loader ELF variables extern u8 loader_elf[]; extern int size_loader_elf; -// ELF-loading stuff -#define ELF_MAGIC 0x464c457f -#define ELF_PT_LOAD 1 +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; + +typedef struct elf_loader_file_load_handler_struct_ +{ + int fd; + elf_loader_elf32_ehdr_t elf_header; + elf_loader_elf32_phdr_t *program_header; +} elf_loader_file_load_handler_struct_t; -static bool file_exists(const char *filename) { - struct stat buffer; - return (stat (filename, &buffer) == 0); +static int check_elf_header(const elf_loader_elf32_ehdr_t *elf_header) +{ + if (elf_header->e_ident[0] != '\x7F') { + return -1; + } + if (elf_header->e_ident[1] != 'E') { + return -1; + } + if (elf_header->e_ident[2] != 'L') { + return -1; + } + if (elf_header->e_ident[3] != 'F') { + return -1; + } + return 0; } -/* IMPORTANT: This method wipe memory where the loader is going to be allocated -* This values come from the linkfile used by the loader.c -MEMORY { - bios : ORIGIN = 0x00000000, LENGTH = 528K --- 0x00000000 - 0x00084000: BIOS memory - bram : ORIGIN = 0x00084000, LENGTH = 496K --- 0x00084000 - 0x00100000: BIOS unused memory - gram : ORIGIN = 0x00100000, LENGTH = 31M --- 0x00100000 - 0x02000000: GAME memory +static int check_elf_architecture(const elf_loader_elf32_ehdr_t *elf_header) +{ + if (elf_header->e_ident[4] != 1) { + return -1; + } + if (elf_header->e_ident[5] != 1) { + return -2; + } + if (elf_header->e_type != 2) { + return -3; + } + if (elf_header->e_machine != 8) { + return -4; + } + if (elf_header->e_ehsize != 52) { + return -5; + } + if (elf_header->e_phentsize != 32) { + return -6; + } + if (elf_header->e_phnum > ELF_LOADER_MAX_PROGRAM_HEADERS) { + return -7; + } + if (elf_header->e_shnum == 0) { + return 1; + } + if (elf_header->e_shentsize != 40) { + return -8; + } + return 1; } -*/ -static void wipe_bramMem(void) { - int i; - for (i = 0x00084000; i < 0x100000; i += 64) { - asm volatile( - "\tsq $0, 0(%0) \n" - "\tsq $0, 16(%0) \n" - "\tsq $0, 32(%0) \n" - "\tsq $0, 48(%0) \n" ::"r"(i)); - } +static int check_valid_ee_elf(elf_loader_file_load_handler_struct_t *flhs) +{ + if (lseek(flhs->fd, 0, SEEK_SET) != 0) { + return -EIO; + } + if (read(flhs->fd, &flhs->elf_header, sizeof(elf_loader_elf32_ehdr_t)) != sizeof(elf_loader_elf32_ehdr_t)) { + return -EIO; + } + if (check_elf_header(&flhs->elf_header) < 0) { + return -ENOEXEC; + } + if (check_elf_architecture(&flhs->elf_header) < 0) { + return -ENOEXEC; + } + return 0; +} + +static int elf_get_program_header(elf_loader_file_load_handler_struct_t *flhs) +{ + int ph_totalbytes; + + ph_totalbytes = flhs->elf_header.e_phentsize * flhs->elf_header.e_phnum; + flhs->program_header = (elf_loader_elf32_phdr_t *)malloc(ph_totalbytes); + if (flhs->program_header == NULL) { + return -ENOMEM; + } + // TODO: check if program header offset is outside of LOADFILE worst case allocation size + if (lseek(flhs->fd, flhs->elf_header.e_phoff, SEEK_SET) != flhs->elf_header.e_phoff) { + return -EIO; + } + if (read(flhs->fd, flhs->program_header, ph_totalbytes) != ph_totalbytes) { + return -EIO; + } + return 0; } -int LoadELFFromFileWithPartition(const char *filename, const char *partition, int argc, char *argv[]) { - u8 *boot_elf; - elf_header_t *eh; - elf_pheader_t *eph; - void *pdata; - int i; - int new_argc = argc + 2; - - // We need to check that the ELF file before continue - if (!file_exists(filename)) { - return -1; // ELF file doesn't exists - } - // ELF Exists - wipe_bramMem(); - - // Preparing filename and partition to be sent in the argv - char *new_argv[argc + 2]; - new_argv[0] = partition != NULL ? (char *)partition : ""; - new_argv[1] = (char *)filename; - for (i = 0; i < argc; i++) { - new_argv[i + 2] = argv[i]; - } - - /* NB: LOADER.ELF is embedded */ - boot_elf = (u8 *)loader_elf; - eh = (elf_header_t *)boot_elf; - if (_lw((u32)&eh->ident) != ELF_MAGIC) - asm volatile("break\n"); - - eph = (elf_pheader_t *)(boot_elf + eh->phoff); - - /* Scan through the ELF's program headers and copy them into RAM, then zero out any non-loaded regions. */ - for (i = 0; i < eh->phnum; i++) { - if (eph[i].type != ELF_PT_LOAD) - continue; - - pdata = (void *)(boot_elf + eph[i].offset); - memcpy(eph[i].vaddr, pdata, eph[i].filesz); - - if (eph[i].memsz > eph[i].filesz) - memset((void *)((u8 *)(eph[i].vaddr) + eph[i].filesz), 0, eph[i].memsz - eph[i].filesz); - } - - /* Let's go. */ - SifExitRpc(); - FlushCache(0); - FlushCache(2); - - return ExecPS2((void *)eh->entry, NULL, new_argc, new_argv); +typedef struct elf_loader_keyval_ +{ + u32 kv_key; + u32 kv_value; +} elf_loader_keyval_t; + +static void sort_keyval_contents(int kv_count, elf_loader_keyval_t *ph_size_offset_data) +{ + if (kv_count > 1) { + int v2; + elf_loader_keyval_t *v4; + + v2 = 1; + v4 = ph_size_offset_data + 1; + do { + int v5; + elf_loader_keyval_t *v9; + u32 kv_key; + u32 kv_value; + + kv_key = v4->kv_key; + kv_value = v4->kv_value; + v5 = v2 - 1; + if (v5 >= 0) { + elf_loader_keyval_t *v6; + + v6 = &ph_size_offset_data[v5]; + for (;;) { + if (kv_value >= v6->kv_value) + break; + v6[1].kv_key = v6->kv_key; + v6[1].kv_value = v6->kv_value; + v5 -= 1; + v6 -= 1; + if (v5 < 0) { + break; + } + } + } + v9 = &ph_size_offset_data[v5]; + v9[1].kv_key = kv_key; + v9[1].kv_value = kv_value; + v2 += 1; + v4 += 1; + } while (v2 < kv_count); + } +} + +typedef struct elf_loader_psegment_ +{ + u32 buf_size; + u32 zero_size; + u32 inbuf_offset; + u32 outbuf_offset; + u32 load_address; +} elf_loader_psegment_t; + +static int elf_load_proc(elf_loader_file_load_handler_struct_t *flhs, void **buf_out) +{ + elf_loader_psegment_t psegment[ELF_LOADER_MAX_PROGRAM_HEADERS]; + unsigned int psegment_count; + psegment_count = 0; + if (flhs->program_header == NULL) { + return -ENOEXEC; + } + + u32 total_filesize; + total_filesize = sizeof(elf_loader_loaderinfo_t); + u32 data_start_offset = 0; + { + int i; + unsigned int kv_count; + kv_count = 0; + elf_loader_keyval_t kvinfo[ELF_LOADER_MAX_PROGRAM_HEADERS]; + + for (i = 0; i < flhs->elf_header.e_phnum; i += 1) { + elf_loader_elf32_phdr_t *program_header; + + program_header = &flhs->program_header[i]; + if (program_header->p_type == 1 && program_header->p_filesz != 0) { + kvinfo[kv_count].kv_key = i; + kvinfo[kv_count].kv_value = program_header->p_offset; + kv_count += 1; + } + } + psegment_count = kv_count; + sort_keyval_contents(kv_count, kvinfo); + + data_start_offset = total_filesize; + for (i = 0; i < kv_count; i += 1) { + elf_loader_elf32_phdr_t *program_header; + u32 key = kvinfo[i].kv_key; + + program_header = &flhs->program_header[kvinfo[i].kv_key]; + psegment[key].buf_size = program_header->p_filesz; + psegment[key].zero_size = program_header->p_filesz - program_header->p_memsz; + psegment[key].inbuf_offset = program_header->p_offset; + psegment[key].outbuf_offset = total_filesize; + psegment[key].load_address = program_header->p_vaddr; + total_filesize += program_header->p_filesz; + } + } + + int ret; + + void *buf; + buf = malloc(total_filesize); + if (buf == NULL) { + ret = -ENOMEM; + goto finish; + } + { + int i; + u8 *buf_cur = buf; + for (i = 0; i < psegment_count; i += 1) { + if (lseek(flhs->fd, psegment[i].inbuf_offset, SEEK_SET) != psegment[i].inbuf_offset) { + ret = -EIO; + goto finish; + } + if (read(flhs->fd, buf_cur + psegment[i].outbuf_offset, psegment[i].buf_size) != psegment[i].buf_size) { + ret = -EIO; + goto finish; + } + } + } + { + int i; + u32 min_load_addr; + u32 max_load_addr; + elf_loader_loaderinfo_t *buf_cur; + min_load_addr = 0xFFFFFFFF; + max_load_addr = 0x00100000; + buf_cur = buf; + buf_cur->count = psegment_count; + u32 info_count; + info_count = 0; + for (i = 0; i < psegment_count; i += 1) { + buf_cur->items[info_count].dest_addr = (void *)(psegment[i].load_address); + buf_cur->items[info_count].src_addr = (void *)(((u8 *)buf) + data_start_offset + psegment[i].outbuf_offset); + buf_cur->items[info_count].size = psegment[i].buf_size; + info_count += 1; + { + u32 load_address; + u32 end_load_address; + load_address = psegment[i].load_address; + end_load_address = load_address + psegment[i].buf_size; + 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 (psegment[i].zero_size != 0) { + } + } + if (min_load_addr != 0xFFFFFFFF) { + u32 wanted_size; + wanted_size = min_load_addr - 0x00100000; + if (wanted_size != 0) { + buf_cur->items[info_count].dest_addr = (void *)0x00100000; + buf_cur->items[info_count].src_addr = (void *)NULL; + buf_cur->items[info_count].size = wanted_size; + info_count += 1; + } + } + if (max_load_addr != 0x00100000) { + buf_cur->items[info_count].dest_addr = (void *)max_load_addr; + buf_cur->items[info_count].src_addr = (void *)NULL; + buf_cur->items[info_count].size = 0xFFFFFFFF; + info_count += 1; + } + buf_cur->items[info_count].dest_addr = (void *)(flhs->elf_header.e_entry); + buf_cur->items[info_count].src_addr = (void *)NULL; // GP returned is always NULL + buf_cur->items[info_count].size = 0; + } + if (buf_out) { + *buf_out = buf; + } + ret = 0; + +finish: + if (ret < 0 && buf != NULL) { + free(buf); + buf = NULL; + } + return ret; +} + +static int elf_load_all_section( + elf_loader_file_load_handler_struct_t *flhs, + void **buf_out) +{ + int result; + + result = check_valid_ee_elf(flhs); + if (result < 0) { + goto finish; + } + result = elf_get_program_header(flhs); + if (result < 0) { + goto finish; + } + { + int i; + int ph_count; + + ph_count = 0; + for (i = 0; i < flhs->elf_header.e_phnum; i += 1) { + elf_loader_elf32_phdr_t *program_header; + + program_header = &flhs->program_header[i]; + if (program_header->p_type == 1 && program_header->p_filesz != 0) { + // LOADFILE checked for before 0x80000. + // We'll check for usage before user memory to avoid clashing with the loader + if (program_header->p_vaddr < 0x00100000) { + result = -ENOEXEC; + goto finish; + } + ph_count += 1; + } + } + // TODO: do we need to handle more than one program header? + if (ph_count > 1) { + result = -ENOEXEC; + goto finish; + } + } + // TODO: check if entry point is in one of the program segments + if (flhs->elf_header.e_entry < 0x00100000) { + result = -ENOEXEC; + goto finish; + } + result = elf_load_proc(flhs, buf_out); + if (result < 0) { + goto finish; + } + result = 0; +finish: + if (flhs->program_header != NULL) { + free(flhs->program_header); + flhs->program_header = NULL; + } + return result; +} + +static void empty_elf_loader_information(elf_loader_file_load_handler_struct_t *flhs) +{ + flhs->fd = -1; + flhs->program_header = NULL; +} + +static int elf_load_common(const char *filename, void **buf_out) +{ + int result; + elf_loader_file_load_handler_struct_t flhs; + + empty_elf_loader_information(&flhs); + flhs.fd = open(filename, 1); + if (flhs.fd < 0) { + return -ENOENT; + } + result = elf_load_all_section(&flhs, buf_out); + close(flhs.fd); + return result; +} + +static void elf_loader_set_arginfo(elf_loader_arginfo_t *arginfo, const char *filename, const char *partition, int argc, char *argv[]) +{ + char *ptr; + int len, i; + + ptr = arginfo->payload; + argc = (argc > 15) ? 15 : argc; + arginfo->argc = argc + 1; + arginfo->argv[0] = ptr; + if (partition != NULL) { + len = strlen(partition); // Not including NULL terminator + memcpy(ptr, partition, len); + ptr += len; + } + len = strlen(filename) + 1; + memcpy(ptr, filename, len); + ptr += len; + + for (i = 0; i < argc; i += 1) { + arginfo->argv[i + 1] = ptr; + len = strlen(argv[i]) + 1; + memcpy(ptr, argv[i], len); + ptr += len; + } +} + +typedef void *(*ldr_getinternalinfo_callback)(void); +#define LDR_ENTRYPOINT_ADDR 0x00084000 + +int LoadELFFromFileWithPartition(const char *filename, const char *partition, int argc, char *argv[]) +{ + int ret; + void *buf; + ldr_getinternalinfo_callback cb; + void **ldr_internalinfo; + + buf = NULL; + ret = elf_load_common(filename, &buf); + if (ret < 0) { + return ret; + } + if (buf == NULL) { + return -1; + } + + // No turning back here. + while (!SifIopReset(NULL, 0)) {}; + while (!SifIopSync()) {}; + + SifInitRpc(0); + SifLoadFileInit(); + SifLoadModule("rom0:SIO2MAN", 0, NULL); + SifLoadModule("rom0:MCMAN", 0, NULL); + SifLoadModule("rom0:MCSERV", 0, NULL); + SifLoadFileExit(); + SifExitRpc(); + + memset((void *)LDR_ENTRYPOINT_ADDR, 0, 0x7c000); + memcpy((void *)LDR_ENTRYPOINT_ADDR, loader_elf, size_loader_elf); + FlushCache(0); + FlushCache(2); + cb = (void *)LDR_ENTRYPOINT_ADDR; + ldr_internalinfo = cb(); + elf_loader_execinfo_t *execinfo; + execinfo = (elf_loader_execinfo_t *)(ldr_internalinfo[0]); + elf_loader_set_arginfo(&(execinfo->arginfo), filename, partition, argc, argv); + memcpy(&(execinfo->loaderinfo), buf, sizeof(elf_loader_execinfo_t)); + // TODO: check if argv can be NULL + ExecPS2(ldr_internalinfo[1], NULL, 0, &(execinfo->arginfo.argv[1])); + // Should be unreachable here + Exit(126); + return -1; } int LoadELFFromFile(const char *filename, int argc, char *argv[]) { - return LoadELFFromFileWithPartition(filename, NULL, argc, argv); + return LoadELFFromFileWithPartition(filename, NULL, argc, argv); } diff --git a/ee/elf-loader/src/elf.h b/ee/elf-loader/src/elf.h deleted file mode 100644 index 03779bbbc43..00000000000 --- a/ee/elf-loader/src/elf.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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. -*/ - -#ifndef __ELF_H__ -#define __ELF_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct -{ - u8 ident[16]; // struct definition for ELF object header - u16 type; - u16 machine; - u32 version; - u32 entry; - u32 phoff; - u32 shoff; - u32 flags; - u16 ehsize; - u16 phentsize; - u16 phnum; - u16 shentsize; - u16 shnum; - u16 shstrndx; -} elf_header_t; - -typedef struct -{ - u32 type; // struct definition for ELF program section header - u32 offset; - void *vaddr; - u32 paddr; - u32 filesz; - u32 memsz; - u32 flags; - u32 align; -} elf_pheader_t; - -#ifdef __cplusplus -} -#endif - -#endif /* __ELF_H__ */ diff --git a/ee/elf-loader/src/include/elf_loader_common.h b/ee/elf-loader/src/include/elf_loader_common.h new file mode 100644 index 00000000000..292f6c5335c --- /dev/null +++ b/ee/elf-loader/src/include/elf_loader_common.h @@ -0,0 +1,57 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ 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 + +#ifdef __cplusplus +extern "C" { +#endif + +#define ELF_LOADER_MAX_PROGRAM_HEADERS 32 + +// dest_addr != 0, src_addr != 0, size != 0: move +// dest_addr != 0, src_addr == 0, size != 0: zero +// dest_addr != 0, src_addr == 0, size == 0xFFFFFFFF: zero to end of memory +// dest_addr != 0, src_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_ +{ + u32 count; + 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; + +#ifdef __cplusplus +} +#endif + +#endif /* __ELF_LOADER_COMMON_H__ */ diff --git a/ee/elf-loader/src/ldrsrc/Makefile b/ee/elf-loader/src/ldrsrc/Makefile new file mode 100644 index 00000000000..5c16fe9b82a --- /dev/null +++ b/ee/elf-loader/src/ldrsrc/Makefile @@ -0,0 +1,41 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ 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 + +EE_LIBS += -lc_nano +EE_INCS += -I$(PS2SDKSRC)/ee/elf-loader/src/include +EE_CFLAGS += -mno-gpopt + +EE_LINKFILE ?= $(PS2SDKSRC)/ee/elf-loader/src/ldrsrc/linkfile + +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-loader/src/ldrsrc/linkfile b/ee/elf-loader/src/ldrsrc/linkfile new file mode 100644 index 00000000000..0304422ff41 --- /dev/null +++ b/ee/elf-loader/src/ldrsrc/linkfile @@ -0,0 +1,101 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ 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_getinternalinfo); + +MEMORY { + bram : ORIGIN = 0x00084000, LENGTH = 0x7c000 /* 0x00084000 - 0x00100000: Low user region */ +} + +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 = .; + + /* Symbols needed by crt0. */ + PROVIDE(_heap_size = 0x2000); + PROVIDE(_stack_size = 0x2000); + + _stack = ALIGN(128); + PROVIDE(_stack = .); + . = _stack + _stack_size; + + /* Special region at the end of the image for storing additional arguments. */ + .ldr_userarg ALIGN(16): { *(.ldr_userarg) } + + _end = .; + PROVIDE(end = .); + + /* Unwanted stuff */ + /DISCARD/ : { + * ( .MIPS.abiflags ) + } +} diff --git a/ee/elf-loader/src/ldrsrc/src/ldrsrc.c b/ee/elf-loader/src/ldrsrc/src/ldrsrc.c new file mode 100644 index 00000000000..a452dc6ac48 --- /dev/null +++ b/ee/elf-loader/src/ldrsrc/src/ldrsrc.c @@ -0,0 +1,145 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ 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() {} + +DISABLE_PATCHED_FUNCTIONS(); +DISABLE_EXTRA_TIMERS_FUNCTIONS(); +PS2_DISABLE_AUTOSTART_PTHREAD(); + +elf_loader_execinfo_t ldr_userarg __attribute__((section(".ldr_userarg"))); + +static void ldr_proc(void) +{ + elf_loader_execinfo_t *execinfo; + elf_loader_loaderinfo_t *ldrinfo; + elf_loader_arginfo_t *arginfo; + + SET_GS_BGCOLOUR(WHITE_BG); + execinfo = (elf_loader_execinfo_t *)&ldr_userarg; + ldrinfo = &(execinfo->loaderinfo); + arginfo = &(execinfo->arginfo); + + { + int i; + for (i = 0; i < ldrinfo->count; 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); + if (item->size == 0xFFFFFFFF) { + memset(item->dest_addr, 0, ((u32)item->dest_addr) - GetMemorySize()); + } + else { + memset(item->dest_addr, 0, item->size); + } + } + else if (item->dest_addr != NULL && item->src_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); + Exit(126); +} + +extern char* _end; +extern char* _heap_size; +extern char* _stack; +extern char* _stack_size; + +static void ldr_entrypoint_stack(); + +static char args_storage[324]; + +// Modified crt0 +// bss zero is skipped, and argument handling removed +static void ldr_entrypoint(void) +{ + asm volatile( + // SetupThread + "move $4, $0 \n" + "la $5, _stack \n" + "la $6, _stack_size \n" + // TODO: can we set args to NULL? + "la $7, %0 \n" + "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"(ldr_entrypoint_stack)); +} + +static void ldr_entrypoint_stack() +{ + SetupHeap(&_end, (int)&_heap_size); + + FlushCache(0); + + ldr_proc(); +} + +static const void *ldr_internalinfo[] = { + &ldr_userarg, + &ldr_entrypoint, +}; + +void *ldr_getinternalinfo(void) __attribute__((section(".start"))); + +void *ldr_getinternalinfo(void) +{ + return &ldr_internalinfo; +} diff --git a/ee/elf-loader/src/loader/Makefile b/ee/elf-loader/src/loader/Makefile deleted file mode 100644 index 7ee2e43094c..00000000000 --- a/ee/elf-loader/src/loader/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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. - -EE_OBJS = loader.o - -# Enable debug colors? -LOADER_ENABLE_DEBUG_COLORS ?= 1 - -# Use nano newlib for saving space -EE_NEWLIB_NANO ?= 1 -EE_COMPACT_EXECUTABLE ?= 1 - -EE_LINKFILE ?= linkfile - -ifneq (x$(LOADER_ENABLE_DEBUG_COLORS), x0) -EE_CFLAGS += -DLOADER_ENABLE_DEBUG_COLORS -endif - -include $(PS2SDKSRC)/Defs.make -include $(PS2SDKSRC)/ee/Rules.bin.make -include $(PS2SDKSRC)/ee/Rules.make -include $(PS2SDKSRC)/ee/Rules.release diff --git a/ee/elf-loader/src/loader/linkfile b/ee/elf-loader/src/loader/linkfile deleted file mode 100644 index 344db6899dd..00000000000 --- a/ee/elf-loader/src/loader/linkfile +++ /dev/null @@ -1,69 +0,0 @@ -ENTRY(__start); - -MEMORY { - bios : ORIGIN = 0x00000000, LENGTH = 528K /* 0x00000000 - 0x00084000: BIOS memory */ - bram : ORIGIN = 0x00084000, LENGTH = 496K /* 0x00084000 - 0x00100000: BIOS unused memory */ - gram : ORIGIN = 0x00100000, LENGTH = 31M /* 0x00100000 - 0x02000000: GAME memory */ -} - -REGION_ALIAS("MAIN_REGION", bram); - -PHDRS { - text PT_LOAD; -} - -SECTIONS { - .text : { - *(.text) - } >MAIN_REGION :text - - .reginfo : { *(.reginfo) } >MAIN_REGION - - .ctors ALIGN(16): { - KEEP(*crtbegin*.o(.ctors)) - KEEP(*(EXCLUDE_FILE(*crtend*.o) .ctors)) - KEEP(*(SORT(.ctors.*))) - KEEP(*(.ctors)) - } >MAIN_REGION - - .dtors ALIGN(16): { - KEEP(*crtbegin*.o(.dtors)) - KEEP(*(EXCLUDE_FILE(*crtend*.o) .dtors)) - KEEP(*(SORT(.dtors.*))) - KEEP(*(.dtors)) - } >MAIN_REGION - - .rodata ALIGN(128): { - *(.rodata) - } >MAIN_REGION - - .data ALIGN(128): { - _fdata = . ; - *(.data) - SORT(CONSTRUCTORS) - } >MAIN_REGION - - _gp = ALIGN(128) + 0x7ff0; - .lit4 ALIGN(128): { *(.lit4) } >MAIN_REGION - .lit8 ALIGN(128): { *(.lit8) } >MAIN_REGION - - .sdata ALIGN(128): { - *(.sdata) - } >MAIN_REGION - - .sbss ALIGN(128) : { - _fbss = . ; - *(.sbss) - } >MAIN_REGION - - .bss ALIGN(128) : { - *(.bss) - } >MAIN_REGION - - /* Symbols needed by crt0.s. */ - PROVIDE(_end = .); - PROVIDE(_heap_size = -1); - - PROVIDE(_stack = .); - PROVIDE(_stack_size = ORIGIN(MAIN_REGION) + LENGTH(MAIN_REGION) - _stack); -} diff --git a/ee/elf-loader/src/loader/src/loader.c b/ee/elf-loader/src/loader/src/loader.c deleted file mode 100644 index a35a8b82c92..00000000000 --- a/ee/elf-loader/src/loader/src/loader.c +++ /dev/null @@ -1,154 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ 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. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef LOADER_ENABLE_DEBUG_COLORS -#define SET_GS_BGCOLOUR(colour) {*((volatile unsigned long int *)0x120000E0) = colour;} -#else -#define SET_GS_BGCOLOUR(colour) -#endif - -// Color status helper in BGR format -#define WHITE_BG 0xFFFFFF // start main -#define CYAN_BG 0xFFFF00 // proper argc count -#define RED_BG 0x0000FF // wrong argc count -#define GREEN_BG 0x00FF00 // before SifLoadELF -#define BLUE_BG 0xFF0000 // after SifLoadELF -#define YELLOW_BG 0x00FFFF // good SifLoadELF return -#define MAGENTA_BG 0xFF00FF // wrong SifLoadELF return -#define ORANGE_BG 0x00A5FF // after reset IOP -#define BROWN_BG 0x2A2AA5 // before FlushCache -#define PURPBLE_BG 0x800080 // before ExecPS2 - - -//-------------------------------------------------------------- -// Redefinition of init/deinit libc: -//-------------------------------------------------------------- -// DON'T REMOVE is for reducing binary size. -// These funtios are defined as weak in /libc/src/init.c -//-------------------------------------------------------------- - void _libcglue_init() {} - void _libcglue_deinit() {} - - DISABLE_PATCHED_FUNCTIONS(); - DISABLE_EXTRA_TIMERS_FUNCTIONS(); - PS2_DISABLE_AUTOSTART_PTHREAD(); - -//-------------------------------------------------------------- -//Start of function code: -//-------------------------------------------------------------- -// Clear user memory -// PS2Link (C) 2003 Tord Lindstrom (pukko@home.se) -// (C) 2003 adresd (adresd_ps2dev@yahoo.com) -//-------------------------------------------------------------- -static void wipeUserMem(void) -{ - int i; - for (i = 0x100000; i < GetMemorySize(); i += 64) { - asm volatile( - "\tsq $0, 0(%0) \n" - "\tsq $0, 16(%0) \n" - "\tsq $0, 32(%0) \n" - "\tsq $0, 48(%0) \n" ::"r"(i)); - } -} - -//-------------------------------------------------------------- -//End of func: void wipeUserMem(void) -//-------------------------------------------------------------- -// *** MAIN *** -// -//-------------------------------------------------------------- -int main(int argc, char *argv[]) -{ - static t_ExecData elfdata; - int ret, i; - - elfdata.epc = 0; - - SET_GS_BGCOLOUR(WHITE_BG); - // arg[0] partition if exists, otherwise is "" - // arg[1]=path to ELF - if (argc < 2) { - SET_GS_BGCOLOUR(RED_BG); - return -EINVAL; - } - - char *new_argv[argc - 1]; - int fullPath_length = 1 + strlen(argv[0]) + strlen(argv[1]); - char fullPath[fullPath_length]; - strcpy(fullPath, argv[0]); - strcat(fullPath, argv[1]); - // final new_argv[0] is partition + path to elf - new_argv[0] = fullPath; - for (i = 2; i < argc; i++) { - new_argv[i - 1] = argv[i]; - } - - SET_GS_BGCOLOUR(CYAN_BG); - - // Initialize - SifInitRpc(0); - wipeUserMem(); - - //Writeback data cache before loading ELF. - FlushCache(0); - SET_GS_BGCOLOUR(GREEN_BG); - SifLoadFileInit(); - ret = SifLoadElf(argv[1], &elfdata); - SifLoadFileExit(); - SET_GS_BGCOLOUR(BLUE_BG); - if (ret == 0 && elfdata.epc != 0) { - SET_GS_BGCOLOUR(YELLOW_BG); - - // Let's reset IOP because ELF was already loaded in memory - while(!SifIopReset(NULL, 0)){}; - while (!SifIopSync()) {}; - - SET_GS_BGCOLOUR(ORANGE_BG); - - SifInitRpc(0); - // Load modules. - SifLoadFileInit(); - SifLoadModule("rom0:SIO2MAN", 0, NULL); - SifLoadModule("rom0:MCMAN", 0, NULL); - SifLoadModule("rom0:MCSERV", 0, NULL); - SifLoadFileExit(); - SifExitRpc(); - - SET_GS_BGCOLOUR(BROWN_BG); - - FlushCache(0); - FlushCache(2); - - SET_GS_BGCOLOUR(PURPBLE_BG); - - return ExecPS2((void *)elfdata.epc, (void *)elfdata.gp, argc-1, new_argv); - } else { - SET_GS_BGCOLOUR(MAGENTA_BG); - SifExitRpc(); - return -ENOENT; - } -} - -//-------------------------------------------------------------- -//End of func: int main(int argc, char *argv[]) -//-------------------------------------------------------------- -//End of file: loader.c -//--------------------------------------------------------------