Suggestion from "mgh".
[open-ps2-loader.git] / ee_core / src / asm.S
blob540498e9fed548e5047f9bc6bb0455e6c57fa7ee
1 /*
2   Copyright 2010, jimmikaelkael <jimmikaelkael@wanadoo.fr>
3   Licenced under Academic Free License version 3.0
4   Review Open PS2 Loader README & LICENSE files for further details.
6   The goal of the code in this file is to force syscall hooks to use
7   an alternate stack when they need to use stack.  
8 */
10 #include <ee_cop0_defs.h>
11 #include <syscallnr.h>
13 #define MAX_ARGS        15
14 #define ARGBUF_SIZE     580
16 #define COMPAT_MODE_3   0x04
18 #define PADOPEN_HOOK  0
21         .set push
22         .set noreorder
23         .set noat
26 /**************************************************************************
27  *
28  * .text section
29  *
30  **************************************************************************/
32         .text
34         /* libkernel */
35         .extern memset
36         .extern memcpy
37         .extern strlen
38         .extern strncpy
40         /* syshook.c */
41         .extern g_argc
42         .extern g_argv
43         .extern t_loadElf
44         .extern set_reg_hook
45         .extern iop_reboot_count
46         .extern New_SifSetDma
47         .extern Old_SifSetDma
48         .extern Old_SifSetReg
49         .extern padOpen_hooked
50         .extern Old_ExecPS2
51         .extern Old_CreateThread
53         /* loader.h */
54         .extern g_compat_mask
55         .extern DisableDebug
57         /* padhook.c */
58         .extern Install_PadOpen_Hook
60         .globl  g_argbuf
61         .globl  Hook_LoadExecPS2
62         .globl  Hook_SifSetDma
63         .globl  Hook_SifSetReg
64         .globl  Hook_ExecPS2
65         .globl  Hook_CreateThread
69  * _LoadExecPS2: this function preserves args and change stack pointer
70  * before to execute t_loadElf
71  */
72         .ent    _LoadExecPS2
73 _LoadExecPS2:
75         /* save args, not needed to preserve sX/ra registers values as we won't return */
76         daddu   $s0, $a0, $zero /* ELF path     */
77         daddu   $s1, $a1, $zero /* argc         */
78         daddu   $s2, $a2, $zero /* argv         */
80         /* dark blue BG color */
81         lui     $v0, 0x1200
82         ori     $v0, $v0, 0x00e0
83         lui     $v1, 0x0040
84         sd      $v1, 0x0000($v0)
86         /* disable Intr */
87         mfc0    $v1, EE_COP0_Status
88         lui     $v0, 0x0010
89         and     $v1, $v1, $v0
90         daddu   $a0, $zero, $zero
91         beq     $v1, $zero, 2f
92         nop
94         di
95         sync.p
96         mfc0    $v1, EE_COP0_Status
97         nop     
98         and     $v1, $v1, $v0
99         nop
100         bne     $v1, $zero, 1b
101         nop
103         /* entering Kernel mode */
104         mfc0    $v0, EE_COP0_Status
105         lui     $v1, 0xffff
106         ori     $v1, $v1, 0xffe7
107         and     $v0, $v0, $v1
108         mtc0    $v0, EE_COP0_Status
109         sync.p
111         /* set g_argc to arg count , or MAX_ARGS if greater */
112         slti    $v0, $s1, MAX_ARGS+1
113         addiu   $v1, $zero, MAX_ARGS
114         movn    $v1, $s1, $v0
115         la      $v0, g_argc
116         sw      $v1, 0x0000($v0)
118         /* pointer to g_argbuf */
119         la      $s3, g_argbuf
121         /* clear g_argbuf */
122         daddu   $a0, $s3, $zero
123         daddu   $a1, $zero, $zero
124         jal     memset
125         addiu   $a2, $zero, ARGBUF_SIZE
127         /* copy elfname to argv[0] */
128         daddu   $a0, $s3, $zero
129         daddu   $a1, $s0, $zero
130         jal     strncpy
131         addiu   $a2, $zero, ARGBUF_SIZE
133         /* set g_argv[0] to g_argbuf */
134         la      $v0, g_argv
135         sw      $s3, 0x0000($v0)
137         /* increment arg buffer pointer */
138         jal     strlen
139         daddu   $a0, $s0, $zero
140         addiu   $v0, $v0, 1
141         daddu   $s3, $s3, $v0
143         /* increment g_argc */
144         la      $v1, g_argc
145         lw      $v0, 0x0000($v1)
146         daddu   $s4, $v0, $zero /* g_argc(-1) */
147         addiu   $v0, $v0, 1
148         sw      $v0, 0x0000($v1)
150         /* copy args from main ELF to args buffer */
151         blez    $s4, 4f
152         daddu   $s5, $zero, $zero /* counter */
154         /* get arg len and increment it */
155         daddu   $a0, $s2, $zero
156         sll     $v0, $s5, 2
157         daddu   $a0, $a0, $v0
158         jal     strlen
159         lw      $a0, 0x0000($a0)
160         addiu   $s6, $v0, 1 /* arg len */
162         /* copy arg to main args buffer */
163         daddu   $a0, $s3, $zero
164         daddu   $a1, $s2, $zero
165         sll     $v0, $s5, 2
166         daddu   $a1, $a1, $v0
167         lw      $a1, 0x0000($a1)
168         jal     memcpy
169         daddu   $a2, $s6, $zero
171         /* store arg pointer to g_argv[counter+1] */
172         la      $v0, g_argv
173         sll     $v1, $s5, 2
174         daddu   $v0, $v0, $v1
175         sw      $s3, 0x0004($v0)
177         /* increment arg buffer pointer with arg len + 1 */
178         daddu   $s3, $s3, $s6
180         /* loop on every args */
181         addiu   $s5, $s5, 1
182         slt     $v1, $s5, $s4
183         bne     $v1, $zero, 3b
184         nop
186         /* exiting Kernel mode */
187         mfc0    $v0, EE_COP0_Status
188         ori     $v0, $v0, 0x0010
189         mtc0    $v0, EE_COP0_Status
190         sync.p
192         /* enable Intr */
193         ei
195         /* FlushCache */
196         daddu   $a0, $zero, $zero
197         addiu   $v1, $zero, __NR_FlushCache
198         syscall
199         addiu   $a0, $zero, 2
200         addiu   $v1, $zero, __NR_FlushCache
201         syscall
203         /* change stack pointer to top of user memory */
204         lui     $v0, 0x0200
205         daddu   $sp, $v0, $zero
207         /*
208          * ExecPS2() does the following for us:
209          * - do a soft EE peripheral reset
210          * - terminate all threads and delete all semaphores
211          * - set up ELF loader thread and run it
212          */
213         la      $a0, t_loadElf
214         daddu   $a1, $zero, $zero
215         daddu   $a2, $zero, $zero
216         daddu   $a3, $zero, $zero
217         addiu   $v1, $zero, __NR_ExecPS2
218         syscall
219         nop
221         .end    _LoadExecPS2
224  * Hook_LoadExecPS2: exit syscall to _LoadExecPS2
225  */
226         .ent    Hook_LoadExecPS2
227 Hook_LoadExecPS2:
229         /* exit syscall to _LoadExecPS2 */
230         la $v1, _LoadExecPS2
231         sw $v1, 8($sp)
232         jr $ra
233         nop
235         .end    Hook_LoadExecPS2
238  * _SifSetDma: function designed to use our own stack during IOP reboot trap
239  */
240         .ent    _SifSetDma
241 _SifSetDma:
243         /* save original stack pointer */
244         daddu   $a2, $sp, $zero
246 #ifdef LOAD_EECORE_DOWN
247         lui     $v0, 0x0009
248         /* ori  $v0, $v0, 0x0000 */
249 #else
250         lui     $v0, 0x000e
251         ori     $v0, $v0, 0x7000
252 #endif
253         /* change the stack pointer */
254         daddu   $sp, $v0, $zero
256         /* call New_SifSetDma, preserving ra and a2 registers values */
257         addiu   $sp, $sp, -0x10
258         sd      $ra, 0x0000($sp)
259         jal     New_SifSetDma
260         sd      $a2, 0x0008($sp)
262         /* restore a2 and ra registers */ 
263         ld      $a2, 0x0008($sp)
264         ld      $ra, 0x0000($sp)
266         /* restore the original stack pointer */
267         daddu   $sp, $a2, $zero
269 #ifdef LOAD_EECORE_DOWN
270         lui     $v0, 0x000b
271         lui     $v1, 0x000d
272 #else
273         lui     $v0, 0x0008
274         ori     $v0, $v0, 0x8000
275         lui     $v1, 0x000e
276         ori     $v1, $v1, 0x7000
277 #endif
278 1:      
279         sq      $zero, 0x0000($v0)
280         sq      $zero, 0x0010($v0)
281         sq      $zero, 0x0020($v0)
282         sq      $zero, 0x0030($v0)
283         addiu   $v0, $v0, 0x0040
284         sltu    $a0, $v0, $v1
285         bne     $a0, $zero, 1b
287         /* FlushCache */
288         daddu   $a0, $zero, $zero
289         addiu   $v1, $zero, __NR_FlushCache
290         syscall
291         addiu   $a0, $zero, 2
292         addiu   $v1, $zero, __NR_FlushCache
293         syscall
295         jr      $ra
296         addiu   $v0, $zero, 1
298         .end    _SifSetDma
301  * Hook_SifSetDma: exit syscall to _SifSetDma when IOP reboot trapped
302  */
303         .ent    Hook_SifSetDma
304 Hook_SifSetDma:
306         /* check ((SifDmaTransfer_t *)$a0)->attr == 0x44 */
307         lw      $v1, 0x000c($a0)
308         addiu   $v0, $zero, 0x44
309         bne     $v0, $v1, 2f
311         /* check ((SifDmaTransfer_t *)$a0)->size == 0x68 */
312         lw      $v1, 0x0008($a0)
313         addiu   $v0, $zero, 0x68
314         beq     $v0, $v1, 1f
316         /* check ((SifDmaTransfer_t *)$a0)->size == 0x70 */
317         addiu   $v0, $zero, 0x70
318         bne     $v0, $v1, 2f
320         /* check (SifCmdResetData *)((SifDmaTransfer_t *)$a0->src)->chdr.psize == ((SifDmaTransfer_t *)$a0)->size */
321         lw      $a2, 0x0000($a0)
322         lw      $v0, 0x0000($a2)
323         bne     $v0, $v1, 2f
325         /* check (SifCmdResetData *)((SifDmaTransfer_t *)$a0->src)->chdr.fcode == 0x80000003 */
326         lui     $a3, 0x8000
327         ori     $a3, $a3, 0x0003
328         lw      $v0, 0x0008($a2)
329         bne     $v0, $a3, 2f
330         nop
332         /* exit syscall to _SifSetDma */
333         la      $v1, _SifSetDma
334         jr      $ra
335         sw      $v1, 0x0008($sp)
337         /* call & return with original SifSetDma */
338         lw      $v0, Old_SifSetDma
339         jr      $v0
340         nop
342         .end    Hook_SifSetDma
345  * _Apply_Mode3: unhook SifSetDma/SifSetReg
346  */
347         .ent    _Apply_Mode3
348 _Apply_Mode3:
350         /* save original stack pointer */
351         daddu   $a0, $sp, $zero
353 #ifdef LOAD_EECORE_DOWN
354         lui     $v0, 0x0009
355         /* ori  $v0, $v0, 0x0000 */
356 #else
357         lui     $v0, 0x000e
358         ori     $v0, $v0, 0x7000
359 #endif
360         /* change the stack pointer */
361         daddu   $sp, $v0, $zero
363         /* preserving ra and a0 registers values */
364         addiu   $sp, $sp, -0x10
365         sd      $ra, 0x0000($sp)
366         sd      $a0, 0x0008($sp)
368         /* unhook SifSetDma */
369         addiu   $a0, $zero, __NR_SifSetDma
370         lw      $a1, Old_SifSetDma
371         addiu   $v1, $zero, __NR_SetSyscall
372         syscall
374         /* unhook SifSetReg */
375         addiu   $a0, $zero, __NR_SifSetReg
376         lw      $a1, Old_SifSetReg
377         addiu   $v1, $zero, __NR_SetSyscall
378         syscall
380         /* FlushCache */
381         daddu   $a0, $zero, $zero
382         addiu   $v1, $zero, __NR_FlushCache
383         syscall
384         addiu   $a0, $zero, 2
385         addiu   $v1, $zero, __NR_FlushCache
386         syscall
388         /* restore a0 and ra registers */ 
389         ld      $a0, 0x0008($sp)
390         ld      $ra, 0x0000($sp)
392         /* restore the original stack pointer */
393         daddu   $sp, $a0, $zero
395         jr      $ra
396         addiu   $v0, $zero, 1
398         .end    _Apply_Mode3
401  * Hook_SifSetReg: disable SifSetReg and unhook SifSetDma/SifSetReg when needed
402  */
403         .ent    Hook_SifSetReg
404 Hook_SifSetReg:
406         /* load set_reg_hook counter to a2 */
407         la      $a2, set_reg_hook
408         lw      $v0, 0x0000($a2)
410         /* check set_reg_hook is != 0, otherwise execute normal SifSetReg */
411         bne     $v0, $zero, 1f
412         addiu   $v0, $v0, -1
413         lw      $v0, Old_SifSetReg
414         jr      $v0
415         nop
417         /* decrement set_reg_hook counter by 1 */
418         sw      $v0, 0x0000($a2)
419         bne     $v0, $zero, 3f
420         nop
422         lw      $v0, DisableDebug
423         bne     $v0, $zero, 2f
425         /* black BG color */
426         lui     $v0, 0x1200
427         ori     $v0, $v0, 0x00e0
428         sd      $zero, 0x0000($v0)      
430         /* check compat mode 3 is enabled */
431         lw      $v0, g_compat_mask
432         andi    $v0, $v0, COMPAT_MODE_3
433         beq     $v0, $zero, 3f
435         /* check iop_reboot_count is == 2 */
436         addiu   $v1, $zero, 2
437         lw      $v0, iop_reboot_count
438         bne     $v0, $v1, 3f
439         nop
441         /* exit syscall to _Apply_Mode3 */
442         la      $v1, _Apply_Mode3
443         sw      $v1, 0x0008($sp)
445         jr      $ra
446         addiu   $v0, $zero, 1
448         .end    Hook_SifSetReg
451  * Hook_ExecPS2:
452  */
453         .ent    Hook_ExecPS2
454 Hook_ExecPS2:
456         /* not needed to preserve sX/ra registers values as ExecPS2 won't return */
457         daddu   $s0, $a0, $zero
458         daddu   $s1, $a1, $zero
459         daddu   $s2, $a2, $zero
460         daddu   $s3, $a3, $zero
462         /* check entry point is >= 0x00100000 */
463         lui     $v0, 0x0010
464         sltu    $v0, $s0, $v0
465         bne     $v0, $zero, 1f
467         /* save original stack pointer */
468         daddu   $s4, $sp, $zero
470 #ifdef LOAD_EECORE_DOWN
471         lui     $v0, 0x0009
472         /* ori  $v0, $v0, 0x0000 */
473 #else
474         lui     $v0, 0x000e
475         ori     $v0, $v0, 0x7000
476 #endif
478         /* change stack pointer */
479         daddu   $sp, $v0, $zero
481         /* call Install_PadOpen_Hook */
482         lui     $a0, 0x0010
483         lui     $a1, 0x01ff
484         jal     Install_PadOpen_Hook
485         addiu   $a2, $zero, PADOPEN_HOOK
486         la      $v1, padOpen_hooked
487         sw      $v0, 0x0000($v1)
489         /* restore stack pointer */
490         daddu   $sp, $s4, $zero
492         /* call ExecPS2 */
493         daddu   $a0, $s0, $zero
494         daddu   $a1, $s1, $zero
495         daddu   $a2, $s2, $zero
496         lw      $v0, Old_ExecPS2
497         jr      $v0
498         daddu   $a3, $s3, $zero
500         .end    Hook_ExecPS2
503  * Hook_CreateThread:
504  */
505         .ent    Hook_CreateThread
506 Hook_CreateThread:
508         /* check padOpen_hooked == 0 */
509         lw      $v0, padOpen_hooked
510         bne     $v0, $zero, 2f
512         /* check thread_param->initial_priority == 0 */
513         lw      $v0, 0x0014($a0)
514         beq     $v0, $zero, 1f
516         /* check thread_param->initial_priority < 5 */
517         slti    $v0, $v0, 5
518         beq     $v0, $zero, 2f
520         /* check thread_param->current_priority == 0 */
521         lw      $v0, 0x0018($a0)
522         bne     $v0, $zero, 2f
524         /* save original stack pointer */
525         daddu   $a1, $sp, $zero
527 #ifdef LOAD_EECORE_DOWN
528         lui     $v0, 0x0009
529         /* ori  $v0, $v0, 0x0000 */
530 #else
531         lui     $v0, 0x000e
532         ori     $v0, $v0, 0x7000
533 #endif
534         /* change the stack pointer */
535         daddu   $sp, $v0, $zero
537         /* preserves ra, a1 and a0 registers values */
538         addiu   $sp, $sp, -0x20
539         sd      $ra, 0x0000($sp)
540         sd      $a1, 0x0008($sp)
541         sd      $a0, 0x0010($sp)
543         /* call Install_PadOpen_Hook */
544         lui     $a0, 0x0010
545         lui     $a1, 0x01ff
546         jal     Install_PadOpen_Hook
547         addiu   $a2, $zero, PADOPEN_HOOK
548         la      $v1, padOpen_hooked
549         sw      $v0, 0x0000($v1)
551         /* restore a0, a1 and ra registers */
552         ld      $a0, 0x0010($sp)
553         ld      $a1, 0x0008($sp)
554         ld      $ra, 0x0000($sp)
556         /* restore the original stack pointer */
557         daddu   $sp, $a1, $zero
559         /* call CreateThread */
560         lw      $v0, Old_CreateThread
561         jr      $v0
562         nop
564         .end    Hook_CreateThread
567 /**************************************************************************
569  * COMMON section
571  **************************************************************************/
573         .section COMMON
574 g_argbuf:
575         .space  (ARGBUF_SIZE)
578         .set pop