sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
ps2sdkapi.c
Go to the documentation of this file.
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# (C)2001, Gustavo Scotti (gustavo@scotti.com)
7# (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
8# (c) 2023 Francisco Javier Trujillo Mata <fjtrujy@gmail.com>
9# Licenced under Academic Free License version 2.0
10# Review ps2sdk README & LICENSE files for further details.
11*/
12
17
18#include <ps2sdkapi.h>
19#include <string.h>
20#include <stdio.h>
21#include <errno.h>
22#include <stdlib.h>
23#define NEWLIB_PORT_AWARE
24#include <fileio.h>
25#include "iox_stat.h"
26
27typedef struct _fio_file_info_
28{
29 // cppcheck-suppress unusedStructMember
30 int fd;
31 // cppcheck-suppress unusedStructMember
32 char filename[];
33} _fio_file_info_t;
34
35_libcglue_fdman_path_ops_t __fio_fdman_path_ops;
36_libcglue_fdman_fd_ops_t __fio_fdman_ops_file;
37_libcglue_fdman_fd_ops_t __fio_fdman_ops_dir;
38
39extern void __fioOpsInitializeImpl(void);
40
41__attribute__((constructor))
42static void __fioOpsInitialize(void)
43{
44 __fioOpsInitializeImpl();
45}
46
47#define IOP_O_RDONLY 0x0001
48#define IOP_O_WRONLY 0x0002
49#define IOP_O_RDWR 0x0003
50#define IOP_O_DIROPEN 0x0008 // Internal use for dopen
51#define IOP_O_NBLOCK 0x0010
52#define IOP_O_APPEND 0x0100
53#define IOP_O_CREAT 0x0200
54#define IOP_O_TRUNC 0x0400
55#define IOP_O_EXCL 0x0800
56#define IOP_O_NOWAIT 0x8000
57
58int __fioOpenHelper(_libcglue_fdman_fd_info_t *info, const char *buf, int flags, mode_t mode)
59{
60 int iop_flags = 0;
61 int is_dir = 0;
62 int iop_fd;
63
64 // newlib flags differ from iop flags
65 if ((flags & 3) == O_RDONLY) iop_flags |= IOP_O_RDONLY;
66 if ((flags & 3) == O_WRONLY) iop_flags |= IOP_O_WRONLY;
67 if ((flags & 3) == O_RDWR ) iop_flags |= IOP_O_RDWR;
68 if (flags & O_NONBLOCK) iop_flags |= IOP_O_NBLOCK;
69 if (flags & O_APPEND) iop_flags |= IOP_O_APPEND;
70 if (flags & O_CREAT) iop_flags |= IOP_O_CREAT;
71 if (flags & O_TRUNC) iop_flags |= IOP_O_TRUNC;
72 if (flags & O_EXCL) iop_flags |= IOP_O_EXCL;
73 //if (flags & O_???) iop_flags |= IOP_O_NOWAIT;
74 if (flags & O_DIRECTORY) {
75 iop_flags |= IOP_O_DIROPEN;
76 is_dir = 1;
77 }
78
79 iop_fd = is_dir ? fioDopen(buf) : fioOpen(buf, iop_flags);
80 if (iop_fd >= 0) {
81 _fio_file_info_t *userdata;
82 int buf_len;
83
84 buf_len = strlen(buf);
85 userdata = malloc(sizeof(_fio_file_info_t) + buf_len + 1);
86 if (userdata == NULL)
87 {
88 return -ENOMEM;
89 }
90 userdata->fd = iop_fd;
91 memcpy(userdata->filename, buf, buf_len);
92 userdata->filename[buf_len] = '\x00';
93 info->userdata = (void *)userdata;
94 info->ops = is_dir ? &__fio_fdman_ops_dir : &__fio_fdman_ops_file;
95 return 0;
96 }
97 return iop_fd;
98}
99
100int __fioGetFdHelper(void *userdata)
101{
102 _fio_file_info_t *finfo;
103
104 if (userdata == NULL)
105 {
106 return -EINVAL;
107 }
108
109 finfo = (_fio_file_info_t *)userdata;
110 return finfo->fd;
111}
112
113char *__fioGetFilenameHelper(void *userdata)
114{
115 _fio_file_info_t *finfo;
116
117 if (userdata == NULL)
118 {
119 return NULL;
120 }
121
122 finfo = (_fio_file_info_t *)userdata;
123 return finfo->filename;
124}
125
126int __fioCloseHelper(void *userdata)
127{
128 int rv;
129 int fd;
130
131 fd = __fioGetFdHelper(userdata);
132 if (fd < 0)
133 {
134 return fd;
135 }
136
137 rv = fioClose(fd);
138 free(userdata);
139 return rv;
140}
141
142int __fioDcloseHelper(void *userdata)
143{
144 int rv;
145 int fd;
146
147 fd = __fioGetFdHelper(userdata);
148 if (fd < 0)
149 {
150 return fd;
151 }
152
153 rv = fioDclose(fd);
154 free(userdata);
155 return rv;
156}
157
158int __fioReadHelper(void *userdata, void *buf, int nbytes)
159{
160 int rv;
161 int fd;
162
163 fd = __fioGetFdHelper(userdata);
164 if (fd < 0)
165 {
166 return fd;
167 }
168
169 rv = fioRead(fd, buf, nbytes);
170 return rv;
171}
172
173int __fioLseekHelper(void *userdata, int offset, int whence)
174{
175 int rv;
176 int fd;
177
178 fd = __fioGetFdHelper(userdata);
179 if (fd < 0)
180 {
181 return fd;
182 }
183
184 rv = fioLseek(fd, offset, whence);
185 return rv;
186}
187
188int __fioWriteHelper(void *userdata, const void *buf, int nbytes)
189{
190 int rv;
191 int fd;
192
193 fd = __fioGetFdHelper(userdata);
194 if (fd < 0)
195 {
196 return fd;
197 }
198
199 rv = fioWrite(fd, buf, nbytes);
200 return rv;
201}
202
203int __fioIoctlHelper(void *userdata, int request, void *data)
204{
205 int rv;
206 int fd;
207
208 fd = __fioGetFdHelper(userdata);
209 if (fd < 0)
210 {
211 return fd;
212 }
213
214 rv = fioIoctl(fd, request, data);
215 return rv;
216}
217
218int __fioDreadHelper(void *userdata, struct dirent *dir)
219{
220 int rv;
221 int fd;
222 // The IOP DMAs the entry into this buffer, so it must own whole 64-byte cache lines.
223 struct { io_dirent_t d; } __attribute__((aligned(64))) aligned_dirent;
224 io_dirent_t *iodir = &aligned_dirent.d;
225
226 // Took from io_dirent_t
227 #define __MAXNAMLEN 256
228
229 fd = __fioGetFdHelper(userdata);
230 if (fd < 0)
231 {
232 return fd;
233 }
234
235 rv = fioDread(fd, iodir);
236 if (rv < 0) {
237 errno = ENOENT;
238 return -1;
239 }
240
241 dir->d_fileno = rv; // TODO: This number should be in theory a unique number per file
242 snprintf(dir->d_name, sizeof(dir->d_name), "%.*s", (int)(sizeof(iodir->name) - 1), iodir->name);
243 dir->d_reclen = 0;
244 switch (iodir->stat.mode & FIO_SO_IFMT) {
245 case FIO_SO_IFLNK: dir->d_type = DT_LNK; break;
246 case FIO_SO_IFDIR: dir->d_type = DT_DIR; break;
247 case FIO_SO_IFREG: dir->d_type = DT_REG; break;
248 default: dir->d_type = DT_UNKNOWN; break;
249 }
250
251
252 return rv;
253}
254
255int __fioLseekDirHelper(void *userdata, int offset, int whence)
256{
257 int i;
258 int fd;
259 char *filename;
260 _fio_file_info_t *finfo;
261 int uid;
262 struct dirent dir;
263
264 fd = __fioGetFdHelper(userdata);
265 if (fd < 0)
266 {
267 return fd;
268 }
269
270 filename = __fioGetFilenameHelper(userdata);
271
272 if (filename == NULL)
273 {
274 return -EINVAL;
275 }
276
277 if (userdata == NULL)
278 {
279 return -EINVAL;
280 }
281
282 finfo = (_fio_file_info_t *)userdata;
283
284 if (whence != SEEK_SET)
285 {
286 return -EINVAL;
287 }
288
289 fioDclose(fd);
290 uid = fioDopen(filename);
291 finfo->fd = uid;
292 for (i = 0; i < offset; i++) {
293 __fioDreadHelper(userdata, &dir);
294 }
295
296 return offset;
297}
298
299int __libcglue_init_stdio(_libcglue_fdman_fd_info_t *info, int fd)
300{
301 _fio_file_info_t *userdata;
302 int fnlen;
303 const char *tty0_str = "tty0:";
304
305 fnlen = strlen(tty0_str) + 1;
306
307 userdata = malloc(sizeof(_fio_file_info_t) + fnlen);
308 if (userdata == NULL)
309 {
310 return -ENOMEM;
311 }
312 userdata->fd = fd;
313 memcpy(userdata->filename, tty0_str, fnlen - 1);
314 userdata->filename[fnlen - 1] = '\x00';
315 info->userdata = (void *)userdata;
316 info->ops = &__fio_fdman_ops_file;
317 return 0;
318}
319
321int __fioMkdirHelper(const char *path, int mode)
322{
323 // Old fio mkdir has no mode argument
324 (void)mode;
325
326 return fioMkdir(path);
327}
328
329static time_t io_to_posix_time(const unsigned char *ps2time)
330{
331 struct tm tim;
332 tim.tm_sec = ps2time[1];
333 tim.tm_min = ps2time[2];
334 tim.tm_hour = ps2time[3];
335 tim.tm_mday = ps2time[4];
336 tim.tm_mon = ps2time[5] - 1;
337 tim.tm_year = ((u16)ps2time[6] | ((u16)ps2time[7] << 8)) - 1900;
338 return mktime(&tim);
339}
340
341static mode_t io_to_posix_mode(unsigned int ps2mode)
342{
343 mode_t posixmode = 0;
344 if (ps2mode & FIO_SO_IFREG) posixmode |= S_IFREG;
345 if (ps2mode & FIO_SO_IFDIR) posixmode |= S_IFDIR;
346 if (ps2mode & FIO_SO_IROTH) posixmode |= S_IRUSR|S_IRGRP|S_IROTH;
347 if (ps2mode & FIO_SO_IWOTH) posixmode |= S_IWUSR|S_IWGRP|S_IWOTH;
348 if (ps2mode & FIO_SO_IXOTH) posixmode |= S_IXUSR|S_IXGRP|S_IXOTH;
349 return posixmode;
350}
351
352static void __fill_stat(struct stat *stat, const io_stat_t *fiostat)
353{
354 stat->st_dev = 0;
355 stat->st_ino = 0;
356 stat->st_mode = io_to_posix_mode(fiostat->mode);
357 stat->st_nlink = 0;
358 stat->st_uid = 0;
359 stat->st_gid = 0;
360 stat->st_rdev = 0;
361 stat->st_size = ((off_t)fiostat->hisize << 32) | (off_t)fiostat->size;
362 stat->st_atime = io_to_posix_time(fiostat->atime);
363 stat->st_mtime = io_to_posix_time(fiostat->mtime);
364 stat->st_ctime = io_to_posix_time(fiostat->ctime);
365 stat->st_blksize = 16*1024;
366 stat->st_blocks = stat->st_size / 512;
367}
368
369int __fioGetstatHelper(const char *path, struct stat *buf)
370{
371 // The IOP DMAs the result into this buffer, so it must own whole 64-byte cache lines.
372 struct { io_stat_t st; } __attribute__((aligned(64))) aligned_stat;
373 io_stat_t *fiostat_p = &aligned_stat.st;
374
375 if (strncmp(path, "tty", 3) == 0 && path[3] >= '0' && path[3] <= '9' && path[4] == ':')
376 {
377 memset(buf, 0, sizeof(struct stat));
378 buf->st_mode = S_IFCHR;
379 return 0;
380 }
381
382 if (fioGetstat(path, fiostat_p) < 0) {
383 return -ENOENT;
384 }
385
386 __fill_stat(buf, fiostat_p);
387
388 return 0;
389}
390
391int __attribute__((weak)) _open(const char *buf, int flags, ...);
392int __attribute__((weak)) _unlink(const char *path);
393int __attribute__((weak)) mkdir(const char *path, mode_t mode);
394int __attribute__((weak)) rmdir(const char *path);
395int __attribute__((weak)) _stat(const char *path, struct stat *buf);
396int __attribute__((weak)) _fstat(int fd, struct stat *buf);
397int __attribute__((weak)) _close(int fd);
398int __attribute__((weak)) _read(int fd, void *buf, size_t nbytes);
399off_t __attribute__((weak)) _lseek(int fd, off_t offset, int whence);
400int __attribute__((weak)) _write(int fd, const void *buf, size_t nbytes);
401int __attribute__((weak)) _ioctl(int fd, int request, void *data);
402int __attribute__((weak)) _ps2sdk_ioctl(int fd, int request, void *data);
403int __attribute__((weak)) getdents(int fd, void *dd_buf, int count);
404
405void __fioOpsInitializeImpl(void)
406{
407 memset(&__fio_fdman_path_ops, 0, sizeof(__fio_fdman_path_ops));
408 // cppcheck-suppress knownConditionTrueFalse
409 if (&_open) __fio_fdman_path_ops.open = __fioOpenHelper;
410 // cppcheck-suppress knownConditionTrueFalse
411 if (&_unlink) __fio_fdman_path_ops.remove = fioRemove;
412 // cppcheck-suppress knownConditionTrueFalse
413 if (&mkdir) __fio_fdman_path_ops.mkdir = __fioMkdirHelper;
414 // cppcheck-suppress knownConditionTrueFalse
415 if (&rmdir) __fio_fdman_path_ops.rmdir = fioRmdir;
416 // cppcheck-suppress knownConditionTrueFalse
417 if ((&_stat) || (&_fstat)) __fio_fdman_path_ops.stat = __fioGetstatHelper;
418
419 memset(&__fio_fdman_ops_file, 0, sizeof(__fio_fdman_ops_file));
420 __fio_fdman_ops_file.getfd = __fioGetFdHelper;
421 __fio_fdman_ops_file.getfilename = __fioGetFilenameHelper;
422 // cppcheck-suppress knownConditionTrueFalse
423 if (&_close) __fio_fdman_ops_file.close = __fioCloseHelper;
424 // cppcheck-suppress knownConditionTrueFalse
425 if (&_read) __fio_fdman_ops_file.read = __fioReadHelper;
426 // cppcheck-suppress knownConditionTrueFalse
427 if (&_lseek) __fio_fdman_ops_file.lseek = __fioLseekHelper;
428 // cppcheck-suppress knownConditionTrueFalse
429 if (&_write) __fio_fdman_ops_file.write = __fioWriteHelper;
430 // cppcheck-suppress knownConditionTrueFalse
431 if ((&_ioctl) || (&_ps2sdk_ioctl)) __fio_fdman_ops_file.ioctl = __fioIoctlHelper;
432
433 memset(&__fio_fdman_ops_dir, 0, sizeof(__fio_fdman_ops_dir));
434 __fio_fdman_ops_dir.getfd = __fioGetFdHelper;
435 __fio_fdman_ops_dir.getfilename = __fioGetFilenameHelper;
436 // cppcheck-suppress knownConditionTrueFalse
437 if (&_close) __fio_fdman_ops_dir.close = __fioDcloseHelper;
438 // cppcheck-suppress knownConditionTrueFalse
439 if (&_lseek) __fio_fdman_ops_dir.lseek = __fioLseekDirHelper;
440 // cppcheck-suppress knownConditionTrueFalse
441 if (&getdents) __fio_fdman_ops_dir.dread = __fioDreadHelper;
442}
443
444extern _libcglue_fdman_path_ops_t * _ps2sdk_get_default_fdman_path_ops(void);
445_libcglue_fdman_path_ops_t * __attribute__((weak)) _ps2sdk_get_default_fdman_path_ops(void)
446{
447 return &__fio_fdman_path_ops;
448}
449
450_libcglue_fdman_path_ops_t *_libcglue_fdman_path_ops = NULL;
451
452__attribute__((constructor))
453static void __libcglue_fdman_path_ops_initialize(void)
454{
455 _libcglue_fdman_path_ops = _ps2sdk_get_default_fdman_path_ops();
456}
457
458_libcglue_fdman_socket_ops_t *_libcglue_fdman_socket_ops = NULL;
459
460/* sys/socket.h #defines ps2ip_getconfig/ps2ip_setconfig/dns_setserver/
461 * dns_getserver to these four libcglue_-prefixed names for any real
462 * caller (found for real getting Open-PS2-Loader and ps2_drivers to
463 * build: both call the plain names directly) - the real backend side
464 * of this dispatch (core/ps2ips's own ps2ipc_ps2sdk.c, which points
465 * _libcglue_fdman_socket_ops at its own real RPC-client implementation
466 * from _ps2sdk_ps2ipc_init()) already existed, but libcglue itself
467 * never defined the trampoline functions callers actually link
468 * against - a real, previously-latent gap, only ever exercised by a
469 * program that both includes this header AND actually calls one of
470 * these four names, which nothing in this tree's own samples did
471 * until now. ENETDOWN (not ENOSYS) when nothing is registered - the
472 * real, standard errno for "no network subsystem is up", matching
473 * what these fail from is a *missing* ps2ipcInit()-style call, not an
474 * unimplemented feature. */
475int libcglue_ps2ip_setconfig(const t_ip_info *ip_info)
476{
477 if (_libcglue_fdman_socket_ops == NULL || _libcglue_fdman_socket_ops->setconfig == NULL)
478 {
479 errno = ENETDOWN;
480 return -1;
481 }
482 return _libcglue_fdman_socket_ops->setconfig(ip_info);
483}
484
485int libcglue_ps2ip_getconfig(char *netif_name, t_ip_info *ip_info)
486{
487 if (_libcglue_fdman_socket_ops == NULL || _libcglue_fdman_socket_ops->getconfig == NULL)
488 {
489 errno = ENETDOWN;
490 return -1;
491 }
492 return _libcglue_fdman_socket_ops->getconfig(netif_name, ip_info);
493}
494
495void libcglue_dns_setserver(u8 numdns, const ip_addr_t *dnsserver)
496{
497 if (_libcglue_fdman_socket_ops == NULL || _libcglue_fdman_socket_ops->dns_setserver == NULL)
498 {
499 return;
500 }
501 _libcglue_fdman_socket_ops->dns_setserver(numdns, dnsserver);
502}
503
504const ip_addr_t *libcglue_dns_getserver(u8 numdns)
505{
506 if (_libcglue_fdman_socket_ops == NULL || _libcglue_fdman_socket_ops->dns_getserver == NULL)
507 {
508 return NULL;
509 }
510 return _libcglue_fdman_socket_ops->dns_getserver(numdns);
511}
512
513_libcglue_fdman_inet_ops_t *_libcglue_fdman_inet_ops = NULL;
#define ENOENT
Definition errno.h:32
#define EINVAL
Definition errno.h:72
#define ENOMEM
Definition errno.h:52
#define ENETDOWN
Definition errno.h:230
#define FIO_SO_IFMT
Definition iox_stat.h:123
#define FIO_SO_IFDIR
Definition iox_stat.h:129
#define FIO_SO_IFLNK
Definition iox_stat.h:125
#define FIO_SO_IXOTH
Definition iox_stat.h:136
#define FIO_SO_IWOTH
Definition iox_stat.h:134
#define FIO_SO_IFREG
Definition iox_stat.h:127
#define FIO_SO_IROTH
Definition iox_stat.h:132
int __fioMkdirHelper(const char *path, int mode)
Definition ps2sdkapi.c:321
u32 count
start sector of fragmented bd/file