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