Hey Hominem ... don't commit shit you used for trying to reproduce some bug ;)
[open-ps2-loader/simon.git] / ee_core / src / padhook.c
blob96472c6d34cd2b1933108952b5df181e713cc691
1 /*
2 padhook.c Open PS2 Loader In Game Reset
4 Copyright 2009-2010, Ifcaro, jimmikaelkael & Polo
5 Copyright 2006-2008 Polo
6 Licenced under Academic Free License version 3.0
7 Review OpenUsbLd README & LICENSE files for further details.
9 Reset SPU function taken from PS2SDK freesd.
10 Copyright (c) 2004 TyRaNiD <tiraniddo@hotmail.com>
11 Copyright (c) 2004,2007 Lukasz Bruun <mail@lukasz.dk>
13 PadOpen Hooking function inspired from ps2rd.
14 Hook scePadPortOpen/scePad2CreateSocket instead of scePadRead/scePad2Read
15 Copyright (C) 2009 jimmikaelkael <jimmikaelkael@wanadoo.fr>
16 Copyright (C) 2009 misfire <misfire@xploderfreax.de>
19 #include "ee_core.h"
20 #include "iopmgr.h"
21 #include "modmgr.h"
22 #include "util.h"
23 #include "spu.h"
24 #include "padhook.h"
25 #include "padpatterns.h"
26 #include "syshook.h"
28 /* scePadPortOpen & scePad2CreateSocket prototypes */
29 static int (*scePadPortOpen)( int port, int slot, void *addr );
30 static int (*scePad2CreateSocket)( pad2socketparam_t *SocketParam, void *addr );
32 /* Monitored pad data */
33 static paddata_t Pad_Data;
35 /* Monitored power button data */
36 static powerbuttondata_t Power_Button;
38 /* IGR Thread ID */
39 static int IGR_Thread_ID = -1;
41 /* IGR thread stack & stack size */
42 #define IGR_STACK_SIZE (16 * 512)
43 static u8 IGR_Stack[IGR_STACK_SIZE] __attribute__ ((aligned(16)));
45 /* Extern symbol */
46 extern void *_gp;
48 // Shutdown Dev9 hardware
49 static void Shutdown_Dev9()
51 u16 dev9_hw_type;
53 DIntr();
54 ee_kmode_enter();
56 // Get dev9 hardware type
57 dev9_hw_type = *DEV9_R_146E & 0xf0;
59 // Shutdown Pcmcia
60 if ( dev9_hw_type == 0x20 )
62 *DEV9_R_146C = 0;
63 *DEV9_R_1474 = 0;
65 // Shutdown Expansion Bay
66 else if ( dev9_hw_type == 0x30 )
68 *DEV9_R_1466 = 1;
69 *DEV9_R_1464 = 0;
70 *DEV9_R_1460 = *DEV9_R_1464;
71 *DEV9_R_146C = *DEV9_R_146C & ~4;
72 *DEV9_R_1460 = *DEV9_R_146C & ~1;
75 //Wait a sec
76 delay(5);
78 ee_kmode_exit();
79 EIntr();
82 // Return to PS2 Browser
83 static void Go_Browser(void)
85 // Shutdown Dev9 hardware
86 if (HDDSpindown)
87 Shutdown_Dev9();
89 // FlushCache before exiting
90 FlushCache(0);
91 FlushCache(2);
93 // Exit to PS2Browser
94 __asm__ __volatile__(
95 " li $3, 0x04;"
96 " syscall;"
97 " nop;"
101 // Load home ELF
102 static void t_loadElf(void)
104 int ret;
105 char *argv[2];
106 t_ExecData elf;
108 if(!DisableDebug)
109 GS_BGCOLOUR = 0x80FF00; // Blue Green
111 // Init RPC & CMD
112 SifInitRpc(0);
114 if(!DisableDebug)
115 GS_BGCOLOUR = 0x000080; // Dark Red
117 // Reset IO Processor
118 while (!Reset_Iop("rom0:UDNL rom0:EELOADCNF", 0)) {;}
119 while (!Sync_Iop()){;}
121 if(!DisableDebug)
122 GS_BGCOLOUR = 0xFF80FF; // Pink
124 // Init RPC & CMD
125 SifInitRpc(0);
127 // Apply Sbv patches
128 Sbv_Patch();
130 if(!DisableDebug)
131 GS_BGCOLOUR = 0xFF8000; // Blue sky
133 // Load basic modules
134 LoadModule("rom0:SIO2MAN", 0, NULL);
135 LoadModule("rom0:MCMAN", 0, NULL);
137 // Load exit ELF
138 argv[0] = ExitPath;
140 argv[1] = NULL;
142 ret = LoadElf(argv[0], &elf);
144 if (!ret && elf.epc) {
146 // Exit services
147 fioExit();
148 LoadFileExit();
149 SifExitIopHeap();
150 SifExitRpc();
152 FlushCache(0);
153 FlushCache(2);
155 if(!DisableDebug)
156 GS_BGCOLOUR = 0x0080FF; // Orange
158 // Execute BOOT.ELF
159 ExecPS2((void*)elf.epc, (void*)elf.gp, 1, argv);
162 if(!DisableDebug)
164 GS_BGCOLOUR = 0x0000FF; // Red
165 delay(5);
168 // Return to PS2 Browser
169 Go_Browser();
172 // Poweroff PlayStation 2
173 static void PowerOff_PS2(void)
175 // Shutdown Dev9 hardware
176 Shutdown_Dev9();
178 DIntr();
179 ee_kmode_enter();
181 // PowerOff PS2
182 *CDVD_R_SDIN = 0x00;
183 *CDVD_R_SCMD = 0x0F;
185 ee_kmode_exit();
186 EIntr();
189 // In Game Reset Thread
190 static void IGR_Thread(void *arg)
192 u32 Cop0_Index, Cop0_Perf;
194 // Place our IGR thread in WAIT state
195 // It will be woken up by our IGR interrupt handler
196 SleepThread();
198 DPRINTF("IGR thread woken up!\n");
200 // If Pad Combo is Start + Select then Return to Home
201 if(Pad_Data.combo_type == IGR_COMBO_START_SELECT)
203 if(!DisableDebug)
204 GS_BGCOLOUR = 0xFFFFFF; // White
206 // Re-Init RPC & CMD
207 SifExitRpc();
208 SifInitRpc(0);
210 if(!DisableDebug)
211 GS_BGCOLOUR = 0x800000; // Dark Blue
213 // Remove kernel hook
214 Remove_Kernel_Hooks();
216 if(!DisableDebug)
217 GS_BGCOLOUR = 0x008000; // Dark Green
219 // Reset Data Decompression Vector Unit 0 & 1
220 ResetEE(0x04);
222 if(!DisableDebug)
223 GS_BGCOLOUR = 0x800080; // Purple
225 // Reset SPU Sound processor
226 ResetSPU();
228 if(!DisableDebug)
229 GS_BGCOLOUR = 0x0000FF; // Red
231 // Check Translation Look-Aside Buffer
232 // Some game (GT4, GTA) modify memory map
233 // A re-init is needed to properly access memory
234 Cop0_Index = GetCop0(0);
236 // Init TLB
237 if(Cop0_Index != 0x26)
239 ee_kmode_enter();
240 InitializeTLB();
241 ee_kmode_exit();
244 // Check Performance Counter
245 // Some game (GT4) start performance counter
246 // When counter overflow, an exception occur, so stop them
247 Cop0_Perf = GetCop0(25);
249 // Stop Performance Counter
250 if(Cop0_Perf & 0x80000000)
252 __asm__ __volatile__(
253 " mfc0 $3, $25;"
254 " lui $2, 0x8000;"
255 " or $3, $3, $2;"
256 " xor $3, $3, $2;"
257 " mtc0 $3, $25;"
258 " sync.p;"
262 if(!DisableDebug)
263 GS_BGCOLOUR = 0x00FFFF; // Yellow
265 // Exit services
266 fioExit();
267 LoadFileExit();
268 SifExitIopHeap();
269 SifExitRpc();
271 FlushCache(0);
272 FlushCache(2);
274 // Execute home loader
275 if (ExitPath[0] != '\0')
276 ExecPS2(t_loadElf, &_gp, 0, NULL);
278 // Return to PS2 Browser
279 Go_Browser();
282 // If combo is R3 + L3 or Reset failed, Poweroff PS2
283 PowerOff_PS2();
286 // IGR VBLANK_END interrupt handler install to monitor combo trick in pad data aera
287 static int IGR_Intc_Handler(int cause)
289 int i;
291 // Write back the D-cache contents to update Pad Buffer
292 iSyncDCache(Pad_Data.pad_buf, Pad_Data.pad_buf + 256);
294 // First check pad state
295 if ( ( (Pad_Data.libpad == IGR_LIBPAD_V1) && (Pad_Data.pad_buf[Pad_Data.pos_state] == IGR_PAD_STABLE_V1) ) ||
296 ( (Pad_Data.libpad == IGR_LIBPAD_V2) && (Pad_Data.pad_buf[Pad_Data.pos_state] == IGR_PAD_STABLE_V2) ) )
298 // Check if pad buffer is still alive with pad data frame counter
299 // If pad frame change save it, otherwise tell to syshook to re-install padOpen hook
300 if( Pad_Data.vb_count++ >= 10)
302 if(Pad_Data.pad_buf[Pad_Data.pos_frame] != Pad_Data.prev_frame)
304 padOpen_hooked = 1;
305 Pad_Data.prev_frame = Pad_Data.pad_buf[Pad_Data.pos_frame];
307 else
309 padOpen_hooked = 0;
311 Pad_Data.vb_count = 0;
314 // Combo R1 + L1 + R2 + L2
315 if ( Pad_Data.pad_buf[Pad_Data.pos_combo1] == IGR_COMBO_R1_L1_R2_L2 )
317 // Combo Start + Select OR R3 + L3
318 if ( ( Pad_Data.pad_buf[Pad_Data.pos_combo2] == IGR_COMBO_START_SELECT ) || // Start + Select combo, so reset
319 ( Pad_Data.pad_buf[Pad_Data.pos_combo2] == IGR_COMBO_R3_L3 ) ) // R3 + L3 combo, so poweroff
320 Pad_Data.combo_type = Pad_Data.pad_buf[Pad_Data.pos_combo2];
324 ee_kmode_enter();
326 // Check power button press
327 if ( (*CDVD_R_NDIN & 0x20) && (*CDVD_R_POFF & 0x04) )
329 // Increment button press counter
330 Power_Button.press++;
332 // Cancel poweroff to catch the second button press
333 *CDVD_R_SDIN = 0x00;
334 *CDVD_R_SCMD = 0x1B;
337 // Start VBlank counter when power button is pressed
338 if( Power_Button.press )
340 // Check number of power button press after 1 ~ sec
341 if( Power_Button.vb_count++ >= 50 )
343 if( Power_Button.press == 1 )
344 Pad_Data.combo_type = IGR_COMBO_R3_L3; // power button press 1 time, so poweroff
345 else
346 Pad_Data.combo_type = IGR_COMBO_START_SELECT; // power button press 2 time, so reset
350 ee_kmode_exit();
352 // If power button or combo is press
353 // Disable all interrupts (not SBUS, TIMER2, TIMER3 use by kernel)
354 // Suspend and Change priority of all threads other then our IGR thread
355 // Wakeup and Change priority of our IGR thread
356 if ( Pad_Data.combo_type != 0x00 )
358 // Disable Interrupts
359 iDisableIntc(kINTC_GS );
360 iDisableIntc(kINTC_VBLANK_START);
361 iDisableIntc(kINTC_VBLANK_END );
362 iDisableIntc(kINTC_VIF0 );
363 iDisableIntc(kINTC_VIF1 );
364 iDisableIntc(kINTC_VU0 );
365 iDisableIntc(kINTC_VU1 );
366 iDisableIntc(kINTC_IPU );
367 iDisableIntc(kINTC_TIMER0 );
368 iDisableIntc(kINTC_TIMER1 );
370 // Loop for each threads
371 for(i = 3; i < 256; i++)
373 if(i == IGR_Thread_ID )
375 DPRINTF("IGR: trying to wake IGR thread...\n");
376 // WakeUp IGR thread
377 iWakeupThread(IGR_Thread_ID);
378 iChangeThreadPriority( i, 0 );
380 else
382 // Suspend all threads
383 iSuspendThread( i );
384 iChangeThreadPriority( i, 127 );
389 // Exit handler
390 __asm__ __volatile__(
391 " sync.l;"
392 " ei;"
395 return 0;
398 // Install IGR thread, and Pad interrupt handler
399 static void Install_IGR(void *addr, int libpad)
401 ee_thread_t thread_param;
403 // Reset power button data
404 Power_Button.press = 0;
405 Power_Button.vb_count = 0;
407 // Init Pad_Data informations
408 Pad_Data.vb_count = 0;
409 Pad_Data.libpad = libpad;
410 Pad_Data.pad_buf = addr;
411 Pad_Data.combo_type = 0x00;
412 Pad_Data.prev_frame = 0x00;
414 // Set positions of pad data and pad state in buffer
415 if(libpad == IGR_LIBPAD_V1)
417 Pad_Data.pos_combo1 = 3;
418 Pad_Data.pos_combo2 = 2;
419 Pad_Data.pos_state = 112;
420 Pad_Data.pos_frame = 88;
422 else
424 Pad_Data.pos_combo1 = 29;
425 Pad_Data.pos_combo2 = 28;
426 Pad_Data.pos_state = 4;
427 Pad_Data.pos_frame = 124;
430 // Create and start IGR thread
431 thread_param.gp_reg = &_gp;
432 thread_param.func = IGR_Thread;
433 thread_param.stack = (void*)IGR_Stack;
434 thread_param.stack_size = IGR_STACK_SIZE;
435 thread_param.initial_priority = 127;
436 IGR_Thread_ID = CreateThread(&thread_param);
438 StartThread(IGR_Thread_ID, NULL);
440 // Create IGR interrupt handler
441 AddIntcHandler(kINTC_VBLANK_END, IGR_Intc_Handler, 0);
442 EnableIntc(kINTC_VBLANK_END);
445 // Hook function for libpad scePadPortOpen
446 static int Hook_scePadPortOpen( int port, int slot, void* addr )
448 int ret;
450 // Make sure scePadPortOpen function is still available
451 if(port == 0 && slot == 0) {
452 DPRINTF("IGR: Hook_scePadPortOpen - padOpen hooking check...\n");
453 Install_PadOpen_Hook(0x00100000, 0x01ff0000, PADOPEN_CHECK);
456 // Call original scePadPortOpen function
457 ret = scePadPortOpen(port, slot, addr);
459 // Install IGR with libpad1 parameters
460 if(port == 0 && slot == 0) {
461 DPRINTF("IGR: Hook_scePadPortOpen - installing IGR...\n");
462 Install_IGR(addr, IGR_LIBPAD_V1);
465 return ret;
468 // Hook function for libpad2 scePad2CreateSocket
469 static int Hook_scePad2CreateSocket( pad2socketparam_t *SocketParam, void *addr )
471 int ret;
473 // Make sure scePad2CreateSocket function is still available
474 if(SocketParam->port == 0 && SocketParam->slot == 0)
475 Install_PadOpen_Hook(0x00100000, 0x01ff0000, PADOPEN_CHECK);
477 // Call original scePad2CreateSocket function
478 ret = scePad2CreateSocket( SocketParam, addr );
480 // Install IGR with libpad2 parameters
481 if(SocketParam->port == 0 && SocketParam->slot == 0)
482 Install_IGR(addr, IGR_LIBPAD_V2);
484 return ret;
487 // This function patch the padOpen calls. (scePadPortOpen or scePad2CreateSocket)
488 int Install_PadOpen_Hook(u32 mem_start, u32 mem_end, int mode)
490 u32 *ptr, *ptr2;
491 u32 inst, fncall;
492 u32 mem_size, mem_size2;
493 u32 pattern[1], mask[1];
494 int i, found, patched;
496 pattern_t padopen_patterns[NB_PADOPEN_PATTERN] = {
497 { padPortOpenpattern0 , padPortOpenpattern0_mask , sizeof(padPortOpenpattern0) , 1 },
498 { pad2CreateSocketpattern0, pad2CreateSocketpattern0_mask, sizeof(pad2CreateSocketpattern0), 2 },
499 { pad2CreateSocketpattern1, pad2CreateSocketpattern1_mask, sizeof(pad2CreateSocketpattern1), 2 },
500 { pad2CreateSocketpattern2, pad2CreateSocketpattern2_mask, sizeof(pad2CreateSocketpattern2), 2 },
501 { padPortOpenpattern1 , padPortOpenpattern1_mask , sizeof(padPortOpenpattern1) , 1 },
502 { padPortOpenpattern2 , padPortOpenpattern2_mask , sizeof(padPortOpenpattern2) , 1 },
503 { padPortOpenpattern3 , padPortOpenpattern3_mask , sizeof(padPortOpenpattern3) , 1 }
506 found = 0;
507 patched = 0;
509 // Loop for each libpad version
510 for(i = 0; i < NB_PADOPEN_PATTERN; i++)
512 ptr = (u32 *)mem_start;
513 while (ptr)
515 // Purple while PadOpen pattern search
516 if(!DisableDebug)
517 GS_BGCOLOUR = 0x800080;
519 mem_size = mem_end - (u32)ptr;
521 // First try to locate the orginal libpad's PadOpen function
522 ptr = find_pattern_with_mask(ptr, mem_size, padopen_patterns[i].pattern, padopen_patterns[i].mask, padopen_patterns[i].size);
523 if (ptr)
525 DPRINTF("IGR: found padopen pattern%d at 0x%08x mode=%d\n", i, (int)ptr, mode);
526 found = 1;
528 // Green while PadOpen patches
529 if(!DisableDebug)
530 GS_BGCOLOUR = 0x008000;
532 // Save original PadOpen function
533 if (padopen_patterns[i].version == IGR_LIBPAD_V1)
534 scePadPortOpen = (void *)ptr;
535 else
536 scePad2CreateSocket = (void *)ptr;
538 if(mode == PADOPEN_HOOK)
540 // Retrieve PadOpen call Instruction code
541 inst = 0x00000000;
542 inst |= 0x03ffffff & ((u32)ptr >> 2);
544 // Make pattern with function call code saved above
545 // Ignore bits 24-27 because Jump type can be J(8) or JAL(C)
546 pattern[0] = inst;
547 mask[0] = 0xf0ffffff;
549 DPRINTF("IGR: searching opcode %08x witk mask %08x\n", (int)pattern[0], (int)mask[0]);
551 // Search & patch for calls to PadOpen
552 ptr2 = (u32 *)0x00100000;
553 while (ptr2)
555 mem_size2 = 0x01ff0000 - (u32)ptr2;
557 ptr2 = find_pattern_with_mask(ptr2, mem_size2, pattern, mask, sizeof(pattern));
558 if (ptr2)
560 DPRINTF("IGR: found padOpen call at 0x%08x\n", (int)ptr2);
562 patched = 1;
564 fncall = (u32)ptr2;
566 // Get PadOpen call Jump Instruction type. (JAL or J)
567 inst = (ptr2[0] & 0x0f000000);
569 // Get Hook_PadOpen call Instruction code
570 if (padopen_patterns[i].version == IGR_LIBPAD_V1) {
571 DPRINTF("IGR: Hook_scePadPortOpen addr 0x%08x\n", (int)Hook_scePadPortOpen);
572 inst |= 0x03ffffff & ((u32)Hook_scePadPortOpen >> 2);
574 else {
575 DPRINTF("IGR: Hook_scePad2CreateSocket addr 0x%08x\n", (int)Hook_scePad2CreateSocket);
576 inst |= 0x03ffffff & ((u32)Hook_scePad2CreateSocket >> 2);
579 DPRINTF("IGR: patching padopen call at addr 0x%08x with opcode %08x\n", (int)fncall, (int)inst);
580 // Overwrite the original PadOpen function call with our function call
581 _sw(inst, fncall);
585 if(!patched)
587 DPRINTF("IGR: 2nd padOpen patch attempt...\n");
589 // Make pattern with function address saved above
590 pattern[0] = (u32)ptr;
591 mask[0] = 0xffffffff;
593 DPRINTF("IGR: searching opcode %08x witk mask %08x\n", (int)pattern[0], (int)mask[0]);
595 // Search & patch for PadOpen function address
596 ptr2 = (u32 *)0x00100000;
597 while (ptr2)
599 mem_size2 = 0x01ff0000 - (u32)ptr2;
601 ptr2 = find_pattern_with_mask(ptr2, mem_size2, pattern, mask, sizeof(pattern));
602 if (ptr2)
604 DPRINTF("IGR: found padOpen call at 0x%08x\n", (int)ptr2);
606 patched = 1;
608 fncall = (u32)ptr2;
610 // Get Hook_PadOpen function address
611 if (padopen_patterns[i].version == IGR_LIBPAD_V1) {
612 DPRINTF("IGR: Hook_scePadPortOpen addr 0x%08x\n", (int)Hook_scePadPortOpen);
613 inst = (u32)Hook_scePadPortOpen;
615 else {
616 DPRINTF("IGR: Hook_scePad2CreateSocket addr 0x%08x\n", (int)Hook_scePad2CreateSocket);
617 inst = (u32)Hook_scePad2CreateSocket;
620 DPRINTF("IGR: patching padopen call at addr 0x%08x with opcode %08x\n", (int)fncall, (int)inst);
621 // Overwrite the original PadOpen function address with our function address
622 _sw(inst, fncall);
626 }else {
627 DPRINTF("IGR: no hooking requested, breaking loop...\n");
628 // Hooking is not required and padOpen function was found, so stop searching
629 break;
632 // Increment search pointer
633 //ptr += padopen_patterns[i].size;
634 ptr += (padopen_patterns[i].size >> 2);
638 // If a padOpen function call was patched or ( hooking is not required and a padOpen function was found ), so stop the libpad version search loop
639 if( patched == 1 || (mode == PADOPEN_CHECK && found == 1) ) {
640 DPRINTF("IGR: job done exiting...\n");
641 break;
645 // Black, done
646 if(!DisableDebug)
647 GS_BGCOLOUR = 0x000000;
649 return patched;