This is a syscall implementation and (only slightly modified) linker script for use with Newlib on the Sony PlayStation. Newlib is a portable libc/stdlib implementation that doesn't require a Linux or BSD kernel like most libc's, and is complete and standards-compliant unlike a custom libc.
The PlayStation includes a BIOS ROM that has a number of system support functions, which we use to implement device-specific system calls. However, it additionally includes a few libc functions itself that do not interact with peripherals. As such, Newlib can either be used for all libc functions except as necessary to interact with hardware, or Newlib can be patched to use BIOS routines whereever possible. The second option may run slower in some cases but will result in a smaller executable. Patching newlib is also required if you set any exception handlers, link with the legacy PsyQ libraries (which set exception handlers), or debug with the pcsx-redux emulator.
Download a pre-compiled bundle from the releases page and install it into your existing MIPSEL prefix. Make sure to use -nodefaultlibs -Tpsx.ld
in the linker flags, or if using another linker script, add -lpsxsys
manually.
-
Copy
psx.c
andpsx.ld
tolibgloss/mips/
. -
Add them to
libgloss/mips/Makefile.in
, for example with:PSXOBJS = psx.o syscalls.o getpid.o kill.o putnum.o libpsxsys.a: $(PSXOBJS) ${AR} ${ARFLAGS} $@ $(PSXOBJS) ${RANLIB} $@
Then continue with "Configuring and compiling Newlib" below.
- Copy
psx.c
,psx.ld
,psx-bonus.c
, andpsx-printf.S
tolibgloss/mips/
. - In the top-level Newlib source, run
patch -p1 <psx.patch
(using the full path ofpsx.patch
).
Then continue with "Configuring and compiling Newlib" below.
- Configure Newlib with these flags:
--target=mipsel-elf
: Required for the platform. Themipsel-unknown-elf
triple is sometimes recommended in other tutorials, but it does the same thing.CFLAGS
(orCFLAGS_FOR_TARGET
for a unified build) set to:-DHAVE_BLKSIZE
: Required. PSX file I/O can only be done in block units, so this tells Newlib to enable "optimizations" that transform FS calls to block alignment.-g -O2
: From the default configuration.-DHAVE_RENAME
: Not required, but you'll need to remove_rename
frompsx.c
if you don't add the flag.
--prefix=/usr/local/psxsdk
or whatever. Optional but recommended to keep your host system root clean.--disable-multilib
: Optional, but recommended to keep the prefix clean. Disables building extra, unnecessary big-endian and hard-float versions of target libraries.--enable-lto
: Optional but recommended. Enables link-time-optimization, building intermediate code so that optimizations can be performed all at once during linking.--disable-libssp
: Optional. Disables support for stack protection.--disable-libstdcxx
: Optional. Disables support for GNU libstdc++-v3.--disable-newlib-hw-fp
: Optional. Enforces disabling hard-float support.--disable-newlib-io-float
: Optional. Disables floating point in format strings.--disable-newlib-multithread
: Optional. Disables threading support.--disable-shared
: Optional. Do not build shared libraries.--enable-lite-exit
: Optional. Console games don't typically exit, so why spend time there?--enable-newlib-nano-malloc
: Optional. Enables an alternativemalloc
implementation, "which is for small systems with very limited memory."
For example, here's my full configure line, using a "unified" build alongside binutils and GCC:
../configure --prefix=/usr/local/psxsdk --target=mipsel-elf \
--disable-gcov \
--disable-libssp \
--disable-libstdcxx \
--disable-multilib \
--disable-newlib-hw-fp \
--disable-newlib-io-float \
--disable-newlib-multithread \
--disable-nls \
--disable-shared \
--enable-gold \
--enable-languages=c,c++ \
--enable-lite-exit \
--enable-lto \
--enable-serial-configure \
--with-float=soft \
--with-isl \
--with-newlib \
--with-no-pic \
CFLAGS_FOR_TARGET="-g -O2 -DHAVE_BLKSIZE -DHAVE_RENAME"
Then make
and make install
as usual. Add the new prefix to your PATH
if necessary, then you can use mipsel-elf-gcc
with -flto -msoft-float -march=r3000
to build things, and mipsel-elf-gcc-ld
with -nodefaultlibs -Tpsx.ld
to link things.
environ
getpid
kill
assert
getenv
,_getenv_r
raise
,_raise_r
tmpfile
,tmpfile_r
tmpfile64
,_tmpfile64_r
tmpnam
,tempnam
,_tmpnam_r
,_tempnam_r
gettimeofday
link
_gettimeofday_r
_link_r
time
dup2
execve
execvpe
fcntl
fork
fstat64
lseek64
mkdir
open64
pipe
sched_setparam
sched_setscheduler
setegid
seteuid
setpgid
sigaction
sigprocmask
symlink
times
vfork
wait
waitpid
Library functions affected by unimplemented OS subroutines (programs that use these will fail to link)
_execve_r
_fcntl_r
_fork_r
_fstat64_r
_lseek64_r
_mkdir_r
_open64_r
_times_r
_wait_r
clock
fopen64
,_fopen64_r
freopen64
,_freopen64_r
fseeko64
,_fsseko64_r
fsetpos64
,_fsetpos64_r
mktemp
,mkdtemp
,mkstemp
,mkstemps
,mkostemp
,mkostemps
,_mktemp_r
,_mkdtemp_r
,_mkstemp_r
,_mkstemps_r
,_mkostemp_r
,_mkostemps_r
popen
,pclose
posix_spawn
,posix_spawnp
pread64
pwrite64
system
,_system_r
tmpfile64
,_tmpfile64_r
- Make a custom, slimmer
crt0.s
. The built-in one is great, but 1) supplies_exit
, which could be done as a syscall, and 2) zeroes.bss
and does some other system initialization that the BIOS boot sequence already does. - Pass
argv
to main. Syscall A(0x43) passes parameters tor4
andr5
, presumably argc and argv (though they are 0 and null for the boot executable) - The boot executable copies some of
system.cnf
to 0x180—could this be used for environment? - Add syscall versions of malloc and memset.
- Consider
-O2
vs-Os
vs-O3
.
- Adrian Siekierka for candyk, which helped me figure out some of the configure flags
- Nicolas Noble for Openbios, which helped me figure out how some of the BIOS calls work, and also how to do them inline in C
- Nocash for the PSX Specifications
- NextVolume and Lameguy64 for their existing PS1 SDKs