PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
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"
16IRX_ID(MODNAME, 1, 1);
17// Based on the module from DVD Player 3.11.
18
19typedef 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
28typedef struct erom_info_
29{
30 const void *m_erom_start;
31 const erom_dentry_t *m_erom_dentry_start;
33
34typedef 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
45static int erom_op_close(iop_file_t *f);
46static int erom_op_lseek(iop_file_t *f, int pos, int mode);
47static int erom_op_open(iop_file_t *f, const char *name, int mode);
48static int erom_op_read(iop_file_t *f, void *ptr, int size);
49static int get_val_from_hash0(u32 obfval);
50static int get_val_from_hash1(u32 obfval);
51static erom_info_t *get_erom_info(const u32 *erom_start, const u32 *erom_end, erom_info_t *info);
52static const erom_dentry_t *get_direntry_by_name(erom_info_t *info, const char *name);
53
54IOMAN_RETURN_VALUE_IMPL(0);
55IOMAN_RETURN_VALUE_IMPL(EIO);
56
57static 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
77static iop_device_t erom_dev = {
78 "erom",
79 IOP_DT_FS,
80 1u,
81 "",
82 &erom_devops,
83};
84
85static erom_fdpriv_t erom_fdpriv;
86static erom_info_t erom_info;
87static const erom_dentry_t *erom_dentry;
88
89static 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
98static 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
124int _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
153static 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
187static 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
252static 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
286static 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
307static 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
326static 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
364const 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}
#define ENOENT
Definition errno.h:23
#define ENXIO
Definition errno.h:31
#define EINVAL
Definition errno.h:63
#define ENOMEM
Definition errno.h:43
#define EIO
Definition errno.h:29
#define EBADF
Definition errno.h:37
int CpuResumeIntr(int state)
Definition intrman.c:227
int CpuSuspendIntr(int *state)
Definition intrman.c:205
void * privdata
Definition ioman.h:61
int unit
Definition ioman.h:57