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>
25 #include "padpatterns.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
;
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)));
48 // Shutdown Dev9 hardware
49 static void Shutdown_Dev9()
56 // Get dev9 hardware type
57 dev9_hw_type
= *DEV9_R_146E
& 0xf0;
60 if ( dev9_hw_type
== 0x20 )
65 // Shutdown Expansion Bay
66 else if ( dev9_hw_type
== 0x30 )
70 *DEV9_R_1460
= *DEV9_R_1464
;
71 *DEV9_R_146C
= *DEV9_R_146C
& ~4;
72 *DEV9_R_1460
= *DEV9_R_146C
& ~1;
82 // Return to PS2 Browser
83 static void Go_Browser(void)
85 // Shutdown Dev9 hardware
89 // FlushCache before exiting
102 static void t_loadElf(void)
109 GS_BGCOLOUR
= 0x80FF00; // Blue Green
115 GS_BGCOLOUR
= 0x000080; // Dark Red
117 // Reset IO Processor
118 while (!Reset_Iop("rom0:UDNL rom0:EELOADCNF", 0)) {;}
119 while (!Sync_Iop()){;}
122 GS_BGCOLOUR
= 0xFF80FF; // Pink
131 GS_BGCOLOUR
= 0xFF8000; // Blue sky
133 // Load basic modules
134 LoadModule("rom0:SIO2MAN", 0, NULL
);
135 LoadModule("rom0:MCMAN", 0, NULL
);
142 ret
= LoadElf(argv
[0], &elf
);
144 if (!ret
&& elf
.epc
) {
156 GS_BGCOLOUR
= 0x0080FF; // Orange
159 ExecPS2((void*)elf
.epc
, (void*)elf
.gp
, 1, argv
);
164 GS_BGCOLOUR
= 0x0000FF; // Red
168 // Return to PS2 Browser
172 // Poweroff PlayStation 2
173 static void PowerOff_PS2(void)
175 // Shutdown Dev9 hardware
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
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
)
204 GS_BGCOLOUR
= 0xFFFFFF; // White
211 GS_BGCOLOUR
= 0x800000; // Dark Blue
213 // Remove kernel hook
214 Remove_Kernel_Hooks();
217 GS_BGCOLOUR
= 0x008000; // Dark Green
219 // Reset Data Decompression Vector Unit 0 & 1
223 GS_BGCOLOUR
= 0x800080; // Purple
225 // Reset SPU Sound processor
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);
237 if(Cop0_Index
!= 0x26)
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__(
263 GS_BGCOLOUR
= 0x00FFFF; // Yellow
274 // Execute home loader
275 if (ExitPath
[0] != '\0')
276 ExecPS2(t_loadElf
, &_gp
, 0, NULL
);
278 // Return to PS2 Browser
282 // If combo is R3 + L3 or Reset failed, 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
)
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
)
305 Pad_Data
.prev_frame
= Pad_Data
.pad_buf
[Pad_Data
.pos_frame
];
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
];
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
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
346 Pad_Data
.combo_type
= IGR_COMBO_START_SELECT
; // power button press 2 time, so reset
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");
377 iWakeupThread(IGR_Thread_ID
);
378 iChangeThreadPriority( i
, 0 );
382 // Suspend all threads
384 iChangeThreadPriority( i
, 127 );
390 __asm__
__volatile__(
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;
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
)
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
);
468 // Hook function for libpad2 scePad2CreateSocket
469 static int Hook_scePad2CreateSocket( pad2socketparam_t
*SocketParam
, void *addr
)
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
);
487 // This function patch the padOpen calls. (scePadPortOpen or scePad2CreateSocket)
488 int Install_PadOpen_Hook(u32 mem_start
, u32 mem_end
, int mode
)
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 }
509 // Loop for each libpad version
510 for(i
= 0; i
< NB_PADOPEN_PATTERN
; i
++)
512 ptr
= (u32
*)mem_start
;
515 // Purple while PadOpen pattern search
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
);
525 DPRINTF("IGR: found padopen pattern%d at 0x%08x mode=%d\n", i
, (int)ptr
, mode
);
528 // Green while PadOpen patches
530 GS_BGCOLOUR
= 0x008000;
532 // Save original PadOpen function
533 if (padopen_patterns
[i
].version
== IGR_LIBPAD_V1
)
534 scePadPortOpen
= (void *)ptr
;
536 scePad2CreateSocket
= (void *)ptr
;
538 if(mode
== PADOPEN_HOOK
)
540 // Retrieve PadOpen call Instruction code
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)
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;
555 mem_size2
= 0x01ff0000 - (u32
)ptr2
;
557 ptr2
= find_pattern_with_mask(ptr2
, mem_size2
, pattern
, mask
, sizeof(pattern
));
560 DPRINTF("IGR: found padOpen call at 0x%08x\n", (int)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);
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
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;
599 mem_size2
= 0x01ff0000 - (u32
)ptr2
;
601 ptr2
= find_pattern_with_mask(ptr2
, mem_size2
, pattern
, mask
, sizeof(pattern
));
604 DPRINTF("IGR: found padOpen call at 0x%08x\n", (int)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
;
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
627 DPRINTF("IGR: no hooking requested, breaking loop...\n");
628 // Hooking is not required and padOpen function was found, so stop searching
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");
647 GS_BGCOLOUR
= 0x000000;