-
Notifications
You must be signed in to change notification settings - Fork 137
/
Copy pathsio2man_hook.c
249 lines (204 loc) · 8.6 KB
/
sio2man_hook.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
#include <stdio.h>
#include <string.h>
#include <thsemap.h>
#include <modhook.h>
#include "sio2man.h"
#include "sio2man_hook.h"
// #define DEBUG //comment out this line when not debugging
#include "module_debug.h"
#define PORT_NR 3
static int lock_sema = -1;
static int lock_sema2 = -1;
static u16 hooked_version = 0;
// sio2man function typedefs
typedef void (*psio2_transfer_init)(void);
typedef int (*psio2_transfer)(sio2_transfer_data_t *td);
typedef void (*psio2_transfer_reset)(void);
// Original sio2man function pointers
psio2_transfer_init _23_psio2_pad_transfer_init;
psio2_transfer_init _24_psio2_mc_transfer_init;
psio2_transfer_init _46_psio2_pad_transfer_init;
psio2_transfer_init _47_psio2_mc_transfer_init;
psio2_transfer_init _48_psio2_mtap_transfer_init;
psio2_transfer_init _49_psio2_rm_transfer_init;
psio2_transfer_init _50_psio2_unk_transfer_init;
psio2_transfer _25_psio2_transfer;
psio2_transfer _51_psio2_transfer;
psio2_transfer_reset _26_psio2_transfer_reset;
psio2_transfer_reset _52_psio2_transfer_reset;
// Generic sio2man init function
static void _sio2_transfer_init(psio2_transfer_init init_func)
{
//M_DEBUG("%s\n", __FUNCTION__);
WaitSema(lock_sema);
init_func();
}
// Generic sio2man transfer function
static int _sio2_transfer(psio2_transfer transfer_func, sio2_transfer_data_t *td)
{
int rv, i;
//M_DEBUG("%s\n", __FUNCTION__);
// Do not allow transfers to/from our used port
for (i = 0; i < 16; i++) {
// Last transfer, we're ok.
if (td->regdata[i] == 0)
break;
// Wrong port, abort.
if ((td->regdata[i] & 3) == PORT_NR)
return 1;
}
WaitSema(lock_sema2);
rv = transfer_func(td);
SignalSema(lock_sema2);
return rv;
}
// Generic sio2man transfer_reset function
static void _sio2_transfer_reset(psio2_transfer_reset reset_func)
{
//M_DEBUG("%s\n", __FUNCTION__);
reset_func();
SignalSema(lock_sema);
}
// Hooked sio2man functions
static void _23_sio2_pad_transfer_init() { _sio2_transfer_init(_23_psio2_pad_transfer_init); }
static void _24_sio2_mc_transfer_init() { _sio2_transfer_init(_24_psio2_mc_transfer_init); }
static void _46_sio2_pad_transfer_init() { _sio2_transfer_init(_46_psio2_pad_transfer_init); }
static void _47_sio2_mc_transfer_init() { _sio2_transfer_init(_47_psio2_mc_transfer_init); }
static void _48_sio2_mtap_transfer_init() { _sio2_transfer_init(_48_psio2_mtap_transfer_init); }
static void _49_sio2_rm_transfer_init() { _sio2_transfer_init(_49_psio2_rm_transfer_init); }
static void _50_sio2_unk_transfer_init() { _sio2_transfer_init(_50_psio2_unk_transfer_init); }
static void _26_sio2_transfer_reset() { _sio2_transfer_reset(_26_psio2_transfer_reset); }
static void _52_sio2_transfer_reset() { _sio2_transfer_reset(_52_psio2_transfer_reset); }
static int _25_sio2_transfer(sio2_transfer_data_t *td) { return _sio2_transfer(_25_psio2_transfer, td); }
static int _51_sio2_transfer(sio2_transfer_data_t *td) { return _sio2_transfer(_51_psio2_transfer, td); }
static void _sio2man_unhook(iop_library_t *lib)
{
if (hooked_version == 0) {
M_DEBUG("Warning: trying to unhook sio2man while not hooked\n");
return;
}
modhookk_hookExportEntry(lib, 23, _23_psio2_pad_transfer_init);
modhook_hookExportEntry(lib, 24, _24_psio2_mc_transfer_init);
modhook_hookExportEntry(lib, 25, _25_psio2_transfer);
modhookk_hookExportEntry(lib, 26, _26_psio2_transfer_reset);
modhook_hookExportEntry(lib, 46, _46_psio2_pad_transfer_init);
modhook_hookExportEntry(lib, 47, _47_psio2_mc_transfer_init);
modhook_hookExportEntry(lib, 48, _48_psio2_mtap_transfer_init);
if ((hooked_version >= IRX_VER(1, 2)) && (hooked_version < IRX_VER(2, 0))) {
// Only for the newer rom0:XSIO2MAN
// Assume all v1.x libraries to use this interface (reset at 50)
modhook_hookExportEntry(lib, 49, _51_psio2_transfer);
modhook_hookExportEntry(lib, 50, _52_psio2_transfer_reset);
} else /*if (hooked_version >= IRX_VER(2, 3))*/ {
// Only for the newer rom1:SIO2MAN
// Assume all v2.x libraries to use this interface (reset at 52)
modhook_hookExportEntry(lib, 49, _49_psio2_rm_transfer_init);
modhook_hookExportEntry(lib, 50, _50_psio2_unk_transfer_init);
modhook_hookExportEntry(lib, 51, _51_psio2_transfer);
modhook_hookExportEntry(lib, 52, _52_psio2_transfer_reset);
}
hooked_version = 0;
}
static void _sio2man_hook(iop_library_t *lib)
{
if (hooked_version != 0) {
M_DEBUG("Warning: trying to hook sio2man version 0x%x\n", lib->version);
M_DEBUG(" while version 0x%x already hooked\n", hooked_version);
return;
}
// Only the newer sio2man libraries (with reset functions) are supported
if (lib->version > IRX_VER(1, 1)) {
M_DEBUG("Installing sio2man hooks for version 0x%x\n", lib->version);
_23_psio2_pad_transfer_init = modhook_hookExportEntry(lib, 23, _23_sio2_pad_transfer_init);
// Lock sio2 to prevent race conditions with MC/PAD libraries
_23_psio2_pad_transfer_init();
_24_psio2_mc_transfer_init = modhook_hookExportEntry(lib, 24, _24_sio2_mc_transfer_init);
_25_psio2_transfer = modhook_hookExportEntry(lib, 25, _25_sio2_transfer);
_26_psio2_transfer_reset = modhook_hookExportEntry(lib, 26, _26_sio2_transfer_reset);
_46_psio2_pad_transfer_init = modhook_hookExportEntry(lib, 46, _46_sio2_pad_transfer_init);
_47_psio2_mc_transfer_init = modhook_hookExportEntry(lib, 47, _47_sio2_mc_transfer_init);
_48_psio2_mtap_transfer_init = modhook_hookExportEntry(lib, 48, _48_sio2_mtap_transfer_init);
if ((lib->version >= IRX_VER(1, 2)) && (lib->version < IRX_VER(2, 0))) {
// Only for the newer rom0:XSIO2MAN
// Assume all v1.x libraries to use this interface (reset at 50)
_51_psio2_transfer = modhook_hookExportEntry(lib, 49, _51_sio2_transfer);
_52_psio2_transfer_reset = modhook_hookExportEntry(lib, 50, _52_sio2_transfer_reset);
} else /*if (lib->version >= IRX_VER(2, 3))*/ {
// Only for the newer rom1:SIO2MAN
// Assume all v2.x libraries to use this interface (reset at 52)
_49_psio2_rm_transfer_init = modhook_hookExportEntry(lib, 49, _49_sio2_rm_transfer_init);
_50_psio2_unk_transfer_init = modhook_hookExportEntry(lib, 50, _50_sio2_unk_transfer_init);
_51_psio2_transfer = modhook_hookExportEntry(lib, 51, _51_sio2_transfer);
_52_psio2_transfer_reset = modhook_hookExportEntry(lib, 52, _52_sio2_transfer_reset);
}
// Unlock sio2
_26_psio2_transfer_reset();
hooked_version = lib->version;
} else {
M_DEBUG("ERROR: sio2man version 0x%x not supported\n", lib->version);
}
}
int (*pRegisterLibraryEntries)(iop_library_t *lib);
static int hookRegisterLibraryEntries(iop_library_t *lib)
{
M_DEBUG("RegisterLibraryEntries: %s 0x%x\n", lib->name, lib->version);
if (!strcmp(lib->name, "sio2man"))
_sio2man_hook(lib);
return pRegisterLibraryEntries(lib);
}
int sio2man_hook_init()
{
iop_sema_t sema;
iop_library_t *lib;
M_DEBUG("%s\n", __FUNCTION__);
// Create semaphore for locking sio2man exclusively
sema.attr = 1;
sema.initial = 1;
sema.max = 1;
sema.option = 0;
lock_sema = CreateSema(&sema);
lock_sema2 = CreateSema(&sema);
// Hook into 'loadcore' so we know when sio2man is loaded in the future
lib = modhook_getModule("loadcore");
if (lib == NULL) {
DeleteSema(lock_sema);
DeleteSema(lock_sema2);
return -1;
}
pRegisterLibraryEntries = modhook_hookExportEntry(lib, 6, hookRegisterLibraryEntries);
// Hook into 'sio2man' now if it's already loaded
lib = modhook_getModule("sio2man");
if (lib != NULL) {
_sio2man_hook(lib);
modhook_relinkExports(lib);
}
return 0;
}
void sio2man_hook_deinit()
{
iop_library_t *lib;
M_DEBUG("%s\n", __FUNCTION__);
// Unhook 'sio2man'
lib = modhook_getModule("sio2man");
if (lib != NULL) {
_sio2man_unhook(lib);
modhook_relinkExports(lib);
}
// Unhook 'loadcore'
modhook_hookExportEntry(lib, 6, pRegisterLibraryEntries);
// Delete locking semaphore
DeleteSema(lock_sema);
DeleteSema(lock_sema2);
}
void sio2man_hook_sio2_lock()
{
// Lock sio2man driver so we can use it exclusively
WaitSema(lock_sema);
WaitSema(lock_sema2);
}
void sio2man_hook_sio2_unlock()
{
// Unlock sio2man driver
SignalSema(lock_sema2);
SignalSema(lock_sema);
}