mgh: fix for default HDD DMA mode, that wasn't correctly set
[open-ps2-loader.git] / ee_core / src / syshook.c
blob681c4926406aa48101e8e5191537e2014f496505
1 /*
2 Copyright 2009-2010, Ifcaro, jimmikaelkael & Polo
3 Copyright 2006-2008 Polo
4 Licenced under Academic Free License version 3.0
5 Review OpenUsbLd README & LICENSE files for further details.
7 Some parts of the code are taken from HD Project by Polo
8 */
10 #include "ee_core.h"
11 #include "asm.h"
12 #include "iopmgr.h"
13 #include "modmgr.h"
14 #include "util.h"
15 #include "spu.h"
16 #include "patches.h"
17 #include "padhook.h"
18 #include "syshook.h"
20 #include <syscallnr.h>
21 #include <ee_regs.h>
22 #include <ps2_reg_defs.h>
24 extern void *cddev_irx;
25 extern int size_cddev_irx;
27 #define MAX_ARGS 15
29 int g_argc;
30 char *g_argv[1 + MAX_ARGS];
31 static char g_ElfPath[1024];
32 static void *g_patchInitializeUserMem_addr;
33 static u32 g_patchInitializeUserMem_val;
35 int set_reg_hook;
36 int set_reg_disabled;
37 int iop_reboot_count = 0;
39 int padOpen_hooked = 0;
41 static u32 systemRestartpattern[] = {
42 0x00000000, // nop
43 0x0c000000, // jal restartEE()
44 0x00000000, // nop
45 0x8fa30010, // lw v1, $0010(sp)
46 0x0240302d, // daddu a2, s2, zero
47 0x8fa50014, // lw a1, $0014(sp)
48 0x8c67000c, // lw a3, $000c(v1)
49 0x18e00009, // blez a3, 2f
50 0x0000202d, // daddu a0, zero, zero
51 0x00000000, // nop
52 0x8ca30000, // lw v1, $0000(a1)
53 0x24840004, // addiu a0, a0, $0004
54 0x24a50004, // addiu a1, a1, $0004
55 0x0087102a, // slt v0, a0, a3
56 0xacc30000 // sw v1, $0000(a2)
58 static u32 systemRestartpattern_mask[] = {
59 0xffffffff,
60 0xfc000000,
61 0xffffffff,
62 0xffffffff,
63 0xffffffff,
64 0xffffffff,
65 0xffffffff,
66 0xffffffff,
67 0xffffffff,
68 0xffffffff,
69 0xffffffff,
70 0xffffffff,
71 0xffffffff,
72 0xffffffff,
73 0xffffffff
76 static void (*systemRestart)(void);
78 static u32 InitializeUserMempattern[] = {
79 0x27bdffe0, // addiu sp, sp, $ffe0
80 0xffb00000, // sd s0, $0000(sp)
81 0xffbf0010, // sd ra, $0010(sp)
82 0x0c000000, // jal GetMemorySize
83 0x00000000, // daddu s0, a0, zero <-- some modchips are patching here, so we'll repatch
84 0x0040202d, // daddu a0, v0, zero
85 0x0204102b, // sltu v0, s0, a0
86 0x1040000a, // beq v0, zero, 2f
87 0xdfbf0010, // ld ra, $0010(sp)
88 0x700014a9, // por v0, zero, zero
89 0x7e020000, // sq v0, $0000(s0)
90 0x26100010, // addiu s0, s0, $10
91 0x0204102b, // sltu v0, s0, a0
92 0x00000000, // nop
93 0x00000000, // nop
94 0x1440fffa, // bne v0, zero, 1b
95 0x700014a9 // por v0, zero, zero
97 0xdfbf0010, // ld ra, $0010(sp)
98 0xdfbf0000, // ld s0, $0000(sp)
99 0x03e00008, // jr ra
100 0x27bd0020 // addiu sp, sp, $0020
104 static u32 InitializeUserMempattern_mask[] = {
105 0xffffffff,
106 0xffffffff,
107 0xffffffff,
108 0xfc000000,
109 0x00000000,
110 0xffffffff,
111 0xffffffff,
112 0xffffffff,
113 0xffffffff,
114 0xffffffff,
115 0xffffffff,
116 0xffffffff,
117 0xffffffff,
118 0xffffffff,
119 0xffffffff,
120 0xffffffff,
121 0xffffffff
124 static u32 InitializeTLBpattern[] = {
125 0x3c027000, // lui v0, $7000
126 0x8c423ff0, // lw v0, $3ff0(v0)
127 0x3c038001, // lui v1, $8001
128 0xac620000, // sw v0, $XXXX(v1)
129 0x3c02bfc0, // lui v0, $bfc0
130 0x8c4201f8, // lw v0, $01f8(v0)
131 0x3c038001, // lui v1, $8001
132 0xac620000, // sw v0, $XXXX(v1)
133 0x3c1d8000, // lui sp, $800X
134 0x27bd0000, // addiu sp, sp, $XXXX
135 0x0c000000, // jal InitializeTLB
136 0x00000000 // nop
138 static u32 InitializeTLBpattern_mask[] = {
139 0xffffffff,
140 0xffffffff,
141 0xffffffff,
142 0xffff0000,
143 0xffffffff,
144 0xffffffff,
145 0xffffffff,
146 0xffff0000,
147 0xfffffff0,
148 0xffff0000,
149 0xfc000000,
150 0xffffffff
153 void (*InitializeTLB)(void);
156 /*----------------------------------------------------------------------------------------*/
157 /* This fonction is call when SifSetDma catch a reboot request. */
158 /*----------------------------------------------------------------------------------------*/
159 u32 New_SifSetDma(SifDmaTransfer_t *sdd, s32 len)
161 // Hook padOpen function to install In Game Reset
162 if( !(g_compat_mask & COMPAT_MODE_6) && padOpen_hooked == 0 )
163 padOpen_hooked = Install_PadOpen_Hook(0x00100000, 0x01ff0000, PADOPEN_HOOK);
165 SifCmdResetData *reset_pkt = (SifCmdResetData*)sdd->src;
167 // does IOP reset
168 New_Reset_Iop(reset_pkt->arg, reset_pkt->flag);
170 return 1;
173 /*----------------------------------------------------------------------------------------*/
174 /* This fonction replace SifSetDma syscall in kernel. */
175 /*----------------------------------------------------------------------------------------*/
177 u32 Hook_SifSetDma(SifDmaTransfer_t *sdd, s32 len)
179 if((sdd->attr == 0x44) && ((sdd->size==0x68) || (sdd->size==0x70))) {
181 SifCmdResetData *reset_pkt = (SifCmdResetData*)sdd->src;
182 if(((reset_pkt->chdr.psize == 0x68) || (reset_pkt->chdr.psize == 0x70)) && (reset_pkt->chdr.fcode == 0x80000003)) {
184 __asm__ __volatile__ (
185 "la $v1, _SifSetDma\n\t"
186 "sw $v1, 8($sp)\n\t"
187 "jr $ra\n\t"
188 "nop\n\t"
192 __asm__ __volatile__ (
193 "move $a0, %1\n\t"
194 "move $a1, %2\n\t"
195 "jr %0\n\t"
196 ::"r"((u32)Old_SifSetDma), "r"((u32)sdd), "r"((u32)len)
199 return 1;
203 /*----------------------------------------------------------------------------------------*/
204 /* This fonction unhook SifSetDma/SifSetReg sycalls */
205 /*----------------------------------------------------------------------------------------*/
207 void Apply_Mode3(void)
209 SetSyscall(__NR_SifSetDma, Old_SifSetDma);
210 SetSyscall(__NR_SifSetReg, Old_SifSetReg);
215 /*----------------------------------------------------------------------------------------*/
216 /* This fonction replace SifSetReg syscall in kernel. */
217 /*----------------------------------------------------------------------------------------*/
219 int Hook_SifSetReg(u32 register_num, int register_value)
221 if(set_reg_hook) {
223 set_reg_hook--;
225 if (set_reg_hook == 0) {
227 if(!DisableDebug)
228 GS_BGCOLOUR = 0x000000;
230 // We should have a mode to do this: this is corresponding to HD-Loader's mode 3
231 if ((g_compat_mask & COMPAT_MODE_3) && (iop_reboot_count == 2)) {
232 __asm__ __volatile__ (
233 "la $v1, Apply_Mode3\n\t"
234 "sw $v1, 8($sp)\n\t"
235 "jr $ra\n\t"
236 "nop\n\t"
240 return 1;
243 __asm__ __volatile__ (
244 "move $a0, %1\n\t"
245 "move $a1, %2\n\t"
246 "jr %0\n\t"
247 ::"r"((u32)Old_SifSetReg), "r"((u32)register_num), "r"((u32)register_value)
250 return 1;
254 // ------------------------------------------------------------------------
255 static void init_systemRestart(void)
257 u32 *ptr;
259 DIntr();
260 ee_kmode_enter();
262 // scan to find kernel InitializeUserMemory()
263 ptr = (u32 *)0x80001000;
264 ptr = find_pattern_with_mask(ptr, 0x7f000, InitializeUserMempattern, InitializeUserMempattern_mask, sizeof(InitializeUserMempattern));
265 if (!ptr)
266 goto err;
267 // keep original opcode address and value
268 g_patchInitializeUserMem_addr = (void *)&ptr[4];
269 g_patchInitializeUserMem_val = ptr[4];
270 // patch InitializeUserMemory() to avoid user mem to be cleared
271 _sw(0x3c100200, (u32)g_patchInitializeUserMem_addr); // it will exit at first s0/a0 comparison
273 // scan to find kernel systemRestart() function
274 ptr = (u32 *)0x80001000;
275 ptr = find_pattern_with_mask(ptr, 0x7f000, systemRestartpattern, systemRestartpattern_mask, sizeof(systemRestartpattern));
276 if (!ptr)
277 goto err;
278 // get systemRestart function pointer
279 systemRestart = (void *)(((ptr[1] & 0x03ffffff) << 2) | 0x80000000);
281 // scan to find kernel InitializeTLB() function
282 ptr = (u32 *)0x80001000;
283 ptr = find_pattern_with_mask(ptr, 0x7f000, InitializeTLBpattern, InitializeTLBpattern_mask, sizeof(InitializeTLBpattern));
284 if (!ptr)
285 goto err;
286 // get InitializeTLB function pointer
287 InitializeTLB = (void *)(((ptr[10] & 0x03ffffff) << 2) | 0x80000000);
289 ee_kmode_exit();
290 EIntr();
292 FlushCache(0);
294 return;
296 err:
297 GS_BGCOLOUR = 0x0000ff; // hangs on red screen
298 while (1) {;}
301 // ------------------------------------------------------------------------
302 static void deinit_systemRestart(void)
304 DIntr();
305 ee_kmode_enter();
307 // unpatch InitializeUserMemory()
308 _sw(g_patchInitializeUserMem_val, (u32)g_patchInitializeUserMem_addr);
310 ee_kmode_exit();
311 EIntr();
313 FlushCache(0);
316 // ------------------------------------------------------------------------
317 void t_loadElf(void)
319 int i, r;
320 t_ExecData elf;
322 DPRINTF("t_loadElf()\n");
324 ResetSPU();
326 SifExitRpc();
328 DPRINTF("t_loadElf: Resetting IOP...\n");
330 set_reg_disabled = 0;
331 New_Reset_Iop("rom0:UDNL rom0:EELOADCNF", 0);
332 set_reg_disabled = 1;
334 iop_reboot_count = 1;
336 SifInitRpc(0);
337 LoadFileInit();
339 DPRINTF("t_loadElf: Loading cddev IOP module...\n");
340 LoadIRXfromKernel(cddev_irx, size_cddev_irx, 0, NULL);
342 strncpy(g_ElfPath, g_argv[0], 1024);
343 g_ElfPath[1023] = 0;
344 DPRINTF("t_loadElf: elf path = '%s'\n", g_ElfPath);
346 // replacing cdrom in elf path by cddev
347 if (_strstr(g_argv[0], "cdrom")) {
348 u8 *ptr = (u8 *)g_argv[0];
349 _strcpy(g_ElfPath, "cddev");
350 _strcat(g_ElfPath, &ptr[5]);
353 DPRINTF("t_loadElf: elf path = '%s'\n", g_ElfPath);
355 DPRINTF("t_loadElf: System Restart...\n");
356 DIntr();
357 ee_kmode_enter();
358 systemRestart();
359 while (!(*(vu32 *)R_EE_SBUS_SMFLAG & SBUS_CTRL_MSINT)) {;}
360 *(vu32 *)R_EE_SBUS_SMFLAG = SBUS_CTRL_MSINT;
361 ee_kmode_exit();
362 EIntr();
364 if(!DisableDebug)
365 GS_BGCOLOUR = 0x00ff00;
367 DPRINTF("t_loadElf: cleaning user memory...");
369 // wipe user memory
370 for (i = 0x00100000; i < 0x02000000; i += 64) {
371 __asm__ __volatile__ (
372 "\tsq $0, 0(%0) \n"
373 "\tsq $0, 16(%0) \n"
374 "\tsq $0, 32(%0) \n"
375 "\tsq $0, 48(%0) \n"
376 :: "r" (i)
379 DPRINTF(" done\n");
381 DPRINTF("t_loadElf: loading elf...");
382 r = LoadElf(g_ElfPath, &elf);
384 if ((!r) && (elf.epc)) {
385 DPRINTF(" done\n");
387 DPRINTF("t_loadElf: exiting services...\n");
388 // exit services
389 fioExit();
390 SifExitIopHeap();
391 LoadFileExit();
392 SifExitRpc();
394 // replacing cddev in elf path by cdrom
395 if (_strstr(g_ElfPath, "cddev"))
396 memcpy(g_ElfPath, "cdrom", 5);
398 DPRINTF("t_loadElf: real elf path = '%s'\n", g_ElfPath);
400 DPRINTF("t_loadElf: trying to apply patches...\n");
401 // applying needed patches
402 apply_patches();
404 FlushCache(0);
405 FlushCache(2);
407 DPRINTF("t_loadElf: executing...\n");
408 ExecPS2((void*)elf.epc, (void*)elf.gp, g_argc, g_argv);
411 DPRINTF(" failed\n");
413 if(!DisableDebug)
414 GS_BGCOLOUR = 0xffffff; // white screen: error
415 SleepThread();
418 // ------------------------------------------------------------------------
420 int Hook_CreateThread(ee_thread_t *thread_param)
422 // Hook padOpen function to install In Game Reset
423 if( padOpen_hooked == 0 && ( thread_param->initial_priority == 0 || (thread_param->initial_priority < 5 && thread_param->current_priority == 0) ) )
424 padOpen_hooked = Install_PadOpen_Hook(0x00100000, 0x01ff0000, PADOPEN_HOOK);
426 return Old_CreateThread(thread_param);
430 // ------------------------------------------------------------------------
432 int Hook_ExecPS2(void *entry, void *gp, int num_args, char *args[])
434 // Hook padOpen function to install In Game Reset
435 if( (u32)entry >= 0x00100000 )
436 padOpen_hooked = Install_PadOpen_Hook( 0x00100000, 0x01ff0000, PADOPEN_HOOK );
438 __asm__ __volatile__ (
439 "move $a0, %1\n\t"
440 "move $a1, %2\n\t"
441 "move $a2, %3\n\t"
442 "move $a3, %4\n\t"
443 "jr %0\n\t"
444 ::"r"((u32)Old_ExecPS2), "r"((u32)entry), "r"((u32)gp), "r"((u32)num_args), "r"((u32)args)
447 return 1;
451 /*----------------------------------------------------------------------------------------*/
452 /* Replace SifSetDma, SifSetReg, LoadExecPS2 syscalls in kernel. (Game Loader) */
453 /* Replace CreateThread and ExecPS2 syscalls in kernel. (In Game Reset) */
454 /*----------------------------------------------------------------------------------------*/
455 void Install_Kernel_Hooks(void)
457 init_systemRestart();
459 Old_SifSetDma = GetSyscallHandler(__NR_SifSetDma);
460 SetSyscall(__NR_SifSetDma, &Hook_SifSetDma);
462 Old_SifSetReg = GetSyscallHandler(__NR_SifSetReg);
463 SetSyscall(__NR_SifSetReg, &Hook_SifSetReg);
465 Old_LoadExecPS2 = GetSyscallHandler(__NR_LoadExecPS2);
466 SetSyscall(__NR_LoadExecPS2, &Hook_LoadExecPS2);
468 // If IGR is enabled hook ExecPS2 & CreateThread syscalls
469 if(!(g_compat_mask & COMPAT_MODE_6))
471 Old_CreateThread = GetSyscallHandler(__NR_CreateThread);
472 SetSyscall(__NR_CreateThread, &Hook_CreateThread);
474 Old_ExecPS2 = GetSyscallHandler(__NR_ExecPS2);
475 SetSyscall(__NR_ExecPS2, &Hook_ExecPS2);
479 /*----------------------------------------------------------------------------------------*/
480 /* Restore original SifSetDma, SifSetReg, LoadExecPS2 syscalls in kernel. (Game loader) */
481 /* Restore original CreateThread and ExecPS2 syscalls in kernel. (In Game Reset) */
482 /*----------------------------------------------------------------------------------------*/
483 void Remove_Kernel_Hooks(void)
485 deinit_systemRestart();
487 SetSyscall(__NR_SifSetDma, Old_SifSetDma);
488 SetSyscall(__NR_SifSetReg, Old_SifSetReg);
489 SetSyscall(__NR_LoadExecPS2, Old_LoadExecPS2);
491 // If IGR is enabled unhook ExecPS2 & CreateThread syscalls
492 if(!(g_compat_mask & COMPAT_MODE_6))
494 SetSyscall(__NR_CreateThread, Old_CreateThread);
495 SetSyscall(__NR_ExecPS2, Old_ExecPS2);