| 1 |
//-------------------------------------------------------------- |
| 2 |
//File name: loader.c |
| 3 |
//-------------------------------------------------------------- |
| 4 |
//dlanor: This subprogram has been modified to minimize the code |
| 5 |
//dlanor: size of the resident loader portion. Some of the parts |
| 6 |
//dlanor: that were moved into the main program include loading |
| 7 |
//dlanor: of all IRXs and mounting pfs0: for ELFs on hdd. |
| 8 |
//dlanor: Another change was to skip threading in favor of ExecPS2 |
| 9 |
/*================================================================== |
| 10 |
== == |
| 11 |
== Copyright(c)2004 Adam Metcalf(gamblore_@hotmail.com) == |
| 12 |
== Copyright(c)2004 Thomas Hawcroft(t0mb0la@yahoo.com) == |
| 13 |
== This file is subject to terms and conditions shown in the == |
| 14 |
== file LICENSE which should be kept in the top folder of == |
| 15 |
== this distribution. == |
| 16 |
== == |
| 17 |
== Portions of this code taken from PS2Link: == |
| 18 |
== pkoLoadElf == |
| 19 |
== wipeUserMemory == |
| 20 |
== (C) 2003 Tord Lindstrom (pukko@home.se) == |
| 21 |
== (C) 2003 adresd (adresd_ps2dev@yahoo.com) == |
| 22 |
== Portions of this code taken from Independence MC exploit == |
| 23 |
== tLoadElf == |
| 24 |
== LoadAndRunHDDElf == |
| 25 |
== (C) 2003 Marcus Brown <mrbrown@0xd6.org> == |
| 26 |
== == |
| 27 |
==================================================================*/ |
| 28 |
#include "tamtypes.h" |
| 29 |
#include "debug.h" |
| 30 |
#include "kernel.h" |
| 31 |
#include "sifrpc.h" |
| 32 |
#include "loadfile.h" |
| 33 |
#include "fileio.h" |
| 34 |
#include "iopcontrol.h" |
| 35 |
#include "stdarg.h" |
| 36 |
#include "stdio.h" // Iritscen: added this for printf() |
| 37 |
#include "string.h" |
| 38 |
#include "malloc.h" |
| 39 |
#include "libmc.h" |
| 40 |
#include "iopheap.h" |
| 41 |
#include "sys/fcntl.h" |
| 42 |
#include "sys/stat.h" |
| 43 |
#include "sys/ioctl.h" |
| 44 |
#include "fileXio_rpc.h" |
| 45 |
#include "errno.h" |
| 46 |
#include "libhdd.h" |
| 47 |
#include "sbv_patches.h" |
| 48 |
//-------------------------------------------------------------- |
| 49 |
//#define DEBUG |
| 50 |
#ifdef DEBUG |
| 51 |
#define dbgprintf(args...) scr_printf(args) |
| 52 |
#define dbginit_scr() init_scr() |
| 53 |
#else |
| 54 |
#define dbgprintf(args...) do { } while(0) |
| 55 |
#define dbginit_scr() do { } while(0) |
| 56 |
#endif |
| 57 |
|
| 58 |
// ELF-header structures and identifiers |
| 59 |
#define ELF_MAGIC 0x464c457f |
| 60 |
#define ELF_PT_LOAD 1 |
| 61 |
|
| 62 |
//-------------------------------------------------------------- |
| 63 |
typedef struct |
| 64 |
{ |
| 65 |
u8 ident[16]; |
| 66 |
u16 type; |
| 67 |
u16 machine; |
| 68 |
u32 version; |
| 69 |
u32 entry; |
| 70 |
u32 phoff; |
| 71 |
u32 shoff; |
| 72 |
u32 flags; |
| 73 |
u16 ehsize; |
| 74 |
u16 phentsize; |
| 75 |
u16 phnum; |
| 76 |
u16 shentsize; |
| 77 |
u16 shnum; |
| 78 |
u16 shstrndx; |
| 79 |
} elf_header_t; |
| 80 |
//-------------------------------------------------------------- |
| 81 |
typedef struct |
| 82 |
{ |
| 83 |
u32 type; |
| 84 |
u32 offset; |
| 85 |
void *vaddr; |
| 86 |
u32 paddr; |
| 87 |
u32 filesz; |
| 88 |
u32 memsz; |
| 89 |
u32 flags; |
| 90 |
u32 align; |
| 91 |
} elf_pheader_t; |
| 92 |
//-------------------------------------------------------------- |
| 93 |
t_ExecData elfdata; |
| 94 |
|
| 95 |
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; |
| 96 |
char HDDpath[256]; |
| 97 |
char partition[128]; |
| 98 |
|
| 99 |
static int pkoLoadElf(char *path); |
| 100 |
|
| 101 |
int userThreadID = 0; |
| 102 |
////static char userThreadStack[16*1024] __attribute__((aligned(16))); |
| 103 |
|
| 104 |
#define MAX_ARGS 16 |
| 105 |
#define MAX_ARGLEN 256 |
| 106 |
|
| 107 |
struct argData |
| 108 |
{ |
| 109 |
int flag; // Contains thread id atm |
| 110 |
int argc; |
| 111 |
char *argv[MAX_ARGS]; |
| 112 |
} __attribute__((packed)) userArgs; |
| 113 |
//-------------------------------------------------------------- |
| 114 |
//End of data declarations |
| 115 |
//-------------------------------------------------------------- |
| 116 |
//Start of function code: |
| 117 |
//-------------------------------------------------------------- |
| 118 |
// Read ELF from hard drive to required location(s) in memory. |
| 119 |
// Modified version of loader from Independence |
| 120 |
// (C) 2003 Marcus R. Brown <mrbrown@0xd6.org> |
| 121 |
//-------------------------------------------------------------- |
| 122 |
static int tLoadElf(char *filename) |
| 123 |
{ |
| 124 |
u8 *boot_elf = (u8 *)0x1800000; |
| 125 |
elf_header_t *eh = (elf_header_t *)boot_elf; |
| 126 |
elf_pheader_t *eph; |
| 127 |
|
| 128 |
int fd, size, i; |
| 129 |
|
| 130 |
//NB: Coming here means pfs0: was mounted correctly earlier |
| 131 |
if ((fd = fileXioOpen(filename, O_RDONLY, fileMode)) < 0) |
| 132 |
{ |
| 133 |
dbgprintf("Failed in fileXioOpen %s\n",filename); |
| 134 |
goto error; |
| 135 |
} |
| 136 |
dbgprintf("Opened file %s\n",filename); |
| 137 |
size = fileXioLseek(fd, 0, SEEK_END); |
| 138 |
dbgprintf("File size = %i\n",size); |
| 139 |
if (!size) |
| 140 |
{ |
| 141 |
dbgprintf("Failed in fileXioLseek\n"); |
| 142 |
fileXioClose(fd); |
| 143 |
goto error; |
| 144 |
} |
| 145 |
fileXioLseek(fd, 0, SEEK_SET); |
| 146 |
fileXioRead(fd, boot_elf, sizeof(elf_header_t)); |
| 147 |
dbgprintf("Read elf header from file\n"); |
| 148 |
fileXioLseek(fd, eh->phoff, SEEK_SET); |
| 149 |
eph = (elf_pheader_t *)(boot_elf + eh->phoff); |
| 150 |
size=eh->phnum*eh->phentsize; |
| 151 |
size=fileXioRead(fd, (void *)eph, size); |
| 152 |
dbgprintf("Read %i bytes of program header(s) from file\n",size); |
| 153 |
for (i = 0; i < eh->phnum; i++) |
| 154 |
{ |
| 155 |
if (eph[i].type != ELF_PT_LOAD) |
| 156 |
continue; |
| 157 |
|
| 158 |
fileXioLseek(fd, eph[i].offset, SEEK_SET); |
| 159 |
size=eph[i].filesz; |
| 160 |
size=fileXioRead(fd, eph[i].vaddr, size); |
| 161 |
dbgprintf("Read %i bytes to %x\n", size, eph[i].vaddr); |
| 162 |
if (eph[i].memsz > eph[i].filesz) |
| 163 |
memset(eph[i].vaddr + eph[i].filesz, 0, |
| 164 |
eph[i].memsz - eph[i].filesz); |
| 165 |
} |
| 166 |
|
| 167 |
fileXioClose(fd); |
| 168 |
// fileXioUmount("pfs0:"); We leave the filesystem mounted now for fakehost |
| 169 |
|
| 170 |
if (_lw((u32)&eh->ident) != ELF_MAGIC) // this should have already been |
| 171 |
{ // done by menu, but a double-check |
| 172 |
dbgprintf("Not a recognised ELF.\n"); // doesn't do any harm |
| 173 |
goto error; |
| 174 |
} |
| 175 |
|
| 176 |
dbgprintf("entry=%x\n",eh->entry); |
| 177 |
elfdata.epc=eh->entry; |
| 178 |
return 0; |
| 179 |
error: |
| 180 |
elfdata.epc=0; |
| 181 |
return -1; |
| 182 |
} |
| 183 |
//-------------------------------------------------------------- |
| 184 |
//End of func: int tLoadElf(char *filename) |
| 185 |
//-------------------------------------------------------------- |
| 186 |
// Load the actual elf, and create a thread for it |
| 187 |
// Return the thread id |
| 188 |
// PS2Link (C) 2003 Tord Lindstrom (pukko@home.se) |
| 189 |
// (C) 2003 adresd (adresd_ps2dev@yahoo.com) |
| 190 |
//-------------------------------------------------------------- |
| 191 |
static int pkoLoadElf(char *path) |
| 192 |
{ |
| 193 |
ee_thread_t th_attr; |
| 194 |
int ret=0; |
| 195 |
int pid; |
| 196 |
|
| 197 |
if(!strncmp(path, "host", 4)) ret = SifLoadElf(path, &elfdata); |
| 198 |
else if(!strncmp(path, "mc", 2)) ret = SifLoadElf(path, &elfdata); |
| 199 |
else if(!strncmp(path, "cdrom", 5)) ret = SifLoadElf(path, &elfdata); |
| 200 |
else if(!strncmp(path, "cdfs", 4)) ret = SifLoadElf(path, &elfdata); |
| 201 |
else if(!strncmp(path, "pfs0", 4)) ret = tLoadElf(path); |
| 202 |
else if(!strncmp(path, "vmc", 3)) ret = tLoadElf(path); |
| 203 |
else ret = SifLoadElf(path, &elfdata); |
| 204 |
|
| 205 |
FlushCache(0); |
| 206 |
FlushCache(2); |
| 207 |
|
| 208 |
dbgprintf("EE: LoadElf returned %d\n", ret); |
| 209 |
|
| 210 |
dbgprintf("EE: Creating user thread (ent: %x, gp: %x, st: %x)\n", |
| 211 |
elfdata.epc, elfdata.gp, elfdata.sp); |
| 212 |
|
| 213 |
if (elfdata.epc == 0) { |
| 214 |
dbgprintf("EE: Could not load file\n"); |
| 215 |
return -1; |
| 216 |
} |
| 217 |
|
| 218 |
th_attr.func = (void *)elfdata.epc; |
| 219 |
//// th_attr.stack = userThreadStack; |
| 220 |
//// th_attr.stack_size = sizeof(userThreadStack); |
| 221 |
th_attr.gp_reg = (void *)elfdata.gp; |
| 222 |
th_attr.initial_priority = 64; |
| 223 |
|
| 224 |
pid = 1; ////CreateThread(&th_attr); |
| 225 |
if (pid < 0) { |
| 226 |
dbgprintf("EE: Create user thread failed %d\n", pid); |
| 227 |
return -1; |
| 228 |
} |
| 229 |
dbgprintf("EE: Created user thread: %d\n", pid); |
| 230 |
|
| 231 |
return pid; |
| 232 |
} |
| 233 |
//-------------------------------------------------------------- |
| 234 |
//End of func: static int pkoLoadElf(char *path) |
| 235 |
//-------------------------------------------------------------- |
| 236 |
// Clear user memory |
| 237 |
// PS2Link (C) 2003 Tord Lindstrom (pukko@home.se) |
| 238 |
// (C) 2003 adresd (adresd_ps2dev@yahoo.com) |
| 239 |
//-------------------------------------------------------------- |
| 240 |
void wipeUserMem(void) |
| 241 |
{ |
| 242 |
int i; |
| 243 |
for (i = 0x100000; i < 0x2000000 ; i += 64) { |
| 244 |
asm ( |
| 245 |
"\tsq $0, 0(%0) \n" |
| 246 |
"\tsq $0, 16(%0) \n" |
| 247 |
"\tsq $0, 32(%0) \n" |
| 248 |
"\tsq $0, 48(%0) \n" |
| 249 |
:: "r" (i) ); |
| 250 |
} |
| 251 |
} |
| 252 |
//-------------------------------------------------------------- |
| 253 |
//End of func: void wipeUserMem(void) |
| 254 |
//-------------------------------------------------------------- |
| 255 |
// C standard strrchr func.. returns pointer to the last occurance of a |
| 256 |
// character in a string, or NULL if not found |
| 257 |
// PS2Link (C) 2003 Tord Lindstrom (pukko@home.se) |
| 258 |
// (C) 2003 adresd (adresd_ps2dev@yahoo.com) |
| 259 |
//-------------------------------------------------------------- |
| 260 |
char *strrchr(const char *sp, int i) |
| 261 |
{ |
| 262 |
const char *last = NULL; |
| 263 |
char c = i; |
| 264 |
|
| 265 |
while (*sp) |
| 266 |
{ |
| 267 |
if (*sp == c) |
| 268 |
{ |
| 269 |
last = sp; |
| 270 |
} |
| 271 |
sp++; |
| 272 |
} |
| 273 |
|
| 274 |
if (*sp == c) |
| 275 |
{ |
| 276 |
last = sp; |
| 277 |
} |
| 278 |
|
| 279 |
return (char *) last; |
| 280 |
} |
| 281 |
//-------------------------------------------------------------- |
| 282 |
//End of func: char *strrchr(const char *sp, int i) |
| 283 |
//-------------------------------------------------------------- |
| 284 |
// *** MAIN *** |
| 285 |
//-------------------------------------------------------------- |
| 286 |
int main(int argc, char *argv[]) |
| 287 |
{ |
| 288 |
char s[256],fakepart[128], *ptr; |
| 289 |
int pid=-1; |
| 290 |
|
| 291 |
// Initialize |
| 292 |
SifInitRpc(0); |
| 293 |
dbginit_scr(); |
| 294 |
wipeUserMem(); |
| 295 |
dbgprintf("Welcome to Loader of LaunchELF v3.50\nPlease wait...loading.\n"); |
| 296 |
|
| 297 |
strcpy(s,argv[0]); |
| 298 |
dbgprintf("argv[0] = %s\n",s); |
| 299 |
/*if (argc==1) // Iritscen: Commented this out and changed "(argc==2)" to "(argc>=2)" below in order to allow add'l args |
| 300 |
{ // should be two params passed by menu |
| 301 |
while(1); // leave this here for adding mc0, host or other |
| 302 |
// to be added in future |
| 303 |
}*/ |
| 304 |
if (argc>=2) // if call came from hddmenu.elf |
| 305 |
{ // arg1=path to ELF, arg2=partition to mount |
| 306 |
strcpy(partition,argv[1]); |
| 307 |
dbgprintf("argv[1] = %s\n", partition); |
| 308 |
strcpy(HDDpath,s); |
| 309 |
} |
| 310 |
dbgprintf("Loading %s\n",HDDpath); |
| 311 |
pid = pkoLoadElf(HDDpath); |
| 312 |
dbgprintf("pkoLoadElf returned %i\n",pid); |
| 313 |
//// if (pid < 0) |
| 314 |
//// { |
| 315 |
//// dbgprintf("failed\n"); |
| 316 |
//// dbgprintf("Could not execute file %s\n", HDDpath); |
| 317 |
//// return -1; |
| 318 |
//// } |
| 319 |
if(!strncmp(HDDpath, "pfs0", 4)) |
| 320 |
{ |
| 321 |
strcpy(fakepart,HDDpath); |
| 322 |
ptr=strrchr(fakepart,'/'); |
| 323 |
if(ptr==NULL) strcpy(fakepart,"pfs0:"); |
| 324 |
else |
| 325 |
{ |
| 326 |
ptr++; |
| 327 |
*ptr='\0'; |
| 328 |
} |
| 329 |
ptr=strrchr(s,'/'); |
| 330 |
if(ptr==NULL) ptr=strrchr(s,':'); |
| 331 |
if(ptr!=NULL) |
| 332 |
{ |
| 333 |
ptr++; |
| 334 |
strcpy(HDDpath,"host:"); |
| 335 |
strcat(HDDpath,ptr); |
| 336 |
} |
| 337 |
} |
| 338 |
|
| 339 |
//// FlushCache(0); |
| 340 |
//// FlushCache(2); |
| 341 |
|
| 342 |
userThreadID = pid; |
| 343 |
|
| 344 |
// Iritscen: Copy extra arguments in argv[] to userArgs |
| 345 |
if (argc > 2) |
| 346 |
{ |
| 347 |
printf("uLaunchELF loader: Received %d launch argument(s) for the game:\n", argc - 2); |
| 348 |
userArgs.argc = argc - 1; |
| 349 |
userArgs.argv[0] = HDDpath; |
| 350 |
int a; |
| 351 |
for (a = 0; a < argc - 2; a++) |
| 352 |
{ |
| 353 |
userArgs.argv[a + 1] = argv[a + 2]; |
| 354 |
printf(" %s\n", argv[a + 2]); |
| 355 |
} |
| 356 |
} |
| 357 |
userArgs.flag = (int)&userThreadID; |
| 358 |
|
| 359 |
//// ret = StartThread(userThreadID, &userArgs); |
| 360 |
//// if (ret < 0) |
| 361 |
//// { |
| 362 |
//// dbgprintf("failed\n"); |
| 363 |
//// dbgprintf("EE: Start user thread failed %d\n", ret); |
| 364 |
//// DeleteThread(userThreadID); |
| 365 |
//// return -1; |
| 366 |
//// } |
| 367 |
//// SleepThread(); |
| 368 |
|
| 369 |
__asm__ __volatile__( |
| 370 |
".set noreorder\n\t" |
| 371 |
"jal FlushCache\n\t" |
| 372 |
"li $a0, 0\n\t" |
| 373 |
"jal FlushCache\n\t" |
| 374 |
"li $a0, 2\n\t" |
| 375 |
"lui $sp, 0x000a\n\t" |
| 376 |
"nop\n\t" |
| 377 |
"addiu $sp, $sp, 0x8000\n\t" |
| 378 |
"nop\n\t" |
| 379 |
".set reorder\n\t" |
| 380 |
); |
| 381 |
ExecPS2((void *)elfdata.epc, (void *)elfdata.gp, userArgs.argc, userArgs.argv); |
| 382 |
return 0; |
| 383 |
} |
| 384 |
//-------------------------------------------------------------- |
| 385 |
//End of func: int main(int argc, char *argv[]) |
| 386 |
//-------------------------------------------------------------- |
| 387 |
//End of file: loader.c |
| 388 |
//-------------------------------------------------------------- |