take over /dev/tty too
[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 "sys_cacheflush.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_mmap[] = {
29   0xe92d000f, // push {r0, r1, r2, r3}
30   0xe1a0000d, // mov  r0, sp
31   0xef90005a, // svc  0x90005a
32   0xe28dd010, // add  sp, sp, #16
33 };
34 #define sig_mask_mmap sig_mask_all
35
36 static const unsigned int sig_mmap2[] = {
37   0xe52d5004, // push {r5}
38   0xe59d5008, // ldr  r5, [sp, #8]
39   0xe52d4004, // push {r4}
40   0xe59d4008, // ldr  r4, [sp, #8]
41   0xe1b0ca05, // lsls ip, r5, #20
42   0x1a000006, // bne  0x34
43   0xe1a05625, // lsr  r5, r5, #12
44   0xef9000c0, // svc  0x009000c0
45 };
46 #define sig_mask_mmap2 sig_mask_all
47
48 static const unsigned int sig_read[] = {
49   0xe59fc080, // ldr ip, [pc, #128]
50   0xe59cc000, // ldr ip, [ip]
51   0xe33c0000, // teq ip, #0
52   0x1a000003, // bne 0x20
53   0xef900003, // svc 0x900003
54 };
55 #define sig_mask_read sig_mask_all
56
57 static const unsigned int sig_ioctl[] = {
58   0xef900036, // svc  0x900036
59   0xe3700a01, // cmn  r0, #0x1000
60   0x312fff1e, // bxcc lr
61 };
62 #define sig_mask_ioctl sig_mask_all
63
64 static const unsigned int sig_hw_ioctl[] = {
65   0xef900036, // svc  0x900036
66   0xe3700a01, // cmn  r0, #0x1000
67   0xe1a04000, // mov  r4, r0
68 };
69 #define sig_mask_hw_ioctl sig_mask_all
70
71 static const unsigned int sig_sigaction[] = {
72   0xe59f300c, //    ldr r3, [pc, #12]
73   0xe3530000, //    cmp r3, #0
74   0x0a000000, //    beq 0f
75   0xea000000, //    b   *
76   0xea000000, // 0: b   *
77 };
78 static const unsigned int sig_mask_sigaction[] = {
79   0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000
80 };
81
82 static const unsigned int sig_execve[] = {
83   0xef90000b, // svc 0x90000b
84   0xe1a04000, // mov r4, r0
85   0xe3700a01, // cmn r0, #4096
86 };
87 #define sig_mask_execve sig_mask_all
88
89 static const unsigned int sig_execve2[] = {
90   0xef90000b, // svc 0x90000b
91   0xe3700a01, // cmn r0, #4096
92   0xe1a04000, // mov r4, r0
93 };
94 #define sig_mask_execve2 sig_mask_all
95
96 static const unsigned int sig_chdir[] = {
97   0xef90000c, // svc  0x90000c
98   0xe3700a01, // cmn  r0, #4096
99   0x312fff1e, // bxcc lr
100   0xea0004bb, // b    *
101 };
102 static const unsigned int sig_mask_chdir[] = {
103   0xffffffff, 0xffffffff, 0xffffffff, 0xff000000
104 };
105
106 /* additional wrapper for harder case of syscalls within the code stream */
107 extern int hw_ioctl(int fd, int request, void *argp);
108 asm(
109 "hw_ioctl:\n"
110 "  stmfd sp!, {r1-r3,r12,lr}\n"
111 #ifdef PND // fix PC, not needed on ARM9
112 "  ldr  r1, [sp, #5*4]\n"
113 "  add  r1, r1, #4\n"
114 "  str  r1, [sp, #5*4]\n"
115 #endif
116 "  bl   w_ioctl\n"
117 "  cmn  r0, #0x1000\n"
118 "  mov  r4, r0\n"
119 "  ldmfd sp!, {r1-r3,r12,lr,pc}\n"
120 );
121
122 #define PATCH_(f, p, t) { sig_##p, sig_mask_##p, ARRAY_SIZE(sig_##p), t, f }
123 #define PATCH(f) PATCH_(w_##f, f, 0)
124
125 static const struct {
126   const unsigned int *sig;
127   const unsigned int *sig_mask;
128   size_t sig_cnt;
129   unsigned int type;
130   void *func;
131 } patches[] = {
132   PATCH(open),
133   PATCH(mmap),
134   PATCH(mmap2), // mmap2 syscall
135   PATCH(read),
136   PATCH(ioctl),
137   PATCH_(hw_ioctl, hw_ioctl, 1),
138   PATCH(sigaction),
139 //  PATCH_(execve, execve2), // hangs
140   PATCH(chdir),
141 };
142
143 void do_patches(void *ptr, unsigned int size)
144 {
145   int i, s;
146
147   for (i = 0; i < ARRAY_SIZE(patches); i++) {
148     const unsigned int *sig = patches[i].sig;
149     const unsigned int *sig_mask = patches[i].sig_mask;
150     unsigned int *seg = (void *)(((long)ptr + 3) & ~3);
151     unsigned int *seg_end = seg + size / 4;
152     unsigned int sig0 = sig[0];
153
154     for (; seg < seg_end; seg++) {
155       if (*seg != sig0)
156         continue;
157
158       for (s = 1; s < patches[i].sig_cnt; s++)
159         if ((seg[s] ^ sig[s]) & sig_mask[s])
160           break;
161
162       if (s == patches[i].sig_cnt) {
163         dbg("  patch #%i @ %08x type %d\n", i, (int)seg, patches[i].type);
164         switch (patches[i].type) {
165         case 0:
166           seg[0] = 0xe59ff000; // ldr pc, [pc]
167           seg[1] = 0;
168           seg[2] = (unsigned int)patches[i].func;
169           break;
170         case 1:
171           seg[0] = 0xe92d8000; // stmfd sp!, {pc}
172           seg[1] = 0xe51ff004; // pc, [pc, #-4]
173           seg[2] = (unsigned int)patches[i].func;
174           break;
175         default:
176           err("bad patch type: %u\n", patches[i].type);
177           abort();
178         }
179         seg += patches[i].sig_cnt - 1;
180       }
181     }
182   }
183
184   sys_cacheflush(ptr, (char *)ptr + size);
185 }
186
187 // vim:shiftwidth=2:expandtab