901de511a511341346b8b1cb3ad694d7f159e64c
[ginge.git] / loader / patches.c
1 /*
2  * GINGE - GINGE Is Not Gp2x Emulator
3  * (C) notaz, 2010-2011,2016
4  *
5  * This work is licensed under the MAME license, see COPYING file for details.
6  */
7 #include <stdio.h>
8
9 #include "header.h"
10 #include "syscalls.h"
11
12 #include "override.c"
13
14 // note: first mask int must be always full for the search algo
15 static const unsigned int sig_mask_all[] = {
16   0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
17   0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
18 };
19
20 static const unsigned int sig_open[] = {
21   0xe59cc000, // ldr ip, [ip]
22   0xe33c0000, // teq ip, #0
23   0x1a000003, // bne 0x1c
24   0xef900005, // svc 0x900005
25 };
26 #define sig_mask_open sig_mask_all
27
28 static const unsigned int sig_open_a1[] = {
29   0xef900005, // svc 0x900005
30   0xe1a0f00e, // mov pc, lr
31 };
32 #define sig_mask_open_a1 sig_mask_all
33
34 static const unsigned int sig_hw_open[] = {
35   0xef900005, // svc  0x900005
36   0xe3700a01, // cmn  r0, #0x1000
37   0xe1a04000, // mov  r4, r0
38 };
39 #define sig_mask_hw_open sig_mask_all
40
41 static const unsigned int sig_mmap[] = {
42   0xe92d000f, // push {r0, r1, r2, r3}
43   0xe1a0000d, // mov  r0, sp
44   0xef90005a, // svc  0x90005a
45   0xe28dd010, // add  sp, sp, #16
46 };
47 #define sig_mask_mmap sig_mask_all
48
49 static const unsigned int sig_munmap[] = {
50   0xef90005b, // svc  0x90005b
51   0xe3700a01, // cmn  r0, #0x1000
52   0x312fff1e, // bxcc lr
53 };
54 #define sig_mask_munmap sig_mask_all
55
56 static const unsigned int sig_mmap2[] = {
57   0xe52d5004, // push {r5}
58   0xe59d5008, // ldr  r5, [sp, #8]
59   0xe52d4004, // push {r4}
60   0xe59d4008, // ldr  r4, [sp, #8]
61   0xe1b0ca05, // lsls ip, r5, #20
62   0x1a000006, // bne  0x34
63   0xe1a05625, // lsr  r5, r5, #12
64   0xef9000c0, // svc  0x9000c0
65 };
66 #define sig_mask_mmap2 sig_mask_all
67
68 static const unsigned int sig_read[] = {
69   0xe59fc080, // ldr ip, [pc, #128]
70   0xe59cc000, // ldr ip, [ip]
71   0xe33c0000, // teq ip, #0
72   0x1a000003, // bne 0x20
73   0xef900003, // svc 0x900003
74 };
75 #define sig_mask_read sig_mask_all
76
77 static const unsigned int sig_read_a1[] = {
78   0xef900003, // svc  0x900003
79   0xe3700a01, // cmn  r0, #0x1000
80   0x312fff1e, // bxcc lr
81 };
82 #define sig_mask_read_a1 sig_mask_all
83
84 static const unsigned int sig_hw_read[] = {
85   0xef900003, // svc  0x900003
86   0xe3700a01, // cmn  r0, #0x1000
87   0xe1a04000, // mov  r4, r0
88 };
89 #define sig_mask_hw_read sig_mask_all
90
91 static const unsigned int sig_ioctl[] = {
92   0xef900036, // svc  0x900036
93   0xe3700a01, // cmn  r0, #0x1000
94   0x312fff1e, // bxcc lr
95 };
96 #define sig_mask_ioctl sig_mask_all
97
98 static const unsigned int sig_hw_ioctl[] = {
99   0xef900036, // svc  0x900036
100   0xe3700a01, // cmn  r0, #0x1000
101   0xe1a04000, // mov  r4, r0
102 };
103 #define sig_mask_hw_ioctl sig_mask_all
104
105 static const unsigned int sig_sigaction[] = {
106   0xe59f300c, //    ldr r3, [pc, #12]
107   0xe3530000, //    cmp r3, #0
108   0x0a000000, //    beq 0f
109   0xea000000, //    b   *
110   0xea000000, // 0: b   *
111 };
112 static const unsigned int sig_mask_sigaction[] = {
113   0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000
114 };
115
116 static const unsigned int sig_execve[] = {
117   0xef90000b, // svc 0x90000b
118   0xe1a04000, // mov r4, r0
119   0xe3700a01, // cmn r0, #4096
120 };
121 #define sig_mask_execve sig_mask_all
122
123 static const unsigned int sig_hw_execve[] = {
124   0xef90000b, // svc 0x90000b
125   0xe3700a01, // cmn r0, #4096
126   0xe1a04000, // mov r4, r0
127 };
128 #define sig_mask_hw_execve sig_mask_all
129
130 static const unsigned int sig_chdir[] = {
131   0xef90000c, // svc  0x90000c
132   0xe3700a01, // cmn  r0, #4096
133   0x312fff1e, // bxcc lr
134   0xea0004bb, // b    *
135 };
136 static const unsigned int sig_mask_chdir[] = {
137   0xffffffff, 0xffffffff, 0xffffffff, 0xff000000
138 };
139
140 static const unsigned int sig_readlink[] = {
141   0xef900055, // svc  0x900055
142   0xe3700a01, // cmn  r0, #0x1000
143   0x312fff1e, // bxcc lr
144 };
145 #define sig_mask_readlink sig_mask_all
146
147 /* special */
148 static const unsigned int sig_cache1[] = {
149   0xee073f5e, // mcr 15, 0, r3, cr7, cr14, 2
150 };
151 #define sig_mask_cache1 sig_mask_all
152
153 static const unsigned int sig_cache2[] = {
154   0xee070f17, // mcr 15, 0, r0, cr7, cr7, 0
155 };
156 #define sig_mask_cache2 sig_mask_all
157
158 /* additional wrappers for harder case of syscalls within the code stream */
159 #ifdef PND /* fix PC, not needed on ARM9 */
160 # define SVC_CMN_R0_MOV_R4_PC_ADJ() \
161 "  ldr  r12, [sp, #5*4]\n" \
162 "  add  r12, r12, #4\n" \
163 "  str  r12, [sp, #5*4]\n"
164 #else
165 # define SVC_CMN_R0_MOV_R4_PC_ADJ()
166 #endif
167
168 #define SVC_CMN_R0_MOV_R4_WRAPPER(name, target) \
169 extern int name(); \
170 asm( \
171 #name ":\n" \
172 "  stmfd sp!, {r1-r3,r12,lr}\n" \
173    SVC_CMN_R0_MOV_R4_PC_ADJ() \
174 "  bl   " #target "\n" \
175 "  cmn  r0, #0x1000\n" \
176 "  mov  r4, r0\n" \
177 "  ldmfd sp!, {r1-r3,r12,lr,pc}\n" \
178 );
179
180 SVC_CMN_R0_MOV_R4_WRAPPER(hw_open, w_open_raw)
181 SVC_CMN_R0_MOV_R4_WRAPPER(hw_read, w_read_raw)
182 SVC_CMN_R0_MOV_R4_WRAPPER(hw_ioctl, w_ioctl_raw)
183 SVC_CMN_R0_MOV_R4_WRAPPER(hw_execve, w_execve_raw)
184
185 #define PATCH_(p, f, t) { sig_##p, sig_mask_##p, ARRAY_SIZE(sig_##p), t, f, #p }
186 #define PATCH(f) PATCH_(f, w_##f, 0)
187
188 static const struct {
189   const unsigned int *sig;
190   const unsigned int *sig_mask;
191   size_t sig_cnt;
192   unsigned int type;
193   void *func;
194   const char *name;
195 } patches[] = {
196   PATCH (open),
197   PATCH_(open_a1, w_open, 0),
198   PATCH_(hw_open, hw_open, 1),
199   PATCH (mmap),
200   PATCH (mmap2), // mmap2 syscall
201   PATCH (munmap),
202   PATCH (read),
203   PATCH_(read_a1, w_read, 0),
204   PATCH_(hw_read, hw_read, 1),
205   PATCH (ioctl),
206   PATCH_(hw_ioctl, hw_ioctl, 1),
207   PATCH (sigaction),
208   PATCH_(hw_execve, hw_execve, 1),
209   PATCH (chdir),
210   PATCH (readlink),
211   PATCH_(cache1, NULL, 2),
212   PATCH_(cache2, NULL, 2),
213 };
214
215 void do_patches(void *ptr, unsigned int size)
216 {
217   unsigned int *seg = (void *)(((long)ptr + 3) & ~3);
218   unsigned int *seg_end = seg + size / 4;
219   int i, s;
220
221   for (; seg < seg_end; seg++) {
222     for (i = 0; i < ARRAY_SIZE(patches); i++) {
223       const unsigned int *sig = patches[i].sig;
224       const unsigned int *sig_mask;
225
226       if (*seg != sig[0])
227         continue;
228
229       sig_mask = patches[i].sig_mask;
230       for (s = 1; s < patches[i].sig_cnt; s++)
231         if ((seg[s] ^ sig[s]) & sig_mask[s])
232           break;
233
234       if (s == patches[i].sig_cnt) {
235         switch (patches[i].type) {
236         case 0:
237           seg[0] = 0xe51ff004; // ldr   pc, [pc, #-4]
238           seg[1] = (unsigned int)patches[i].func;
239           break;
240         case 1:
241           seg[0] = 0xe92d8000; // stmfd sp!, {pc}
242           seg[1] = 0xe51ff004; // ldr   pc, [pc, #-4]
243           seg[2] = (unsigned int)patches[i].func;
244           break;
245         case 2:
246           if (seg < (unsigned int *)ptr + 1 || (seg[-1] >> 28) != 0x0e)
247             // might be data
248             continue;
249           seg[0] = 0xe1a00000; // nop
250           break;
251         default:
252           err("bad patch type: %u\n", patches[i].type);
253           abort();
254         }
255         dbg("  patch #%2i @ %08x type %d %s\n",
256           i, (int)seg, patches[i].type, patches[i].name);
257         seg += patches[i].sig_cnt - 1;
258         break;
259       }
260     }
261   }
262
263   sys_cacheflush(ptr, (char *)ptr + size);
264 }
265
266 // vim:shiftwidth=2:expandtab