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 |
//-------------------------------------------------------------- |