PS2SDK
PS2 Homebrew Libraries
eromdrv.c
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 */
10 
11 #include <errno.h>
12 #include <irx_imports.h>
13 #include <loadcore.h>
14 
15 #define MODNAME "erom_file_driver"
16 IRX_ID(MODNAME, 1, 1);
17 // Based on the module from DVD Player 3.11.
18 
19 typedef struct erom_dentry_
20 {
21  u32 m_filename_hash;
22  u32 m_fileoffset_hash;
23  u32 m_filesize_hash;
24  u32 m_next_fileoffset_hash;
25  u32 m_xordata_size_hash;
27 
28 typedef struct erom_info_
29 {
30  const void *m_erom_start;
31  const erom_dentry_t *m_erom_dentry_start;
32 } erom_info_t;
33 
34 typedef struct erom_fdpriv_
35 {
36  int m_unused0;
37  int m_cur_offset;
38  int m_magic8;
39  void *m_file_offset;
40  u32 m_file_size;
41  void *m_xordata_offset;
42  u32 m_xordata_size;
44 
45 static int erom_op_close(iop_file_t *f);
46 static int erom_op_lseek(iop_file_t *f, int pos, int mode);
47 static int erom_op_open(iop_file_t *f, const char *name, int mode);
48 static int erom_op_read(iop_file_t *f, void *ptr, int size);
49 static int get_val_from_hash0(u32 obfval);
50 static int get_val_from_hash1(u32 obfval);
51 static erom_info_t *get_erom_info(const u32 *erom_start, const u32 *erom_end, erom_info_t *info);
52 static const erom_dentry_t *get_direntry_by_name(erom_info_t *info, const char *name);
53 
54 IOMAN_RETURN_VALUE_IMPL(0);
55 IOMAN_RETURN_VALUE_IMPL(EIO);
56 
57 static iop_device_ops_t erom_devops = {
58  IOMAN_RETURN_VALUE(0), // init
59  IOMAN_RETURN_VALUE(0), // deinit
60  IOMAN_RETURN_VALUE(0), // format
61  &erom_op_open, // open
62  &erom_op_close, // close
63  &erom_op_read, // read
64  IOMAN_RETURN_VALUE(EIO), // write
65  &erom_op_lseek, // lseek
66  IOMAN_RETURN_VALUE(0), // ioctl
67  IOMAN_RETURN_VALUE(0), // remove
68  IOMAN_RETURN_VALUE(0), // mkdir
69  IOMAN_RETURN_VALUE(0), // rmdir
70  IOMAN_RETURN_VALUE(0), // dopen
71  IOMAN_RETURN_VALUE(0), // dclose
72  IOMAN_RETURN_VALUE(0), // dread
73  IOMAN_RETURN_VALUE(0), // getstat
74  IOMAN_RETURN_VALUE(0), // chstat
75 };
76 
77 static iop_device_t erom_dev = {
78  "erom",
79  IOP_DT_FS,
80  1u,
81  "",
82  &erom_devops,
83 };
84 
85 static erom_fdpriv_t erom_fdpriv;
86 static erom_info_t erom_info;
87 static const erom_dentry_t *erom_dentry;
88 
89 static int erom_op_close(iop_file_t *f)
90 {
91  (void)f;
92  if ( !erom_dentry )
93  return -EBADF;
94  erom_dentry = NULL;
95  return 0;
96 }
97 
98 static int erom_op_lseek(iop_file_t *f, int pos, int mode)
99 {
100  erom_fdpriv_t *privdata;
101  int offs_relative;
102  u32 pos_plus_curpos;
103 
104  privdata = (erom_fdpriv_t *)f->privdata;
105  switch ( mode )
106  {
107  case FIO_SEEK_SET:
108  offs_relative = 0;
109  break;
110  case FIO_SEEK_CUR:
111  offs_relative = privdata->m_cur_offset;
112  break;
113  case FIO_SEEK_END:
114  offs_relative = privdata->m_file_size;
115  break;
116  default:
117  return -EINVAL;
118  }
119  pos_plus_curpos = pos + offs_relative;
120  privdata->m_cur_offset = (privdata->m_file_size >= pos_plus_curpos) ? pos_plus_curpos : privdata->m_file_size;
121  return privdata->m_cur_offset;
122 }
123 
124 int _start(int ac, char **av)
125 {
126  int dev1_address;
127  int dev1_delay;
128  int has_erom;
129 
130  (void)ac;
131  (void)av;
132 
133  dev1_address = *((vu32 *)0xBF801400);
134  dev1_delay = *((vu32 *)0xBF80100C);
135  *((vu32 *)0xBF801400) = 0xBE000000;
136  *((vu32 *)0xBF80100C) = 0x18344F;
137  has_erom = get_erom_info((u32 *)0xBE080000, (u32 *)0xBE080400, &erom_info) != 0;
138  if ( !has_erom )
139  {
140  *((vu32 *)0xBF80100C) = 0x18244F;
141  has_erom = get_erom_info((u32 *)0xBE080000, (u32 *)0xBE080400, &erom_info) != 0;
142  }
143  if ( !has_erom )
144  {
145  *((vu32 *)0xBF80100C) = dev1_delay;
146  *((vu32 *)0xBF801400) = dev1_address;
147  return MODULE_NO_RESIDENT_END;
148  }
149  DelDrv(erom_dev.name);
150  return (AddDrv(&erom_dev) < 0) ? MODULE_NO_RESIDENT_END : MODULE_RESIDENT_END;
151 }
152 
153 static int erom_op_open(iop_file_t *f, const char *name, int mode)
154 {
155  int state;
156 
157  (void)mode;
158  if ( f->unit || !erom_info.m_erom_start )
159  return -ENXIO;
160  while ( *name == '@' || *name == '&' )
161  {
162  erom_fdpriv.m_magic8 ^= 1u;
163  name += 1;
164  }
165  CpuSuspendIntr(&state);
166  if ( erom_dentry != NULL )
167  {
168  CpuResumeIntr(state);
169  return -ENOMEM;
170  }
171  erom_dentry = get_direntry_by_name(&erom_info, name);
172  CpuResumeIntr(state);
173  if ( erom_dentry == NULL )
174  {
175  return -ENOENT;
176  }
177  erom_fdpriv.m_unused0 = 0;
178  erom_fdpriv.m_cur_offset = 0;
179  erom_fdpriv.m_file_offset = (u8 *)erom_info.m_erom_start + get_val_from_hash0(erom_dentry->m_fileoffset_hash);
180  erom_fdpriv.m_xordata_size = 4 * get_val_from_hash0(erom_dentry->m_xordata_size_hash);
181  erom_fdpriv.m_xordata_offset = (u8 *)erom_fdpriv.m_file_offset - erom_fdpriv.m_xordata_size;
182  erom_fdpriv.m_file_size = get_val_from_hash1(erom_dentry->m_filesize_hash) & 0xFFFFFF;
183  f->privdata = &erom_fdpriv;
184  return 0;
185 }
186 
187 static int erom_op_read(iop_file_t *f, void *ptr, int size)
188 {
189  int size_tmp;
190  erom_fdpriv_t *privdata;
191  int filesize_tmp;
192  int m_cur_offset;
193  int m_file_size;
194  int m_xordata_size;
195  u8 *dstptr;
196 
197  dstptr = (u8 *)ptr;
198  privdata = (erom_fdpriv_t *)f->privdata;
199  if ( size < 0 )
200  return -EINVAL;
201  m_cur_offset = privdata->m_cur_offset;
202  m_file_size = privdata->m_file_size;
203  size_tmp = (m_file_size - m_cur_offset < size) ? m_file_size - m_cur_offset : size;
204  if ( size_tmp <= 0 )
205  {
206  return size_tmp;
207  }
208  m_xordata_size = privdata->m_xordata_size;
209  filesize_tmp = m_xordata_size - m_cur_offset;
210  if ( filesize_tmp > 0 )
211  {
212  u8 *srcptr;
213  u8 *srcptr_end;
214 
215  if ( filesize_tmp > size_tmp )
216  filesize_tmp = size_tmp;
217  memcpy(dstptr, (u8 *)privdata->m_xordata_offset + m_cur_offset, filesize_tmp);
218  srcptr = (u8 *)privdata->m_file_offset + privdata->m_cur_offset;
219  srcptr_end = srcptr + filesize_tmp;
220  if ( ((uiptr)dstptr & 3) == ((uiptr)srcptr & 3) )
221  {
222  while ( ((uiptr)srcptr & 3) != 0 )
223  {
224  *dstptr ^= *srcptr;
225  dstptr += 1;
226  srcptr += 1;
227  }
228  while ( (uiptr)srcptr < ((uiptr)srcptr_end & (~3)) )
229  {
230  *(u32 *)dstptr ^= *(u32 *)srcptr;
231  srcptr += 4;
232  dstptr += 4;
233  }
234  }
235  while ( srcptr < srcptr_end )
236  {
237  *dstptr ^= *(u8 *)srcptr;
238  dstptr += 1;
239  srcptr += 1;
240  }
241  size_tmp -= filesize_tmp;
242  privdata->m_cur_offset += filesize_tmp;
243  }
244  if ( size_tmp > 0 )
245  {
246  memcpy(dstptr, (u8 *)privdata->m_file_offset + privdata->m_cur_offset, size_tmp);
247  privdata->m_cur_offset += size_tmp;
248  }
249  return size_tmp + filesize_tmp;
250 }
251 
252 static u32 get_string_hash(const char *name)
253 {
254  int ret;
255  int i;
256  char nametmp[6];
257 
258  ret = 0;
259  strncpy(nametmp, name, sizeof(nametmp));
260  for ( i = 0; i < (int)(sizeof(nametmp)); i += 1 )
261  {
262  int tmpval1;
263  int tmpval2;
264 
265  tmpval1 = (u8)nametmp[i];
266  tmpval2 = tmpval1 - 64;
267  if ( (u32)(tmpval1 - 65) >= 0xD )
268  {
269  tmpval2 = 14;
270  if ( tmpval1 )
271  {
272  tmpval2 = (u8)tmpval1 - 63;
273  if ( (u8)tmpval1 < 0x4Eu )
274  {
275  tmpval2 = 28;
276  if ( (u8)tmpval1 != 32 )
277  tmpval2 = (u8)tmpval1 - 19;
278  }
279  }
280  }
281  ret = 40 * ret + tmpval2;
282  }
283  return ret;
284 }
285 
286 static int get_val_from_hash0(u32 obfval)
287 {
288  int ret;
289  int i;
290 
291  ret = 0;
292  for ( i = 0; i < 32; i += 4 )
293  {
294  u32 tmpval1;
295  int tmpval2;
296 
297  tmpval1 = obfval % 0x12;
298  tmpval2 = (tmpval1 - 1) << i;
299  if ( tmpval1 - 1 >= 0xA )
300  tmpval2 = (tmpval1 - 2) << i;
301  ret |= tmpval2;
302  obfval /= 0x12u;
303  }
304  return ret;
305 }
306 
307 static int get_val_from_hash1(u32 obfval)
308 {
309  int ret;
310  int i;
311 
312  ret = 0;
313  for ( i = 0; i < 28; i += 4 )
314  {
315  u32 tmpval1;
316 
317  tmpval1 = obfval % 0x13 + 9;
318  if ( obfval % 0x13 - 1 >= 6 )
319  tmpval1 = obfval % 0x13 - 8;
320  ret |= tmpval1 << i;
321  obfval /= 0x13u;
322  }
323  return ret;
324 }
325 
326 static erom_info_t *get_erom_info(const u32 *erom_start, const u32 *erom_end, erom_info_t *info)
327 {
328  int bufcount;
329  u32 *buf;
330  char c;
331  int i;
332  char tmpname[6];
333 
334  bufcount = erom_end - erom_start;
335  memcpy(tmpname, " @ A B", 6);
336  info->m_erom_start = 0;
337  buf = (u32 *)AllocSysMemory(ALLOC_FIRST, bufcount * sizeof(u32), NULL);
338  if ( buf == NULL )
339  return NULL;
340  memcpy(buf, erom_start, bufcount * sizeof(u32));
341  for ( c = 'C'; (u8)c < '['; c += 1 )
342  {
343  u32 string_hash;
344 
345  tmpname[1] = tmpname[3];
346  tmpname[3] = tmpname[5];
347  tmpname[5] = c;
348  string_hash = get_string_hash(tmpname);
349  for ( i = 0; (i < bufcount) && (buf[i] != string_hash); i += 1 )
350  {
351  }
352  if ( i < bufcount )
353  {
354  info->m_erom_start = erom_start;
355  info->m_erom_dentry_start = (const erom_dentry_t *)&erom_start[i];
356  FreeSysMemory(buf);
357  return info;
358  }
359  }
360  FreeSysMemory(buf);
361  return NULL;
362 }
363 
364 const erom_dentry_t *get_direntry_by_name(erom_info_t *info, const char *name)
365 {
366  const erom_dentry_t *res;
367  u32 string_hash;
368 
369  res = info->m_erom_dentry_start;
370  string_hash = get_string_hash(name);
371  while ( res && res->m_filename_hash != string_hash )
372  {
373  int val_from_hash0;
374 
375  val_from_hash0 = get_val_from_hash0(res->m_next_fileoffset_hash);
376  res = val_from_hash0 ? (const erom_dentry_t *)((u8 *)info->m_erom_start + val_from_hash0) : NULL;
377  }
378  return res;
379 }
_iop_file::privdata
void * privdata
Definition: ioman.h:61
ENOMEM
#define ENOMEM
Definition: errno.h:43
s_info
Definition: xprintf.c:78
ENXIO
#define ENXIO
Definition: errno.h:31
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
EIO
#define EIO
Definition: errno.h:29
loadcore.h
ENOENT
#define ENOENT
Definition: errno.h:23
erom_info_
Definition: eromdrv.c:28
_iop_file::unit
int unit
Definition: ioman.h:57
_iop_file
Definition: ioman.h:53
erom_dentry_
Definition: eromdrv.c:19
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
EBADF
#define EBADF
Definition: errno.h:37
_iop_device_ops
Definition: ioman.h:79
EINVAL
#define EINVAL
Definition: errno.h:63
_iop_device
Definition: ioman.h:64
erom_fdpriv_
Definition: eromdrv.c:34
errno.h