PS2SDK
PS2 Homebrew Libraries
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 
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 
34 iomanX_iop_device_t **dev_list;
35 extern iomanX_iop_file_t file_table[MAX_FILES];
36 
37 static const char *ioman_modname = "IO/File_Manager";
38 
39 static 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 
57 static 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 
72 void 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 
93 static u32 *ioman_exports;
94 
95 static u32 Addr_IOMAN_open = 0;
96 static u32 Addr_IOMAN_close = 0;
97 static u32 Addr_IOMAN_read = 0;
98 static u32 Addr_IOMAN_write = 0;
99 static u32 Addr_IOMAN_lseek = 0;
100 static u32 Addr_IOMAN_ioctl = 0;
101 static u32 Addr_IOMAN_remove = 0;
102 static u32 Addr_IOMAN_mkdir = 0;
103 static u32 Addr_IOMAN_rmdir = 0;
104 static u32 Addr_IOMAN_dopen = 0;
105 static u32 Addr_IOMAN_dclose = 0;
106 static u32 Addr_IOMAN_dread = 0;
107 static u32 Addr_IOMAN_getstat = 0;
108 static u32 Addr_IOMAN_chstat = 0;
109 static u32 Addr_IOMAN_format = 0;
110 
111 static u32 Addr_IOMAN_AddDrv = 0;
112 static u32 Addr_IOMAN_DelDrv = 0;
113 
114 #ifndef FULL_IOMAN
115 
116 /* This is called by a module wanting to add a device to legacy ioman. */
117 static int sbv_AddDrv(iomanX_iop_device_t *device)
118 {
119  int res;
120 
121  /* We get first dibs! */
122  res = AddDrv(device);
123 
124  if (Addr_IOMAN_AddDrv)
125  return(((int (*)(iomanX_iop_device_t *device)) (Addr_IOMAN_AddDrv))(device));
126 
127  return res;
128 }
129 
130 /* This is called by a module wanting to delete a device from legacy ioman. */
131 static int sbv_DelDrv(const char *name)
132 {
133  int res;
134 
135  res = DelDrv(name);
136 
137  if (Addr_IOMAN_DelDrv)
138  return(((int (*)(const char *name)) (Addr_IOMAN_DelDrv))(name));
139 
140  return res;
141 }
142 #endif
143 
144 #ifdef FULL_IOMAN
145 
146 // legacy ioman open and mkdir calls do not specify
147 // the "mode" arg. use default of 0644 for open and 0755 for mkdir.
148 
149 int ioman_open(const char *name, u32 flags)
150 {
151  return(iomanX_open(name, flags, 0644));
152 }
153 
154 int ioman_mkdir(const char *name)
155 {
156  return(iomanX_mkdir(name, 0755));
157 }
158 
159 // legacy format only takes one arg
160 int ioman_format(const char *dev)
161 {
162  return(iomanX_format(dev, NULL, NULL, 0));
163 }
164 
165 iomanX_iop_file_t *get_file(int fd);
166 
167 int mode2modex(int mode);
168 int modex2mode(int mode);
169 
170 static void statx2stat(iox_stat_t *iox_stat, io_stat_t* stat)
171 {
172  stat->mode = modex2mode(iox_stat->mode);
173  stat->attr = iox_stat->attr;
174  stat->size = iox_stat->size;
175  memcpy(stat->ctime, iox_stat->ctime, sizeof(iox_stat->ctime));
176  memcpy(stat->atime, iox_stat->atime, sizeof(iox_stat->atime));
177  memcpy(stat->mtime, iox_stat->mtime, sizeof(iox_stat->mtime));
178  stat->hisize = iox_stat->hisize;
179 }
180 
181 static void stat2statx(io_stat_t* stat, iox_stat_t *iox_stat)
182 {
183  iox_stat->mode = mode2modex(stat->mode);
184  iox_stat->attr = stat->attr;
185  iox_stat->size = stat->size;
186  memcpy(iox_stat->ctime, stat->ctime, sizeof(stat->ctime));
187  memcpy(iox_stat->atime, stat->atime, sizeof(stat->atime));
188  memcpy(iox_stat->mtime, stat->mtime, sizeof(stat->mtime));
189  iox_stat->hisize = stat->hisize;
190 }
191 
192 int ioman_dread(int fd, io_dirent_t *io_dirent)
193 {
194  iomanX_iop_file_t *f = get_file(fd);
195  int res;
196 
197  if (f == NULL || !(f->mode & 8))
198  return -EBADF;
199 
200  /* If this is a new device (such as pfs:) then we need to convert the mode
201  variable of the stat structure to ioman's format. */
202  if ((f->device->type & 0xf0000000) == IOP_DT_FSEXT)
203  {
204  iox_dirent_t iox_dirent;
205  res = f->device->ops->dread(f, &iox_dirent);
206 
207  statx2stat(&iox_dirent.stat, &io_dirent->stat);
208 
209  strncpy(io_dirent->name, iox_dirent.name, sizeof(iox_dirent.name));
210  }
211  else
212  {
213  typedef int io_dread_t(iomanX_iop_file_t *, io_dirent_t *);
214  io_dread_t *io_dread = (io_dread_t*) f->device->ops->dread;
215  res = io_dread(f, io_dirent);
216  }
217 
218  return res;
219 }
220 
221 int ioman_getstat(const char *name, io_stat_t *stat)
222 {
223  iox_stat_t iox_stat;
224  int res = iomanX_getstat(name, &iox_stat);
225  if (res == 0)
226  statx2stat(&iox_stat, stat);
227  return res;
228 }
229 
230 int ioman_chstat(const char *name, io_stat_t *stat, unsigned int mask)
231 {
232  iox_stat_t iox_stat;
233  stat2statx(stat, &iox_stat);
234  return iomanX_chstat(name, &iox_stat, mask);
235 }
236 
237 #endif
238 
239 int hook_ioman(void)
240 {
241  iop_library_t ioman_library = { NULL, NULL, 0x102, 0, "ioman\0\0" };
243 
244  dev_list = iomanX_GetDeviceList();
245 
246  if (smod_get_mod_by_name(ioman_modname, &info))
247  {
248  // steal the original IOMAN's 16 registered device entries
249  memcpy(dev_list, (void *) (info.text_start + info.text_size + info.data_size + 0x10), sizeof(iomanX_iop_device_t *) * 16);
250 
251  // steal the original IOMAN's 16 file descriptors
252  memcpy(file_table, (void *) (info.text_start + info.text_size + info.data_size + 0x50), sizeof(iomanX_iop_file_t) * 16);
253  }
254  else { return(-1); }
255 
256  // patch the IOMAN export library table to call iomanX functions
257  if ((ioman_exports = (u32 *)QueryLibraryEntryTable(&ioman_library)) != NULL)
258  {
259  /* Preserve ioman's library exports. */
260  Addr_IOMAN_open = ioman_exports[4];
261  Addr_IOMAN_close = ioman_exports[5];
262  Addr_IOMAN_read = ioman_exports[6];
263  Addr_IOMAN_write = ioman_exports[7];
264  Addr_IOMAN_lseek = ioman_exports[8];
265  Addr_IOMAN_ioctl = ioman_exports[9];
266  Addr_IOMAN_remove = ioman_exports[10];
267  Addr_IOMAN_mkdir = ioman_exports[11];
268  Addr_IOMAN_rmdir = ioman_exports[12];
269  Addr_IOMAN_dopen = ioman_exports[13];
270  Addr_IOMAN_dclose = ioman_exports[14];
271  Addr_IOMAN_dread = ioman_exports[15];
272  Addr_IOMAN_getstat = ioman_exports[16];
273  Addr_IOMAN_chstat = ioman_exports[17];
274  Addr_IOMAN_format = ioman_exports[18];
275  Addr_IOMAN_AddDrv = ioman_exports[20];
276  Addr_IOMAN_DelDrv = ioman_exports[21];
277 
278 #ifdef FULL_IOMAN
279  ioman_exports[4] = (u32) ioman_open;
280  ioman_exports[5] = (u32) iomanX_close;
281  ioman_exports[6] = (u32) iomanX_read;
282  ioman_exports[7] = (u32) iomanX_write;
283  ioman_exports[8] = (u32) iomanX_lseek;
284  ioman_exports[9] = (u32) iomanX_ioctl;
285  ioman_exports[10] = (u32) iomanX_remove;
286  ioman_exports[11] = (u32) ioman_mkdir;
287  ioman_exports[12] = (u32) iomanX_rmdir;
288  ioman_exports[13] = (u32) iomanX_dopen;
289  ioman_exports[14] = (u32) iomanX_close;
290  ioman_exports[15] = (u32) ioman_dread;
291  ioman_exports[16] = (u32) ioman_getstat;
292  ioman_exports[17] = (u32) ioman_chstat;
293  ioman_exports[18] = (u32) ioman_format;
294  ioman_exports[20] = (u32) iomanX_AddDrv;
295  ioman_exports[21] = (u32) iomanX_DelDrv;
296 #else
297  ioman_exports[20] = (u32) sbv_AddDrv;
298  ioman_exports[21] = (u32) sbv_DelDrv;
299 #endif
300 
301  // repair all the tables that import the ioman library
302  fix_imports((iop_library_t *) (((u32) ioman_exports) - 0x14));
303  }
304  else { return(-2); }
305 
306  return(0);
307 }
308 
309 int unhook_ioman()
310 {
311  int i;
312 
313  dev_list = iomanX_GetDeviceList();
314 
315  /* Remove all registered devices. */
316  for (i = 0; i < MAX_DEVICES; i++) {
317  if (dev_list[i] != NULL) {
318  dev_list[i]->ops->deinit(dev_list[i]);
319  dev_list[i] = NULL;
320  }
321  }
322 
323  /* Restore ioman's library exports. */
324  ioman_exports[4] = Addr_IOMAN_open;
325  ioman_exports[5] = Addr_IOMAN_close;
326  ioman_exports[6] = Addr_IOMAN_read;
327  ioman_exports[7] = Addr_IOMAN_write;
328  ioman_exports[8] = Addr_IOMAN_lseek;
329  ioman_exports[9] = Addr_IOMAN_ioctl;
330  ioman_exports[10] = Addr_IOMAN_remove;
331  ioman_exports[11] = Addr_IOMAN_mkdir;
332  ioman_exports[12] = Addr_IOMAN_rmdir;
333  ioman_exports[13] = Addr_IOMAN_dopen;
334  ioman_exports[14] = Addr_IOMAN_dclose;
335  ioman_exports[15] = Addr_IOMAN_dread;
336  ioman_exports[16] = Addr_IOMAN_getstat;
337  ioman_exports[17] = Addr_IOMAN_chstat;
338  ioman_exports[18] = Addr_IOMAN_format;
339 
340  ioman_exports[20] = Addr_IOMAN_AddDrv;
341  ioman_exports[21] = Addr_IOMAN_DelDrv;
342 
343  // repair all the tables that import the ioman library
344  fix_imports((iop_library_t *) (((u32) ioman_exports) - 0x14));
345 
346  return 0;
347 }
348 #endif
iomanX.h
_iomanX_iop_file::device
struct _iomanX_iop_device * device
Definition: iomanX.h:76
iox_stat_t
Definition: iox_stat.h:92
IOP_DT_FSEXT
#define IOP_DT_FSEXT
Definition: iomanX.h:66
_iomanX_iop_file
Definition: iomanX.h:70
sysclib.h
smod_get_mod_by_name
int smod_get_mod_by_name(const char *name, smod_mod_info_t *info)
Definition: smod.c:54
s_info
Definition: xprintf.c:78
loadcore.h
_iop_library
Definition: loadcore.h:68
_iomanX_iop_file::mode
int mode
Definition: iomanX.h:72
_iomanX_iop_device
Definition: iomanX.h:81
io_stat_t
Definition: io_common.h:47
EBADF
#define EBADF
Definition: errno.h:37
iox_dirent_t
Definition: iox_stat.h:111
io_dirent_t
Definition: io_common.h:58
iomanX_format
int iomanX_format(const char *dev, const char *blockdev, void *arg, int arglen)
Definition: iomanX.c:708
defs.h
irx_import_table
Definition: irx.h:42
_ModuleInfo
Definition: loadcore.h:31
irx_import_stub
Definition: irx.h:52
tag_LC_internals::image_info
ModuleInfo_t * image_info
Definition: loadcore.h:82
errno.h
smod_get_next_mod
int smod_get_next_mod(smod_mod_info_t *cur_mod, smod_mod_info_t *next_mod)
Definition: smod.c:30