//-------------------------------------------------------------- //File name: loader.c //-------------------------------------------------------------- //dlanor: This subprogram has been modified to minimize the code //dlanor: size of the resident loader portion. Some of the parts //dlanor: that were moved into the main program include loading //dlanor: of all IRXs and mounting pfs0: for ELFs on hdd. //dlanor: Another change was to skip threading in favor of ExecPS2 /*================================================================== == == == Copyright(c)2004 Adam Metcalf(gamblore_@hotmail.com) == == Copyright(c)2004 Thomas Hawcroft(t0mb0la@yahoo.com) == == This file is subject to terms and conditions shown in the == == file LICENSE which should be kept in the top folder of == == this distribution. == == == == Portions of this code taken from PS2Link: == == pkoLoadElf == == wipeUserMemory == == (C) 2003 Tord Lindstrom (pukko@home.se) == == (C) 2003 adresd (adresd_ps2dev@yahoo.com) == == Portions of this code taken from Independence MC exploit == == tLoadElf == == LoadAndRunHDDElf == == (C) 2003 Marcus Brown == == == ==================================================================*/ #include "tamtypes.h" #include "debug.h" #include "kernel.h" #include "sifrpc.h" #include "loadfile.h" #include "fileio.h" #include "iopcontrol.h" #include "stdarg.h" #include "stdio.h" // Iritscen: added this for printf() #include "string.h" #include "malloc.h" #include "libmc.h" #include "iopheap.h" #include "sys/fcntl.h" #include "sys/stat.h" #include "sys/ioctl.h" #include "fileXio_rpc.h" #include "errno.h" #include "libhdd.h" #include "sbv_patches.h" //-------------------------------------------------------------- //#define DEBUG #ifdef DEBUG #define dbgprintf(args...) scr_printf(args) #define dbginit_scr() init_scr() #else #define dbgprintf(args...) do { } while(0) #define dbginit_scr() do { } while(0) #endif // ELF-header structures and identifiers #define ELF_MAGIC 0x464c457f #define ELF_PT_LOAD 1 //-------------------------------------------------------------- typedef struct { u8 ident[16]; 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; u32 offset; void *vaddr; u32 paddr; u32 filesz; u32 memsz; u32 flags; u32 align; } elf_pheader_t; //-------------------------------------------------------------- t_ExecData elfdata; int fileMode = FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IXUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IXGRP | FIO_S_IROTH | FIO_S_IWOTH | FIO_S_IXOTH; char HDDpath[256]; char partition[128]; static int pkoLoadElf(char *path); int userThreadID = 0; ////static char userThreadStack[16*1024] __attribute__((aligned(16))); #define MAX_ARGS 16 #define MAX_ARGLEN 256 struct argData { int flag; // Contains thread id atm int argc; char *argv[MAX_ARGS]; } __attribute__((packed)) userArgs; //-------------------------------------------------------------- //End of data declarations //-------------------------------------------------------------- //Start of function code: //-------------------------------------------------------------- // Read ELF from hard drive to required location(s) in memory. // Modified version of loader from Independence // (C) 2003 Marcus R. Brown //-------------------------------------------------------------- static int tLoadElf(char *filename) { u8 *boot_elf = (u8 *)0x1800000; elf_header_t *eh = (elf_header_t *)boot_elf; elf_pheader_t *eph; int fd, size, i; //NB: Coming here means pfs0: was mounted correctly earlier if ((fd = fileXioOpen(filename, O_RDONLY, fileMode)) < 0) { dbgprintf("Failed in fileXioOpen %s\n",filename); goto error; } dbgprintf("Opened file %s\n",filename); size = fileXioLseek(fd, 0, SEEK_END); dbgprintf("File size = %i\n",size); if (!size) { dbgprintf("Failed in fileXioLseek\n"); fileXioClose(fd); goto error; } fileXioLseek(fd, 0, SEEK_SET); fileXioRead(fd, boot_elf, sizeof(elf_header_t)); dbgprintf("Read elf header from file\n"); fileXioLseek(fd, eh->phoff, SEEK_SET); eph = (elf_pheader_t *)(boot_elf + eh->phoff); size=eh->phnum*eh->phentsize; size=fileXioRead(fd, (void *)eph, size); dbgprintf("Read %i bytes of program header(s) from file\n",size); for (i = 0; i < eh->phnum; i++) { if (eph[i].type != ELF_PT_LOAD) continue; fileXioLseek(fd, eph[i].offset, SEEK_SET); size=eph[i].filesz; size=fileXioRead(fd, eph[i].vaddr, size); dbgprintf("Read %i bytes to %x\n", size, eph[i].vaddr); if (eph[i].memsz > eph[i].filesz) memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz); } fileXioClose(fd); // fileXioUmount("pfs0:"); We leave the filesystem mounted now for fakehost if (_lw((u32)&eh->ident) != ELF_MAGIC) // this should have already been { // done by menu, but a double-check dbgprintf("Not a recognised ELF.\n"); // doesn't do any harm goto error; } dbgprintf("entry=%x\n",eh->entry); elfdata.epc=eh->entry; return 0; error: elfdata.epc=0; return -1; } //-------------------------------------------------------------- //End of func: int tLoadElf(char *filename) //-------------------------------------------------------------- // Load the actual elf, and create a thread for it // Return the thread id // PS2Link (C) 2003 Tord Lindstrom (pukko@home.se) // (C) 2003 adresd (adresd_ps2dev@yahoo.com) //-------------------------------------------------------------- static int pkoLoadElf(char *path) { ee_thread_t th_attr; int ret=0; int pid; if(!strncmp(path, "host", 4)) ret = SifLoadElf(path, &elfdata); else if(!strncmp(path, "mc", 2)) ret = SifLoadElf(path, &elfdata); else if(!strncmp(path, "cdrom", 5)) ret = SifLoadElf(path, &elfdata); else if(!strncmp(path, "cdfs", 4)) ret = SifLoadElf(path, &elfdata); else if(!strncmp(path, "pfs0", 4)) ret = tLoadElf(path); else if(!strncmp(path, "vmc", 3)) ret = tLoadElf(path); else ret = SifLoadElf(path, &elfdata); FlushCache(0); FlushCache(2); dbgprintf("EE: LoadElf returned %d\n", ret); dbgprintf("EE: Creating user thread (ent: %x, gp: %x, st: %x)\n", elfdata.epc, elfdata.gp, elfdata.sp); if (elfdata.epc == 0) { dbgprintf("EE: Could not load file\n"); return -1; } th_attr.func = (void *)elfdata.epc; //// th_attr.stack = userThreadStack; //// th_attr.stack_size = sizeof(userThreadStack); th_attr.gp_reg = (void *)elfdata.gp; th_attr.initial_priority = 64; pid = 1; ////CreateThread(&th_attr); if (pid < 0) { dbgprintf("EE: Create user thread failed %d\n", pid); return -1; } dbgprintf("EE: Created user thread: %d\n", pid); return pid; } //-------------------------------------------------------------- //End of func: static int pkoLoadElf(char *path) //-------------------------------------------------------------- // Clear user memory // PS2Link (C) 2003 Tord Lindstrom (pukko@home.se) // (C) 2003 adresd (adresd_ps2dev@yahoo.com) //-------------------------------------------------------------- void wipeUserMem(void) { int i; for (i = 0x100000; i < 0x2000000 ; i += 64) { asm ( "\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) //-------------------------------------------------------------- // C standard strrchr func.. returns pointer to the last occurance of a // character in a string, or NULL if not found // PS2Link (C) 2003 Tord Lindstrom (pukko@home.se) // (C) 2003 adresd (adresd_ps2dev@yahoo.com) //-------------------------------------------------------------- char *strrchr(const char *sp, int i) { const char *last = NULL; char c = i; while (*sp) { if (*sp == c) { last = sp; } sp++; } if (*sp == c) { last = sp; } return (char *) last; } //-------------------------------------------------------------- //End of func: char *strrchr(const char *sp, int i) //-------------------------------------------------------------- // *** MAIN *** //-------------------------------------------------------------- int main(int argc, char *argv[]) { char s[256],fakepart[128], *ptr; int pid=-1; // Initialize SifInitRpc(0); dbginit_scr(); wipeUserMem(); dbgprintf("Welcome to Loader of LaunchELF v3.50\nPlease wait...loading.\n"); strcpy(s,argv[0]); dbgprintf("argv[0] = %s\n",s); /*if (argc==1) // Iritscen: Commented this out and changed "(argc==2)" to "(argc>=2)" below in order to allow add'l args { // should be two params passed by menu while(1); // leave this here for adding mc0, host or other // to be added in future }*/ if (argc>=2) // if call came from hddmenu.elf { // arg1=path to ELF, arg2=partition to mount strcpy(partition,argv[1]); dbgprintf("argv[1] = %s\n", partition); strcpy(HDDpath,s); } dbgprintf("Loading %s\n",HDDpath); pid = pkoLoadElf(HDDpath); dbgprintf("pkoLoadElf returned %i\n",pid); //// if (pid < 0) //// { //// dbgprintf("failed\n"); //// dbgprintf("Could not execute file %s\n", HDDpath); //// return -1; //// } if(!strncmp(HDDpath, "pfs0", 4)) { strcpy(fakepart,HDDpath); ptr=strrchr(fakepart,'/'); if(ptr==NULL) strcpy(fakepart,"pfs0:"); else { ptr++; *ptr='\0'; } ptr=strrchr(s,'/'); if(ptr==NULL) ptr=strrchr(s,':'); if(ptr!=NULL) { ptr++; strcpy(HDDpath,"host:"); strcat(HDDpath,ptr); } } //// FlushCache(0); //// FlushCache(2); userThreadID = pid; // Iritscen: Copy extra arguments in argv[] to userArgs if (argc > 2) { printf("uLaunchELF loader: Received %d launch argument(s) for the game:\n", argc - 2); userArgs.argc = argc - 1; userArgs.argv[0] = HDDpath; int a; for (a = 0; a < argc - 2; a++) { userArgs.argv[a + 1] = argv[a + 2]; printf(" %s\n", argv[a + 2]); } } userArgs.flag = (int)&userThreadID; //// ret = StartThread(userThreadID, &userArgs); //// if (ret < 0) //// { //// dbgprintf("failed\n"); //// dbgprintf("EE: Start user thread failed %d\n", ret); //// DeleteThread(userThreadID); //// return -1; //// } //// SleepThread(); __asm__ __volatile__( ".set noreorder\n\t" "jal FlushCache\n\t" "li $a0, 0\n\t" "jal FlushCache\n\t" "li $a0, 2\n\t" "lui $sp, 0x000a\n\t" "nop\n\t" "addiu $sp, $sp, 0x8000\n\t" "nop\n\t" ".set reorder\n\t" ); ExecPS2((void *)elfdata.epc, (void *)elfdata.gp, userArgs.argc, userArgs.argv); return 0; } //-------------------------------------------------------------- //End of func: int main(int argc, char *argv[]) //-------------------------------------------------------------- //End of file: loader.c //--------------------------------------------------------------