sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
ioman_sbv.c
Go to the documentation of this file.
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
7# Copyright (c) 2004 adresd <adresd_ps2dev@yahoo.com>
8# Licenced under Academic Free License version 2.0
9# Review ps2sdk README & LICENSE files for further details.
10*/
11
16
17#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
18#include <stdarg.h>
19
20#include "types.h"
21#include "defs.h"
22#include "loadcore.h"
23#include "iomanX.h"
24#include "sysclib.h"
25
26#include "errno.h"
27
28// define this to hook all IOMAN exports instead of just AddDrv and DelDrv
29#define FULL_IOMAN
30
31#define MAX_DEVICES 32
32#define MAX_FILES 32
33
34iomanX_iop_device_t **dev_list;
35extern iomanX_iop_file_t file_table[MAX_FILES];
36
37static const char *ioman_modname = "IO/File_Manager";
38
39static int smod_get_next_mod(ModuleInfo_t *cur_mod, ModuleInfo_t *next_mod)
40{
41 void *addr;
42
43 /* If cur_mod is 0, return the head of the list (IOP address 0x800). */
44 if (!cur_mod) {
45 addr = GetLoadcoreInternalData()->image_info;
46 } else {
47 if (!cur_mod->next)
48 return 0;
49 else
50 addr = cur_mod->next;
51 }
52
53 memcpy(next_mod, addr, sizeof(ModuleInfo_t));
54 return next_mod->id;
55}
56
57static int smod_get_mod_by_name(const char *name, ModuleInfo_t *info)
58{
59 int len = strlen(name) + 1; /* Thanks to adresd for this fix. */
60
61 if (!smod_get_next_mod(NULL, info))
62 return 0;
63
64 do {
65 if (!memcmp(info->name, name, len))
66 return info->id;
67 } while (smod_get_next_mod(info, info) != 0);
68
69 return 0;
70}
71
72void fix_imports(iop_library_t *lib)
73{
74 struct irx_import_table *table;
75 struct irx_import_stub *stub;
76
77 FlushDcache();
78
79 // go through each table that imports the library
80 for(table = lib->caller; table != NULL; table = table->next)
81 {
82 // go through each import in the table
83 for(stub = (struct irx_import_stub *) table->stubs; stub->jump != 0; stub++)
84 {
85 // patch the stub to jump to the address specified in the library export table for "fno"
86 stub->jump = 0x08000000 | (((u32) lib->exports[stub->fno] << 4) >> 6);
87 }
88 }
89
90 FlushIcache();
91}
92
93static u32 *ioman_exports;
94
95#ifndef FULL_IOMAN
96static u32 Addr_IOMAN_AddDrv = 0;
97static u32 Addr_IOMAN_DelDrv = 0;
98#endif
99
100#ifndef FULL_IOMAN
101
102/* This is called by a module wanting to add a device to legacy ioman. */
103static int sbv_AddDrv(iomanX_iop_device_t *device)
104{
105 int res;
106
107 /* We get first dibs! */
108 res = AddDrv(device);
109
110 if (Addr_IOMAN_AddDrv)
111 return(((int (*)(iomanX_iop_device_t *device)) (Addr_IOMAN_AddDrv))(device));
112
113 return res;
114}
115
116/* This is called by a module wanting to delete a device from legacy ioman. */
117static int sbv_DelDrv(const char *name)
118{
119 int res;
120
121 res = DelDrv(name);
122
123 if (Addr_IOMAN_DelDrv)
124 return(((int (*)(const char *name)) (Addr_IOMAN_DelDrv))(name));
125
126 return res;
127}
128#endif
129
130#ifdef FULL_IOMAN
131
132// legacy ioman open and mkdir calls do not specify
133// the "mode" arg. use default of 0644 for open and 0755 for mkdir.
134
135int ioman_open(const char *name, u32 flags)
136{
137 return(iomanX_open(name, flags, 0644));
138}
139
140int ioman_mkdir(const char *name)
141{
142 return(iomanX_mkdir(name, 0755));
143}
144
145// legacy format only takes one arg
146int ioman_format(const char *dev)
147{
148 return(iomanX_format(dev, NULL, NULL, 0));
149}
150
151iomanX_iop_file_t *get_file(int fd);
152
153int mode2modex(int mode);
154int modex2mode(int mode);
155
156static void statx2stat(iox_stat_t *iox_stat, io_stat_t* stat)
157{
158 stat->mode = modex2mode(iox_stat->mode);
159 stat->attr = iox_stat->attr;
160 stat->size = iox_stat->size;
161 memcpy(stat->ctime, iox_stat->ctime, sizeof(iox_stat->ctime));
162 memcpy(stat->atime, iox_stat->atime, sizeof(iox_stat->atime));
163 memcpy(stat->mtime, iox_stat->mtime, sizeof(iox_stat->mtime));
164 stat->hisize = iox_stat->hisize;
165}
166
167static void stat2statx(io_stat_t* stat, iox_stat_t *iox_stat)
168{
169 iox_stat->mode = mode2modex(stat->mode);
170 iox_stat->attr = stat->attr;
171 iox_stat->size = stat->size;
172 memcpy(iox_stat->ctime, stat->ctime, sizeof(stat->ctime));
173 memcpy(iox_stat->atime, stat->atime, sizeof(stat->atime));
174 memcpy(iox_stat->mtime, stat->mtime, sizeof(stat->mtime));
175 iox_stat->hisize = stat->hisize;
176}
177
178int ioman_dread(int fd, io_dirent_t *io_dirent)
179{
180 iomanX_iop_file_t *f = get_file(fd);
181 int res;
182
183 if (f == NULL || !(f->mode & 8))
184 return -EBADF;
185
186 /* If this is a new device (such as pfs:) then we need to convert the mode
187 variable of the stat structure to ioman's format. */
188 if ((f->device->type & 0xf0000000) == IOP_DT_FSEXT)
189 {
190 iox_dirent_t iox_dirent;
191 res = f->device->ops->dread(f, &iox_dirent);
192
193 statx2stat(&iox_dirent.stat, &io_dirent->stat);
194
195 strncpy(io_dirent->name, iox_dirent.name, sizeof(iox_dirent.name));
196 }
197 else
198 {
199 typedef int io_dread_t(iomanX_iop_file_t *, io_dirent_t *);
200 io_dread_t *io_dread = (io_dread_t*) f->device->ops->dread;
201 res = io_dread(f, io_dirent);
202 }
203
204 return res;
205}
206
207int ioman_getstat(const char *name, io_stat_t *stat)
208{
209 iox_stat_t iox_stat;
210 int res = iomanX_getstat(name, &iox_stat);
211 if (res == 0)
212 statx2stat(&iox_stat, stat);
213 return res;
214}
215
216int ioman_chstat(const char *name, io_stat_t *stat, unsigned int mask)
217{
218 iox_stat_t iox_stat;
219 stat2statx(stat, &iox_stat);
220 return iomanX_chstat(name, &iox_stat, mask);
221}
222
223#endif
224
225extern struct irx_export_table _exp_ioman;
226
227int hook_ioman(void)
228{
229 iop_library_t ioman_library = { NULL, NULL, 0x102, 0, "ioman\0\0" };
230 ModuleInfo_t info;
231
232 /* If we already hooked, don't hook again */
233 if (ioman_exports)
234 return -1;
235
236 /* Query if ioman libary exists, otherwise register our own */
237 /* By having a higher version, libraries will relink to the new entry table in RegisterLibraryEntries. */
238 if (!smod_get_mod_by_name(ioman_modname, &info) || !(ioman_exports = (u32 *)QueryLibraryEntryTable(&ioman_library)))
239 {
240 int ret;
241 u16 old_version;
242
243 old_version = _exp_ioman.version;
244 _exp_ioman.version |= 0xFF;
245 ret = RegisterLibraryEntries(&_exp_ioman);
246 _exp_ioman.version = old_version;
247 return ret;
248 }
249
250 // patch the IOMAN export library table to call iomanX functions
251#ifdef FULL_IOMAN
252 /* Replace ioman library entries with our updated ones. */
253 /* By having a higher version, libraries will relink to the new entry table in RegisterLibraryEntries. */
254 {
255 int ret;
256 u16 old_version;
257
258 old_version = _exp_ioman.version;
259 _exp_ioman.version |= 0xFF;
260 ret = RegisterLibraryEntries(&_exp_ioman);
261 _exp_ioman.version = old_version;
262 if ( ret )
263 return ret;
264 }
265 /* Prepare the old table for restoration inside unhook_ioman. */
266 ReleaseLibraryEntries((struct irx_export_table *) (((uiptr) ioman_exports) - 0x14));
267#else
268 /* Preserve ioman's library exports. */
269 Addr_IOMAN_AddDrv = ioman_exports[20];
270 Addr_IOMAN_DelDrv = ioman_exports[21];
271
272 ioman_exports[20] = (u32) sbv_AddDrv;
273 ioman_exports[21] = (u32) sbv_DelDrv;
274
275 /* repair all the tables that import the ioman library */
276 fix_imports((iop_library_t *)(((uiptr) ioman_exports) - 0x14));
277#endif
278
279 dev_list = iomanX_GetDeviceList();
280 /* steal the original IOMAN's 16 registered device entries */
281 memcpy(dev_list, (void *) (info.text_start + info.text_size + info.data_size + 0x10), sizeof(iomanX_iop_device_t *) * 16);
282#ifdef FULL_IOMAN
283 /* ... and clear the original so they don't get double-deinitialized */
284 memset((void *) (info.text_start + info.text_size + info.data_size + 0x10), 0, sizeof(iomanX_iop_device_t *) * 16);
285#endif
286
287 /* steal the original IOMAN's 16 file descriptors */
288 memcpy(file_table, (void *) (info.text_start + info.text_size + info.data_size + 0x50), sizeof(iomanX_iop_file_t) * 16);
289#ifdef FULL_IOMAN
290 /* ... and clear the original so they don't get double-deinitialized */
291 memset((void *) (info.text_start + info.text_size + info.data_size + 0x50), 0, sizeof(iomanX_iop_file_t) * 16);
292#endif
293
294 return 0;
295}
296
297int unhook_ioman(void)
298{
299#ifdef FULL_IOMAN
300 if (ioman_exports)
301 {
302 ReleaseLibraryEntries(&_exp_ioman);
303 RegisterLibraryEntries((struct irx_export_table *) (((uiptr) ioman_exports) - 0x14));
304 }
305#else
306 if (!ioman_exports)
307 return -2;
308 /* Restore ioman's library exports. */
309 ioman_exports[20] = Addr_IOMAN_AddDrv;
310 ioman_exports[21] = Addr_IOMAN_DelDrv;
311
312 // repair all the tables that import the ioman library
313 fix_imports((iop_library_t *) (((uiptr) ioman_exports) - 0x14));
314#endif
315 ioman_exports = NULL;
316
317 return 0;
318}
319#endif
#define EBADF
Definition errno.h:46
ModuleInfo_t * smod_get_next_mod(ModuleInfo_t *cur_mod)
Definition smod.c:39
ModuleInfo_t * smod_get_mod_by_name(const char *name)
Definition smod.c:63
int iomanX_format(const char *dev, const char *blockdev, void *arg, int arglen)
Definition iomanX.c:710
struct _iomanX_iop_file iomanX_iop_file_t
#define IOP_DT_FSEXT
Definition iomanX.h:67
struct _ModuleInfo ModuleInfo_t
struct _iomanX_iop_device * device
Definition iomanX.h:77
Definition main.c:40