PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
romdrv.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright 2001-2004, 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 <intrman.h>
13#include <ioman.h>
14#include <loadcore.h>
15#include <sysclib.h>
16#include <irx.h>
17
18#include "romdrv.h"
19
20IRX_ID("ROM_file_driver", 2, 1);
21
22extern struct irx_export_table _exp_romdrv;
23extern struct irx_export_table _exp_romdrvX;
24
25// Unlike the version used in UDNL, this is only 12-bytes (no padding field).
27{
28 const struct RomDirEntry *romdirent;
29 const void *data;
30 const void *extinfo;
31};
32
34{
35 int slotNum;
36 int offset;
37};
38
39static struct RomImg images[ROMDRV_MAX_IMAGES];
40static struct RomdirFileStat fileStats[ROMDRV_MAX_FILES];
41static struct RomFileSlot fileSlots[ROMDRV_MAX_FILES];
42
43/* Function prototypes */
44static int init(void);
45static int romUnsupported(void);
46static int romInit(iop_device_t *device);
47static int romOpen(iop_file_t *fd, const char *path, int mode);
48static int romClose(iop_file_t *);
49static int romRead(iop_file_t *fd, void *buffer, int size);
50static int romWrite(iop_file_t *fd, void *buffer, int size);
51static int romLseek(iop_file_t *fd, int offset, int whence);
52static struct RomImg *romGetImageStat(const void *start, const void *end, struct RomImg *ImageStat);
53static struct RomdirFileStat *GetFileStatFromImage(const struct RomImg *ImageStat, const char *filename, struct RomdirFileStat *stat);
54
55static iop_device_ops_t ops = {
56 &romInit,
57 (void *)&romUnsupported,
58 (void *)&romUnsupported,
59 &romOpen,
60 &romClose,
61 &romRead,
62 &romWrite,
63 &romLseek,
64 (void *)&romUnsupported,
65 (void *)&romUnsupported,
66 (void *)&romUnsupported,
67 (void *)&romUnsupported,
68 (void *)&romUnsupported,
69 (void *)&romUnsupported,
70 (void *)&romUnsupported,
71 (void *)&romUnsupported,
72 (void *)&romUnsupported};
73
74static iop_device_t DeviceOps = {
75 "rom",
76 IOP_DT_FS,
77 1,
78 "ROM/Flash",
79 &ops};
80
81int _start(int argc, char **argv)
82{
83 (void)argc;
84 (void)argv;
85
86 if (RegisterLibraryEntries(&_exp_romdrv) != 0) {
87 return MODULE_NO_RESIDENT_END;
88 }
89
90#ifdef ROMDRV_EXPORT_DEVICES
91 if (RegisterLibraryEntries(&_exp_romdrvX) != 0) {
92 return MODULE_NO_RESIDENT_END;
93 }
94#endif
95
96 init();
97
98 DelDrv(DeviceOps.name);
99
100 return (AddDrv(&DeviceOps) < 0) ? MODULE_NO_RESIDENT_END : MODULE_RESIDENT_END;
101}
102
103static int init(void)
104{
105 memset(images, 0, sizeof(images));
106 memset(fileStats, 0, sizeof(fileStats));
107 memset(fileSlots, 0, sizeof(fileSlots));
108 // Add DEV2 (Boot ROM) as rom0. Unlike ROMDRV v1.1, the code for DEV1 is in the ADDDRV module.
109 romGetImageStat((const void *)0xbfc00000, (const void *)0xbfc40000, &images[0]);
110 return 0;
111}
112
113static int romUnsupported(void)
114{
115 return 0;
116}
117
118static int romInit(iop_device_t *device)
119{
120 (void)device;
121
122 return 0;
123}
124
125int romAddDevice(int unit, const void *image)
126{
127 int result, OldState;
128 struct RomImg *stat;
129
130 if (unit < ROMDRV_MAX_IMAGES) {
131 CpuSuspendIntr(&OldState);
132
133 if (images[unit].ImageStart == NULL) {
134 stat = romGetImageStat(image, (const void *)((const u8 *)image + 0x8000), &images[unit]);
135 CpuResumeIntr(OldState);
136
137 result = stat != NULL ? 0 : ROMDRV_ADD_BAD_IMAGE;
138 } else {
139 result = ROMDRV_ADD_FAILED;
140 CpuResumeIntr(OldState);
141 }
142 } else {
143 result = ROMDRV_ADD_FAILED;
144 }
145
146 return result;
147}
148
149int romDelDevice(int unit)
150{
151 int result, OldState;
152
153 if (unit < ROMDRV_MAX_IMAGES) {
154 CpuSuspendIntr(&OldState);
155
156 if (images[unit].ImageStart != NULL) {
157 images[unit].ImageStart = 0;
158 CpuResumeIntr(OldState);
159 result = 0;
160 } else {
161 CpuResumeIntr(OldState);
162 result = ROMDRV_DEL_FAILED;
163 }
164 } else {
165 result = ROMDRV_DEL_FAILED;
166 }
167
168 return result;
169}
170
171static int romOpen(iop_file_t *fd, const char *path, int mode)
172{
173 int OldState;
174
175 if (fd->unit < ROMDRV_MAX_IMAGES) {
176 struct RomImg *image;
177
178 image = &images[fd->unit];
179
180 if (image->ImageStart != NULL) {
181 int slotNum, result;
182 struct RomdirFileStat *stat;
183
184 if (mode != O_RDONLY) {
185 return -EACCES;
186 }
187
188 CpuSuspendIntr(&OldState);
189
190 // Locate a free file slot.
191 for (slotNum = 0; slotNum < ROMDRV_MAX_FILES; slotNum++) {
192 if (fileStats[slotNum].data == NULL) {
193 break;
194 }
195 }
196 if (slotNum == ROMDRV_MAX_FILES) {
197 CpuResumeIntr(OldState);
198 return -ENOMEM;
199 }
200
201 stat = GetFileStatFromImage(image, path, &fileStats[slotNum]);
202 CpuResumeIntr(OldState);
203
204 if (stat != NULL) {
205 result = 0;
206 fileSlots[slotNum].slotNum = slotNum;
207 fileSlots[slotNum].offset = 0;
208 fd->privdata = &fileSlots[slotNum];
209 } else {
210 result = -ENOENT;
211 }
212
213 return result;
214 } else {
215 return -ENXIO;
216 }
217 } else {
218 return -ENXIO;
219 }
220}
221
222static int romClose(iop_file_t *fd)
223{
224 struct RomFileSlot *slot = (struct RomFileSlot *)fd->privdata;
225 int result;
226
227 if (slot->slotNum < ROMDRV_MAX_FILES) {
228 struct RomdirFileStat *stat;
229
230 stat = &fileStats[slot->slotNum];
231
232 if (stat->data != NULL) {
233 stat->data = NULL;
234 result = 0;
235 } else {
236 result = -EBADF;
237 }
238 } else {
239 result = -EBADF;
240 }
241
242 return result;
243}
244
245static int romRead(iop_file_t *fd, void *buffer, int size)
246{
247 struct RomFileSlot *slot = (struct RomFileSlot *)fd->privdata;
248 struct RomdirFileStat *stat;
249
250 stat = &fileStats[slot->slotNum];
251
252 // Bounds check.
253 if (stat->romdirent->size < (u32)(slot->offset + size)) {
254 size = stat->romdirent->size - slot->offset;
255 }
256
257 if (size <= 0) // Ignore 0-byte reads.
258 {
259 return 0;
260 }
261
262 memcpy(buffer, (const u8 *)stat->data + slot->offset, size);
263 slot->offset += size;
264
265 return size;
266}
267
268static int romWrite(iop_file_t *fd, void *buffer, int size)
269{
270 (void)fd;
271 (void)buffer;
272 (void)size;
273
274 return -EIO;
275}
276
277static int romLseek(iop_file_t *fd, int offset, int whence)
278{
279 struct RomFileSlot *slot = (struct RomFileSlot *)fd->privdata;
280 struct RomdirFileStat *stat;
281 u32 size;
282 int newOffset;
283
284 stat = &fileStats[slot->slotNum];
285 size = stat->romdirent->size;
286
287 switch (whence) {
288 case SEEK_SET:
289 newOffset = offset;
290 break;
291 case SEEK_CUR:
292 newOffset = slot->offset + offset;
293 break;
294 case SEEK_END:
295 newOffset = size + offset;
296 break;
297 default:
298 return -EINVAL;
299 }
300
301 // Update offset.
302 slot->offset = (size < (u32)newOffset) ? size : (u32)newOffset;
303
304 return slot->offset;
305}
306
307static struct RomImg *romGetImageStat(const void *start, const void *end, struct RomImg *ImageStat)
308{
309 const u32 *ptr;
310 unsigned int offset;
311 const struct RomDirEntry *file;
312 u32 size;
313
314 offset = 0;
315 file = (struct RomDirEntry *)start;
316 for (; file < (const struct RomDirEntry *)end; file++, offset += sizeof(struct RomDirEntry)) {
317 /* Check for a valid ROM filesystem (Magic: "RESET\0\0\0\0\0"). Must have the right magic and bootstrap code size (size of RESET = bootstrap code size). */
318 ptr = (u32 *)file->name;
319 if (ptr[0] == 0x45534552 && ptr[1] == 0x54 && (*(u16 *)&ptr[2] == 0) && (((file->size + 15) & ~15) == offset)) {
320 ImageStat->ImageStart = start;
321 ImageStat->RomdirStart = ptr;
322 size = file[1].size; // Get size of image from ROMDIR (after RESET).
323 ImageStat->RomdirEnd = (const void *)((const u8 *)ptr + size);
324 return ImageStat;
325 }
326 }
327
328 ImageStat->ImageStart = NULL;
329 return NULL;
330}
331
332// Similar to the function from UDNL.
333static struct RomdirFileStat *GetFileStatFromImage(const struct RomImg *ImageStat, const char *filename, struct RomdirFileStat *stat)
334{
335 unsigned int i, offset, ExtInfoOffset;
336 u8 filename_temp[12];
337 const struct RomDirEntry *RomdirEntry;
338 struct RomdirFileStat *result;
339
340 offset = 0;
341 ExtInfoOffset = 0;
342 ((u32 *)filename_temp)[0] = 0;
343 ((u32 *)filename_temp)[1] = 0;
344 ((u32 *)filename_temp)[2] = 0;
345 for (i = 0; *filename >= 0x21 && i < sizeof(filename_temp); i++) {
346 filename_temp[i] = *filename;
347 filename++;
348 }
349
350 if (ImageStat->RomdirStart != NULL) {
351 RomdirEntry = ImageStat->RomdirStart;
352
353 do { // Fast comparison of filenames.
354 if (((u32 *)filename_temp)[0] == ((u32 *)RomdirEntry->name)[0] && ((u32 *)filename_temp)[1] == ((u32 *)RomdirEntry->name)[1] && (*(u16 *)&((u32 *)filename_temp)[2] == *(u16 *)&((u32 *)RomdirEntry->name)[2])) {
355
356 stat->romdirent = RomdirEntry;
357 stat->data = ImageStat->ImageStart + offset;
358 stat->extinfo = NULL;
359
360 if (RomdirEntry->ExtInfoEntrySize != 0) { // Unlike the version within UDNL, the existence of the extinfo entry is optional.
361 stat->extinfo = (void *)((u8 *)ImageStat->RomdirEnd + ExtInfoOffset);
362 }
363
364 result = stat;
365 goto end;
366 }
367
368 offset += (RomdirEntry->size + 15) & ~15;
369 ExtInfoOffset += RomdirEntry->ExtInfoEntrySize;
370 RomdirEntry++;
371 } while (((u32 *)RomdirEntry->name)[0] != 0x00000000); // Until the terminator entry is reached.
372
373 result = NULL;
374 } else {
375 result = NULL;
376 }
377
378end:
379 return result;
380}
381
382#ifdef ROMDRV_EXPORT_DEVICES
383const struct RomImg *romGetDevice(int unit)
384{
385 int OldState;
386 const struct RomImg *result;
387
388 if (unit < ROMDRV_MAX_IMAGES) {
389 CpuSuspendIntr(&OldState);
390
391 if (images[unit].ImageStart != NULL) {
392 result = &images[unit];
393 CpuResumeIntr(OldState);
394 } else {
395 CpuResumeIntr(OldState);
396 result = NULL;
397 }
398 } else {
399 result = NULL;
400 }
401
402 return result;
403}
404#endif
#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 EACCES
Definition errno.h:45
#define EBADF
Definition errno.h:37
int CpuResumeIntr(int state)
Definition intrman.c:227
int CpuSuspendIntr(int *state)
Definition intrman.c:205
Definition romdrv.h:40