sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
sio2man_hook.c
1#include <stdio.h>
2#include <string.h>
3#include <thsemap.h>
4#include <thbase.h>
5
6#include "ioplib.h"
7#include "intrman.h"
8#include "sio2man.h"
9#include "sio2man_hook.h"
10
11// #define DEBUG //comment out this line when not debugging
12#include "module_debug.h"
13
14static int lock_sema = -1;
15static int lock_sema2 = -1;
16static u16 hooked_version = 0;
17
18intrman_internals_t *mmce_sio2_intrman_internals_ptr = NULL;
19
20// sio2man function typedefs
21typedef void (*psio2_transfer_init)(void);
22typedef int (*psio2_transfer)(sio2_transfer_data_t *td);
23typedef void (*psio2_transfer_reset)(void);
24
25// Original sio2man function pointers
26psio2_transfer_init _23_psio2_pad_transfer_init;
27psio2_transfer_init _24_psio2_mc_transfer_init;
28psio2_transfer_init _46_psio2_pad_transfer_init;
29psio2_transfer_init _47_psio2_mc_transfer_init;
30psio2_transfer_init _48_psio2_mtap_transfer_init;
31psio2_transfer_init _49_psio2_rm_transfer_init;
32psio2_transfer_init _50_psio2_unk_transfer_init;
33psio2_transfer _25_psio2_transfer;
34psio2_transfer _51_psio2_transfer;
35psio2_transfer_reset _26_psio2_transfer_reset;
36psio2_transfer_reset _52_psio2_transfer_reset;
37
38// Generic sio2man init function
39static void _sio2_transfer_init(psio2_transfer_init init_func)
40{
41 //DPRINTF("%s\n", __FUNCTION__);
42 WaitSema(lock_sema);
43 init_func();
44}
45
46// Generic sio2man transfer function
47static int _sio2_transfer(psio2_transfer transfer_func, sio2_transfer_data_t *td)
48{
49 int rv;
50
51 //DPRINTF("%s\n", __FUNCTION__);
52
53 WaitSema(lock_sema2);
54 rv = transfer_func(td);
55 SignalSema(lock_sema2);
56
57 return rv;
58}
59
60// Generic sio2man transfer_reset function
61static void _sio2_transfer_reset(psio2_transfer_reset reset_func)
62{
63 //DPRINTF("%s\n", __FUNCTION__);
64
65 reset_func();
66 SignalSema(lock_sema);
67}
68
69// Hooked sio2man functions
70static void _23_sio2_pad_transfer_init() { _sio2_transfer_init(_23_psio2_pad_transfer_init); }
71static void _24_sio2_mc_transfer_init() { _sio2_transfer_init(_24_psio2_mc_transfer_init); }
72static void _46_sio2_pad_transfer_init() { _sio2_transfer_init(_46_psio2_pad_transfer_init); }
73static void _47_sio2_mc_transfer_init() { _sio2_transfer_init(_47_psio2_mc_transfer_init); }
74static void _48_sio2_mtap_transfer_init() { _sio2_transfer_init(_48_psio2_mtap_transfer_init); }
75static void _49_sio2_rm_transfer_init() { _sio2_transfer_init(_49_psio2_rm_transfer_init); }
76static void _50_sio2_unk_transfer_init() { _sio2_transfer_init(_50_psio2_unk_transfer_init); }
77static void _26_sio2_transfer_reset() { _sio2_transfer_reset(_26_psio2_transfer_reset); }
78static void _52_sio2_transfer_reset() { _sio2_transfer_reset(_52_psio2_transfer_reset); }
79static int _25_sio2_transfer(sio2_transfer_data_t *td) { return _sio2_transfer(_25_psio2_transfer, td); }
80static int _51_sio2_transfer(sio2_transfer_data_t *td) { return _sio2_transfer(_51_psio2_transfer, td); }
81
82static void _sio2man_unhook(iop_library_t *lib)
83{
84 if (hooked_version == 0) {
85 DPRINTF("Warning: trying to unhook sio2man while not hooked\n");
86 return;
87 }
88
89 ioplib_hookExportEntry(lib, 23, _23_psio2_pad_transfer_init);
90 ioplib_hookExportEntry(lib, 24, _24_psio2_mc_transfer_init);
91 ioplib_hookExportEntry(lib, 25, _25_psio2_transfer);
92 ioplib_hookExportEntry(lib, 26, _26_psio2_transfer_reset);
93 ioplib_hookExportEntry(lib, 46, _46_psio2_pad_transfer_init);
94 ioplib_hookExportEntry(lib, 47, _47_psio2_mc_transfer_init);
95 ioplib_hookExportEntry(lib, 48, _48_psio2_mtap_transfer_init);
96
97 if ((hooked_version >= IRX_VER(1, 2)) && (hooked_version < IRX_VER(2, 0))) {
98 // Only for the newer rom0:XSIO2MAN
99 // Assume all v1.x libraries to use this interface (reset at 50)
100 ioplib_hookExportEntry(lib, 49, _51_psio2_transfer);
101 ioplib_hookExportEntry(lib, 50, _52_psio2_transfer_reset);
102 } else /*if (hooked_version >= IRX_VER(2, 3))*/ {
103 // Only for the newer rom1:SIO2MAN
104 // Assume all v2.x libraries to use this interface (reset at 52)
105 ioplib_hookExportEntry(lib, 49, _49_psio2_rm_transfer_init);
106 ioplib_hookExportEntry(lib, 50, _50_psio2_unk_transfer_init);
107 ioplib_hookExportEntry(lib, 51, _51_psio2_transfer);
108 ioplib_hookExportEntry(lib, 52, _52_psio2_transfer_reset);
109 }
110
111 hooked_version = 0;
112}
113
114static void _sio2man_hook(iop_library_t *lib)
115{
116 if (hooked_version != 0) {
117 DPRINTF("Warning: trying to hook sio2man version 0x%x\n", lib->version);
118 DPRINTF(" while version 0x%x already hooked\n", hooked_version);
119 return;
120 }
121
122 // Only the newer sio2man libraries (with reset functions) are supported
123 if (lib->version > IRX_VER(1, 1)) {
124 DPRINTF("Installing sio2man hooks for version 0x%x\n", lib->version);
125
126 _23_psio2_pad_transfer_init = ioplib_hookExportEntry(lib, 23, _23_sio2_pad_transfer_init);
127 // Lock sio2 to prevent race conditions with MC/PAD libraries
128 _23_psio2_pad_transfer_init();
129
130 _24_psio2_mc_transfer_init = ioplib_hookExportEntry(lib, 24, _24_sio2_mc_transfer_init);
131 _25_psio2_transfer = ioplib_hookExportEntry(lib, 25, _25_sio2_transfer);
132 _26_psio2_transfer_reset = ioplib_hookExportEntry(lib, 26, _26_sio2_transfer_reset);
133 _46_psio2_pad_transfer_init = ioplib_hookExportEntry(lib, 46, _46_sio2_pad_transfer_init);
134 _47_psio2_mc_transfer_init = ioplib_hookExportEntry(lib, 47, _47_sio2_mc_transfer_init);
135 _48_psio2_mtap_transfer_init = ioplib_hookExportEntry(lib, 48, _48_sio2_mtap_transfer_init);
136
137 if ((lib->version >= IRX_VER(1, 2)) && (lib->version < IRX_VER(2, 0))) {
138 // Only for the newer rom0:XSIO2MAN
139 // Assume all v1.x libraries to use this interface (reset at 50)
140 _51_psio2_transfer = ioplib_hookExportEntry(lib, 49, _51_sio2_transfer);
141 _52_psio2_transfer_reset = ioplib_hookExportEntry(lib, 50, _52_sio2_transfer_reset);
142 } else /*if (lib->version >= IRX_VER(2, 3))*/ {
143 // Only for the newer rom1:SIO2MAN
144 // Assume all v2.x libraries to use this interface (reset at 52)
145 _49_psio2_rm_transfer_init = ioplib_hookExportEntry(lib, 49, _49_sio2_rm_transfer_init);
146 _50_psio2_unk_transfer_init = ioplib_hookExportEntry(lib, 50, _50_sio2_unk_transfer_init);
147 _51_psio2_transfer = ioplib_hookExportEntry(lib, 51, _51_sio2_transfer);
148 _52_psio2_transfer_reset = ioplib_hookExportEntry(lib, 52, _52_sio2_transfer_reset);
149 }
150
151 // Unlock sio2
152 _26_psio2_transfer_reset();
153
154 hooked_version = lib->version;
155 } else {
156 DPRINTF("ERROR: sio2man version 0x%x not supported\n", lib->version);
157 }
158}
159
160// intrman hook
161static int hooked = 0;
162int (*pRegisterIntrHandler)(int irq, int mode, int (*handler)(void *), void *arg);
163static int hookRegisterIntrHandler(int irq, int mode, int (*handler)(void *), void *arg)
164{
165 DPRINTF("RegisterIntrHandler irq: %i, handler @ 0x%p\n", irq, handler);
166
167 // SIO2 interrupt
168 if (irq == 17 && hooked == 0) {
169 // TODO: Possibly remove hook after SIO2MAN intr ptr is obtained
170 if (handler != mmce_sio2_intr_handler_ptr) {
171 sio2man_intr_handler_ptr = handler;
172 sio2man_intr_arg_ptr = arg;
173 hooked = 1;
174
175 DPRINTF("Got SIO2MAN intr handler @ 0x%p, arg @ 0x%p\n", handler, arg);
176 }
177 }
178
179 return pRegisterIntrHandler(irq, mode, handler, arg);
180}
181
182// loadcore hook
183int (*pRegisterLibraryEntries)(iop_library_t *lib);
184static int hookRegisterLibraryEntries(iop_library_t *lib)
185{
186 //DPRINTF("RegisterLibraryEntries: %s 0x%x\n", lib->name, lib->version);
187
188 if (!strcmp(lib->name, "sio2man")) {
189 _sio2man_hook(lib);
190 }
191
192 return pRegisterLibraryEntries(lib);
193}
194
195int sio2man_hook_init()
196{
197 iop_sema_t sema;
198 iop_library_t *lib;
199
200 //DPRINTF("%s\n", __FUNCTION__);
201
202 // Get ptr to intrmans internals
203 mmce_sio2_intrman_internals_ptr = GetIntrmanInternalData();
204 if (mmce_sio2_intrman_internals_ptr == NULL) {
205 DPRINTF("Failed to get intrman internals ptr\n");
206 return -1;
207 }
208
209 // Create semaphore for locking sio2man exclusively
210 sema.attr = 1;
211 sema.initial = 1;
212 sema.max = 1;
213 sema.option = 0;
214 lock_sema = CreateSema(&sema);
215 lock_sema2 = CreateSema(&sema);
216
217 // Hook into 'sio2man' now if it's already loaded
218 lib = ioplib_getByName("sio2man");
219 if (lib != NULL) {
220 // Get sio2man intr handler
221 sio2man_intr_handler_ptr = mmce_sio2_intrman_internals_ptr->interrupt_handler_table[17].handler; //TODO: mode set in lowest 2 bits
222 sio2man_intr_arg_ptr = mmce_sio2_intrman_internals_ptr->interrupt_handler_table[17].userdata;
223 DPRINTF("Got SIO2MAN intr handler @ 0x%p, arg @ 0x%p\n", sio2man_intr_handler_ptr, sio2man_intr_arg_ptr);
224
225 // Hook into sio2man
226 _sio2man_hook(lib);
227 ioplib_relinkExports(lib);
228
229 // 'sio2man' is not loaded yet
230 } else {
231 // Hook into 'loadcore' so we know when sio2man is loaded in the future
232 lib = ioplib_getByName("loadcore");
233 if (lib == NULL) {
234 DeleteSema(lock_sema);
235 DeleteSema(lock_sema2);
236 return -1;
237 }
238 pRegisterLibraryEntries = ioplib_hookExportEntry(lib, 6, hookRegisterLibraryEntries);
239
240 // Hook into intrman to get ptr to sio2man's intr handler in future
241 lib = ioplib_getByName("intrman");
242 if (lib == NULL) {
243 DeleteSema(lock_sema);
244 DeleteSema(lock_sema2);
245 return -1;
246 }
247 pRegisterIntrHandler = ioplib_hookExportEntry(lib, 4, hookRegisterIntrHandler);
248 }
249
250 return 0;
251}
252
253void sio2man_hook_deinit()
254{
255 iop_library_t *lib;
256
257 //DPRINTF("%s\n", __FUNCTION__);
258
259 // Unhook 'sio2man'
260 lib = ioplib_getByName("sio2man");
261 if (lib != NULL) {
262 _sio2man_unhook(lib);
263 ioplib_relinkExports(lib);
264 }
265
266 // Unhook 'loadcore'
267 lib = ioplib_getByName("loadcore");
268 if (lib != NULL) {
269 ioplib_hookExportEntry(lib, 6, pRegisterLibraryEntries);
270 }
271
272 // Unhook 'intrman'
273 lib = ioplib_getByName("intrman");
274 if (lib != NULL) {
275 ioplib_hookExportEntry(lib, 4, pRegisterIntrHandler);
276 }
277
278 // Delete locking semaphore
279 DeleteSema(lock_sema);
280 DeleteSema(lock_sema2);
281}
282
283void sio2man_hook_sio2_lock()
284{
285 // Lock sio2man driver so we can use it exclusively
286 WaitSema(lock_sema);
287 WaitSema(lock_sema2);
288}
289
290void sio2man_hook_sio2_unlock()
291{
292 // Unlock sio2man driver
293 SignalSema(lock_sema2);
294 SignalSema(lock_sema);
295}
iop_library_t * ioplib_getByName(const char *name)
get library object of any IRX Module
Definition ioplib.c:17
void * ioplib_hookExportEntry(iop_library_t *lib, unsigned int entry, void *func)
hook an IRX Module exported function
Definition ioplib.c:61