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